Saving large amounts of data when onPause is called? - java

For my app, I have about 15Mb (which can be compressed with some processing power to about 5Mb) of audio+video+image data that I need to save to disk. For instance, I need to save this when user is interrupted with a phone call (because the activity might get killed after this) and when the user leaves the app.
I can save the data to SD card in about 10 seconds if I don't compress it and something like 20 seconds if I do compress it, where I'd like it compressed. What options to I have for saving my data when onPause is called such that I can be sure the data has been saved?
From some basic experiments, my activity gets killed if onPause hasn't finished after 5 seconds. Some ideas I've had:
Starting a new Thread in onPause and saving the data there. This seems to work fine but seems like something I shouldn't be doing.
Starting a service, copying the data to the service somehow (would this be slow?) and then getting the service to save the data. I think this puts a notification icon at the top of the phone, but I don't think it's awful for a user to see the "Saving data..." task here.
Can I put the data in a SQL database quickly and then save it later when the user returns to the app?
(Due to the nature of the app, there really isn't any practical way I can save the data as I go because the user can transform the data in destructive ways with time consuming operations (e.g. 10 seconds for some operations). Even if I stored the original data and a list of the actions performed to recreate the data, the user would have to wait a minute or two when the app is next started up to process this.)

What options to I have for saving my data when onPause is called such that I can be sure the data has been saved?
Technically, what you want is impossible. There are no guarantees after onPause().
The best answer is what #Viktor Lannér suggested. To phrase it another way, don't wait until onPause() to need to do 10-20 seconds of I/O. Devise some mechanism to allow you to save incrementally as the user performs operations, as a fallback mechanism if nothing else. This is akin to how a database maintains a transaction log.
Starting a new Thread in onPause and saving the data there. This seems to work fine but seems like something I shouldn't be doing.
This is dangerous, because if the activity is closing (e.g., onDestroy() will be called momentarily), Android might terminate your process before your thread is completed.
Starting a service, copying the data to the service somehow (would this be slow?) and then getting the service to save the data. I think this puts a notification icon at the top of the phone, but I don't think it's awful for a user to see the "Saving data..." task here.
Make this be an IntentService, so it automatically shuts down when the work is complete. I wouldn't "copy the data to the service", but rather make the data centrally available, by a static data member if needed. This will not automatically put "a notification icon at the top of the phone", and for something of this duration, that is probably not needed.
Can I put the data in a SQL database quickly and then save it later when the user returns to the app?
Flash I/O is not faster for a SQL database than for anything else.
Due to the nature of the app, there really isn't any practical way I can save the data as I go because the user can transform the data in destructive ways with time consuming operations (e.g. 10 seconds for some operations
Then this probably isn't designed for a mobile platform. Consider whether this app is an appropriate use of the technology.

Related

How can I ensure that my Android app doesn't access a file simultaneously?

I am building a fitness app which continually logs activity on the device. I need to log quite often, but I also don't want to unnecessarily drain the battery of my users which is why I am thinking about batching network calls together and transmitting them all at once as soon as the radio is active, the device is connected to a WiFi or it is charging.
I am using a filesystem based approach to implement that. I persist the data first to a File - eventually I might use Tape from Square to do that - but here is where I encounter the first issues.
I am continually writing new log data to the File, but I also need to periodically send all the logged data to my backend. When that happens I delete the contents of the File. The problem now is how can I prevent both of those operations from happening at the same time? Of course it will cause problems if I try to write log data to the File at the same time as some other process is reading from the File and trying to delete its contents.
I am thinking about using an IntentService essentially act as a queue for all those operations. And since - at least I have read as much - an IntentServices handles Intents sequentially in single worker Thread it shouldn't be possible for two of those operations to happen at the same time, right?
Currently I want to schedule a PeriodicTask with the GcmNetworkManager which would take care of sending the data to the server. Is there any better way to do all this?
1) You are overthinking this whole thing!
Your approach is way more complicated than it has to be! And for some reason none of the other answers point this out, but GcmNetworkManager already does everything you are trying to implement! You don't need to implement anything yourself.
2) Optimal way to implement what you are trying to do.
You don't seem to be aware that GcmNetworkManager already batches calls in the most battery efficient way with automatic retries etc and it also persists the tasks across device boots and can ensure their execution as soon as is battery efficient and required by your app.
Just whenever you have data to save schedule a OneOffTask like this:
final OneoffTask task = new OneoffTask.Builder()
// The Service which executes the task.
.setService(MyTaskService.class)
// A tag which identifies the task
.setTag(TASK_TAG)
// Sets a time frame for the execution of this task in seconds.
// This specifically means that the task can either be
// executed right now, or must have executed at the lastest in one hour.
.setExecutionWindow(0L, 3600L)
// Task is persisted on the disk, even across boots
.setPersisted(true)
// Unmetered connection required for task
.setRequiredNetwork(Task.NETWORK_STATE_UNMETERED)
// Attach data to the task in the form of a Bundle
.setExtras(dataBundle)
// If you set this to true and this task already exists
// (just depends on the tag set above) then the old task
// will be overwritten with this one.
.setUpdateCurrent(true)
// Sets if this task should only be executed when the device is charging
.setRequiresCharging(false)
.build();
mGcmNetworkManager.schedule(task);
This will do everything you want:
The Task will be persisted on the disk
The Task will be executed in a batched and battery efficient way, preferably over Wifi
You will have configurable automatic retries with a battery efficient backoff pattern
The Task will be executed within a time window you can specify.
I suggest for starters you read this to learn more about the GcmNetworkManager.
So to summarize:
All you really need to do is implement your network calls in a Service extending GcmTaskService and later whenever you need to perform such a network call you schedule a OneOffTask and everything else will be taken care of for you!
Of course you don't need to call each and every setter of the OneOffTask.Builder like I do above - I just did that to show you all the options you have. In most cases scheduling a task would just look like this:
mGcmNetworkManager.schedule(new OneoffTask.Builder()
.setService(MyTaskService.class)
.setTag(TASK_TAG)
.setExecutionWindow(0L, 300L)
.setPersisted(true)
.setExtras(bundle)
.build());
And if you put that in a helper method or even better create factory methods for all the different tasks you need to do than everything you were trying to do should just boil down to a few lines of code!
And by the way: Yes, an IntentService handles every Intent one after another sequentially in a single worker Thread. You can look at the relevant implementation here. It's actually very simple and quite straight forward.
All UI and Service methods are by default invoked on the same main thread. Unless you explicitly create threads or use AsyncTask there is no concurrency in an Android application per se.
This means that all intents, alarms, broad-casts are by default handled on the main thread.
Also note that doing I/O and/or network requests may be forbidden on the main thread (depending on Android version, see e.g. How to fix android.os.NetworkOnMainThreadException?).
Using AsyncTask or creating your own threads will bring you to concurrency problems but they are the same as with any multi-threaded programming, there is nothing special to Android there.
One more point to consider when doing concurrency is that background threads need to hold a WakeLock or the CPU may go to sleep.
Just some idea.
You may try to make use of serial executor for your file, therefore, only one thread can be execute at a time.
http://developer.android.com/reference/android/os/AsyncTask.html#SERIAL_EXECUTOR

Best time to save persistent data in Service (Service.onDestroy not always called)

I am working on a small financial app with an activity and a background service to update data periodically. I use AlarmManager + PendingIntent to update the data periodically in the background even if after the activity has been destroyed. When the service is running by itself in the background, it will be killed by the system from time to time but will be restarted automatically by the system in a short while since I return START_STICKY in onStartCommand.
Here is the problem. I put the code to save persistent data inside Service.onDestroy(). However, when the system kills my service out of its free will, Service.onDestroy() is not called. Where else should I save my data, then? I could save the data upon every data modification operation. But that seems pretty wasteful of CPU and I/O operation.
Where else should I save my data, then?
Asynchronously, when the data changes.
I could save the data upon every data modification operation. But that seems pretty wasteful of CPU and I/O operation.
Then your problem lies with your use of AlarmManager. If you are worried about the costs of doing the work, then do not do the work quite so frequently, or let the user control how frequently the work gets done.
Data held in a Service, like data held in static data members, is merely a cache, and should be treated as such.

Android AsyncTask/Service killed before task complete

Synopsis: I need a way to start a task and have it persist through onDestroy() of app until it completes, or ability to pick up where it left off.
In my app, I have a ListView containing some items from a database. Hopefully only about 10-30 items, but potentially thousands (if the user never clears it, although I have prompts to clear it from time to time).
I have set up an AsyncTask to perform clearing the selected items from the list when the user wants to. However, I've noticed that the AsyncTask is killed when onDestroy() is called, for example if the user selects all items to delete, presses delete, then swipes app out of Recents while task is still performing.
I remember learning somewhere that a Service persists longer than an AsyncTask, so when the task gets killed I hand off the data to delete to a Service that I created. It does this by
intent.putIntegerArrayListExtra(list);
and get data from it in the Service. The Service persists far longer than the AsyncTask (only about 4-6 seconds), but still not all the way to completion. I know a little about START_XXXX flags, but that would be bad practice for this task, since they'd either send the whole list back to itself, or never really stop.
What is the preferred method to delete selected items from a database without it stopping when the app is killed, or at least to pick up where it leaves off?
Thanks all!
Your problem is very much like this: You have an application open in your favorite OS which is doing things in the background and then in the middle of it, the user force closes it. Logically, it will stop everything it's doing and stop executing and there's not much you can do to interrupt it.
There's no ideal solution to stop this from happening so what most people end up doing is to warn users that stopping the app when this operation is in process can have unwanted consequences.
In Android however, you have another option which is slightly more robust: you can write a persistent background service what continues running even if your app isn't running, but that still wouldn't solve the problem of what happens if the user switches off the phone when you're deleting from the DB? which would be the next logical question given your context. (personally, I would not recommend this approach for your task).
Best you can do is to maybe write a shared preference for every row you've not yet deleted (this will be the full list of rows you want to delete when you start deleting). For every row (or bunch of rows) you delete, change this preference to remove those rows from the preference and then if the app is interrupted, when you restart your app, read this preference and continue where you left off.
Alternatively, do what others do and warn users (by use of dialogs for instance) that they shouldn't stop the app until the delete is done otherwise bad things happen, etc.
I would strongly discourage you from using a service simply because it lasts longer than an AsyncTask. That's way too hacky and not at all reliable.

Should I put (online) database queries in Android into a separate thread, and what should the UI showing meanwhile?

I have some questions about executing SQL queries (to an online database) from an Android app.
Since these are network operations and they are costly, should I be doing them in a separate thread? Also, what should I show the user (UI) while these queries are processing?
I suggest you to make a use of AsyncTask. In the doInBackground() method you'd be downloading/processing stuff. In the onPostExecute() you'll be displaying on the UI. This is in short. Research base on AsyncTask for further information.
The first answer is good with regards to AsyncTask. If they're REALLY long queries, I would put them in a service and communicate back to the activity with a broadcast, but if they're just "network long", then Async is good.
It seems like EVERYBODY wants to use a waiting dialog, but this kind of UI generally sucks. It blocks everything, so if you can't get a response or whatever, the user is stuck. I recently reviewed an app for somebody, and because our network was slow, the time spent waiting in an alert box was 47 seconds. Any idea how long that feels to a user?
I would disable a repost, put some kind of spinner up, but don't block the UI. If the user wants to do something else, let them. Also, when the AsyncTask comes back, the screen that it expects to manipulate may no longer exist. Wrap everything in case you get an exception.
I try to do all remote stuff in a service, even if it isn't totally necessary. Talk back and forth with broadcasts. That's just me, though ;)

Java: Do something on event in SQL Database?

I'm building an application with distributed parts.
Meaning, while one part (writer) maybe inserting, updating information to a database, the other part (reader) is reading off and acting on that information.
Now, i wish to trigger an action event in the reader and reload information from the DB whenever i insert something from the writer.
Is there a simple way about this?
Would this be a good idea? :
// READER
while(true) {
connect();
// reload info from DB
executeQuery("select * from foo");
disconnect();
}
EDIT : More info
This is a restaurant Point-of-sale system.
Whenever the cashier punches an order into the db - the application in the kitchen get's the notification. This is the kind of system you would see at McDonald's.
The applications needn't be connected in any way. But each part will connect to a single mySQL server.
And i believe i'd expect immediate notifications.
You might consider setting up an embedded JMS server in your application, I would recommend ActiveMQ as it is super easy to embed.
For what you want to do a JMS Topic is a perfect fit. When the cashier punches in an order the order is not written to the database but in a message on the Topic, let's name it newOrders.
On the topic there are 2 subscribers : NewOrderPersister and KitchenNotifier. These will each have an onMessage(Message msg) method which contains the details of the order. One saves it to the database, the other adds it to a screen or yells it through te kitchen with text-to-speech, whatever.
The nice part of this is that the poster does not need to know which and how many subscribers are there waiting for the messages. So if you want a NewOrderCOunter in the backoffice to keep an online count of how much money the owner has made today, or add a "FreanchFiresOrderListener" to have a special display near the deep frying pan, nothing has to change in the rest of the application. They just subscribe to the topic.
The idea you are talking about is called "polling". As Graphain pointed out you must add a delay in the loop. The amount of delay should be decided based on factors like how quickly you want your reader to detect any changes in database and how fast the writer is expected to insert/update data.
Next improvement to your solution could be to have an change-indicator within the database. Your algo will look something like:
// READER
while(true) {
connect();
// reload info from DB
change_count=executeQuery("select change_count from change_counters where counter=foo");
if(change_count> last_change_count){
last_change_count=change_count;
reload();
}
disconnect();
}
The above change will ensure that you do not reload data unnecessarily.
You can further tune the solution to keep a row level change count so that you can reload only the updated rows.
I don't think it's a good idea to use a database to synchronize processes. The parties using the database should synchronize directly, i.e., the writer should write its orders and then notify the kitchen that there is a new order. Then again the notification could be the order itself (or some ID for the database). The notifications can be sent via a message broker.
It's more or less like in a real restaurant. The kitchen rings a bell when meals are finished and the waiters fetch them. They don't poll unnecessarily.
If you really want to use the database for synchronization, you should look into triggers and stored procedures. I'm fairly sure that most RDBMS allow the creation of stored procedures in Java or C that can do arbitrary things like opening a Socket and communicating with another Computer. While this is possible and not as bad as polling I still don't think of it as a very good idea.
Well to start with you'd want some kind of wait timer in there or it is literally going to poll every instance of time it can which would be a pretty bad idea unless you want to simulate what it would be like if Google was hosted on one database.
What kind of environment do the apps run in? Are we talking same machine notification, cross-network, over the net?
How frequently do updates occur and how soon does the reader need to know about them?
I have done something similar before using jGroups I don't remember the exact details as it was quite a few years ago but I had a listener on the "writer" end which would then use JGroups to send out notification of change which would cause the receivers to respond accordingly.

Categories

Resources