I have a single activity app that uses a PagerAdapter. In the OnCreate event I trigger the inflation of all 7 of the pages in the PagerAdapter. The various pages have standard widgets, one page has a google Map. It all works well when testing in the AVD.
But what if my app is paused or stopped and then restarted or resumed? Does the inflation of all my pages in the pageradapter get deleted? Do I have to reinflate all the pages again?
More generally...
I've read a lot of articles about what happens with my app gets stopped or paused and what I should do upon restart or resume but I haven't seen a precise accounting of what needs to be rebuilt and what does not need to be rebuilt. I read that "this is a great place to refresh the UI" but I'm not sure exactly what that means.
Begging questions might be...
is my internal state restored i.e. values of my variables, sqlLite db, file contents.
are the values in my widgets restored i.e. characters in a textbox.
How can I prevent corruption if the pause or stop can happen in the middle of a for loop or a code block?
Thanks,
Gary
But what if my app is paused or stopped and then restarted or resumed?
Does the inflation of all my pages in the pageradapter get deleted? Do
I have to reinflate all the pages again?
If by app you mean Activity, when it is paused this just means it is not the focused Activity right now. All the state is still there. This basically means that you cannot accept any foreground events until onResume(). If the OS decides to call, onSaveInstanceState(), you can can actually store things like values of instance variables or just flags for a new instance to read. You can't store complex things here though. So things like Thread or Cursor instances will not be appropriate. Basically anything that is not "data."
In the case where the activity is destroyed or even the process killed, then yes you will need to rebind and reinflate everything. However the beauty of this, in most cases you don't have to do anything special. Only in the cases that you may have written to a bundle in onSaveInstanceState() will you have to do some extra work.
is my internal state restored i.e. values of my variables, sqlLite db, file contents.
If the transition was only between onPause and onResume then yes. Everything should be fine. If there was a destroy or process kill, the activity will restart with onCreate() and have to reset all the state based on the Bundle savedInstanceState. I will address sqlite and files later down.
are the values in my widgets restored i.e. characters in a textbox.
Usually if they have saveEnabled(true) (most do) and for TextView there is a freezesText property that will make them remember the last text set on them. However, most of the time if you save your state correctly during the onSaveInstanceState() call, it's probable that you are storing the state not just for UI but other means as well. In which case you might as well sync them when you go through the next onCreate()
How can I prevent corruption if the pause or stop can happen in the
middle of a for loop or a code block?
So onPause() and onStop() occur on the main UI thread. If you are currently running code on the UI thread, it must complete before these other callbacks can occur. If you are running on some other thread, then yes you have to try to make outputs of task complete on the UI thread. It simplifies a lot of this.
Kills on the other hand, can happen. This usually affects things outside your program's memory though when we talk about corruption. Like if you had a file handle open or a sqlite cursor open, or a network socket open. With that, you sort of have to check the state before you use it.
i.e
Make sure directories really exist before you read or write to them
Make sure the contents of files were properly written to previously (simple expected check-sums usually work here or version metadata).
Use transactions when using sqlite to make sure you only write data to your table(s) in complete atomic chunks so that you don't have tables with rows referencing state in other tables that is not there.
Network connections will be reset, and things like your network protocol of choice should take care of sanity checking for you, along with the application being connected with.
hopefully this helps, while it's not fully complete, it's a good starting approach.
In status Pause and Stop all your objects are preserved and you don't need to worry about interruption in a loop, unless it takes more than 5 seconds to complete which may generate ANR's.
However, is good practice when entering these status to realease the objects that are not needed or can be easly recreated, specially if they are using big amount of memory, and recreate them when reentring the status Resume or Restart.
When your appliaction goes in Destroy status, then all your objects will be lost.
Related
I got some issue when I developing an App.
After I minimized the app or turn the screen off, and open lot of other apps or reopen the phone after a long time.
When I restart my app, it try to resume and keep showing the same page(with fragment).
But the data I need was already been destroyed so it will be null.
The data is an object array, I know maybe I can store them in db.
But due to the data will update every time user click something.
So I don't want to save it into data base, I guess that means lot of storage I/O witch is not necessary.
I'm wondering if there is any solution to restart the hole app when things is destroyed?
Or the only way to make it happen is I handle the null array and do the reload myself?
I don't really want to do that cause I guess that will bring me many unexpected issues cause the data is related with many pages.
Too many situations I have to consider when do switching pages.
Are there any advice?
But the data I need was already been destroyed so it will be null
That is because your process was terminated and you did not save your state.
But due to the data will update every time user click something
Or, you could fork a thread to save the data as part of your onPause() or onStop() methods. There are many possibilities between "never save" and "save on every click".
So I don't want to save it into data base, I guess that means lot of storage I/O witch is not necessary
If you want the data to be there 30+ minutes after the user left the app, your choices are to save the data locally (file, database, SharedPreferences) or save the data on the Internet somewhere.
For small amounts of data over shorter time periods, you could put the data in the Bundle supplied to onSaveInstanceState() and then pull the data out of the Bundle again later (e.g., in onRestoreInstanceState() of your activity). You already should be doing this to handle screen rotations and other configuration changes.
I'm wondering if there is any solution to restart the hole app when things is destroyed?
You are welcome to add android:clearTaskOnLaunch="true" to your launcher activity, to indicate that you always want to start over from scratch whenever the user leaves your app and tries to come back to it. Users will not appreciate this, as this means that they will lose their state even for being out of your app briefly (e.g., a quick reply to a text message). This attribute does not terminate your process, but it will force the user back to the launcher activity and will eliminate any other activities that had been in your app previously.
Or the only way to make it happen is I handle the null array and do the reload myself?
That is what developers normally do, yes.
When a user manually kills an app, what data is cleared?
I have a bit of functionality that only properly clears the data on app kill and reopen, so clearly the system is clearing some data that I am missing.
Basically, I want to know what sort of delete/clear data is called programatically so that I can try and figure out what is being kept around on close/reopen that doesn't stick around for kill/reopen.
EDIT: I am basically trying to find out the difference between finish() of an activity that contains a webview and force-close/reopen
When you force close, the app will be completely removed from the memory. For example, all services will be closed, any static variables that you might be holding, everything will be cleared. However, persistent storage such as SharedPreferences will not be affected. Every value that was committed before the force closure of the app will be remain as they were.
Also, you cannot expect the lifecycle methods to be called on Force Close. So if you're doing anything inside onDestroy of a Service or an Activity, that'll most likely fail since the method is never called.
Considering this scenario: If I created an activity and it moves to the background and this activity contains a Fragment which is set to setRetainInstance(true) then the Android OS might at some point still decide to shut down the activity's hosting process in order to free memory.
Then the Activity's state is saved via onSaveInstanceState(Bundle) where - as far as I understood - the related Bundle is written and to the file system to survive the process shut down. (thus the requirement of objects in the bundle being Serializable). Later, the applications state can be retrieved in a new process via onRestoreInstanceState(Bundle).
In contrast, my Fragment is allowed to contain variables which are not necessarily Serializable. Therefore, I figured, the Fragment cannot be stored on disk like the Bundle is. So what happens to my fragment when the process gets killed?
I was wondering about this reading the developer's guide (http://developer.android.com/guide/components/processes-and-threads.html):
A process holding an activity that's not currently visible to the user
(the activity's onStop() method has been called). These processes have
no direct impact on the user experience, and the system can kill them
at any time to reclaim memory for a foreground, visible, or service
process. Usually there are many background processes running, so they
are kept in an LRU (least recently used) list to ensure that the
process with the activity that was most recently seen by the user is
the last to be killed. If an activity implements its lifecycle methods
correctly, and saves its current state, killing its process will not
have a visible effect on the user experience, because when the user
navigates back to the activity, the activity restores all of its
visible state.
I understood the above killing such that the VM instance is shut down and the state of the process is written to the file system (here comes the Bundle into play). Later the bundles are read for resuming the process. Since the retaining of fragments is not concerned with life cycle methods and since I would not know how to retain e.g. a pointer to a network connection (you should of course never have such a pointer in a fragment anyhow), I was wondering if the fragments are still restored if the process is shut down in the meantime. I concluded that they surely needed to be recreated and that the life cycle methods are therefore to be preferred over setRetainInstance(true) whenever possible.
Does this assumption make any sense?
Sounds like you're mixing up two concepts here.
Saving state across Configuration Changes does not involve serialization. If you request setRetainInstance() for a Fragment then that means it will fully stay in memory and not be re-created only for configuration changes. A similar mechanism is available for Activity objects but they need to explicitly define an Object which is going to be saved. This works via Activity.onRetainNonConfigurationInstance(), not via onSaveInstanceStae().
The other mechanism involves serialization and possibly (maybe not always, not sure) file system I/O to be able to reproduce state information even if an Activity/Fragment is destroyed (which happens independently of its hosting Process, btw). This works via Activity.onSaveInstanceState() and Fragment.onSaveInstanceState().
Of course, you can use the second mechanism for the purpose of the first, thus slowing down the way your app deals with configuration changes. Depending on your internal state, the slowdown could me marginal of significant.
Regarding your questions.
"My Fragment in contrast, is allowed to contain variables which are not serializable." Well, the same is true for your Activity. It can contain non-serializable objects which can be saved across config changes as described above.
"the fragment cannot be stored to disk when a process is shut down and must be recreated when an activity was restored." No, both mechanisms are available for both object types.
Hope I could contribute to clarifying this a bit.
Edit after your first comment.
Regarding the comment:
"onRetainNonConfigurationInstance is deprecated": Yes. I mentioned it for demonstration purposes because of a specific wording in your question. Also, with Android 2 devices having a 46% market share as per today (official Google figures), this method will definitely stay around for a very long time, deprecated or not.
"My main concern is about what will happen to the fragment instance when my hosting process is killed and removed from the memory": Your fragment instance will be removed from memory and there's of course no way it is restored as-is with its complete internal state automatically. This is only done when you setRetainInstanceState in the case of config changes. (But note that this relates to the Instance, in other words, the full object.)
Regarding your edit:
Once more, yes, your Fragment's Bundle will be stored and restored to/from the Bundle regardless of setRetainInstanceState if you use Fragment.onSaveInstanceState() for this purpose, for everything that makes sense.
It is not true that "all of its visible state" will be saved as the text you refer to claims; for example, the visibility attribute will not be saved. Whether that's supposed to be a bug or a feature I don't know, but it's a fact. But this is only a side remark; UI elements will save most of their relevant state.
"the state of the process is written to the file system": No! The state of objects which are able to save their state to a Bundle and actually implement saving their state will be saved in a Bundle, this means that you must provide such information yourself if you want your Fragment to save some state information. Also, again: No, this does not only relate to killing the process but also to deleting Activity and Fragment objects which are not visible; like the last Activity shown -- the Process may well stay alive.
"bundles are read for resuming the process": No, the Bundle will be read to pass it to the re-construction of Activity and/or Fragment objects, there is nothing done automatically in this process (except library objects which save their state also restore their state), but Android does not "resume" the "Process" from these Bundles.
"Since the retaining of fragments is not concerned with life cycle methods": Again, I think you're mixing up the two concepts. The "retaining" of a Fragment is only performed upon configuration changes _IF_ you request it via setRetainInstance, but we're mostly talking about the re-creation of Fragment objects from a Bundle here, which does involve the life cycle methods as documented by Google.
"I would not know how to retain e.g. a pointer to a network connection": Again, this must be a statement based on your mix-up. Of course you can keep a reference to a network connection upon config change (as requested per setRetainInstance) because when that happens, everything is simply kept in memory. Also, even if your Fragment gets deleted (because it became invisible) and your process is still there (because it shows the next Activity), you can (and should) keep references to objects which are expensive to re-create, such as a network connection, in your Application object, which exists as long as your process lives (more or less). It is only when your whole app is killed by Android that you lose everything, but the serialization we're discussing happens much more often.
Your conclusion:
I concluded that they surely needed to be recreated and that the life cycle methods are therefore to be preferred over setRetainInstance(true) whenever possible. Does this assumption make any sense?
Unfortunately not, since you are mixing up completely independent concepts.
I'll give it a final try:
You will want to keep a network connection reference which you need throughout your app in your Application object because it would be a lousy user experience if you created it from scratch on a regular basis throughout your app.
Your Application object will only die if Android kills your app.
Your Activity and Fragment objects will be deleted from your app regularly when the user moves forward within your app.
When the user presses "back", Android will re-create Activity and Fragment objects from Bundles using lifecycle methods. Saving something in a Bundle makes sense if you have expensive computations to do to re-create the internal state. You can live without the Bundle mechanism because Android will always save the Intent so if you don't do anything then you'll start without saved state.
When a configuration change occurs, Android lets you optimize user experience by keeping objects in memory across the config change. Here, Activity life cycle methods get involvwed and it's up to your implementation to use the saved data effectively. For Fragments, this is where setRetainInstance' comes into play: YourFragment` will survive the config change in memory if you set it.
The documentation suggests that the data should be committed/read in onPause()/onResume().
Yet when the application is no longer in the foreground, its data structures remain intact, which suggests that one could delay committing/reading data until the application is no longer visible, i.e. in onStop()/onStart(). Particularly since onStop() is guaranteed to be called before onDestroy().
Is it perhaps the case that either approach is suitable? Is the documentation giving here merely a guideline?
Update
Suppose your application needed to save relatively substantial data, say edits to a large image. One would then surely not write/read in onPause()/onResume(), lest the user experience become sluggish. One would in that case choose instead to write/read in onStop()/onStart(). Is that true?
The problem with using onStop is that you have no guarantees on when it will be called since the only sure thing is that it will be called before onDestroy. If you wait until onStop to commit your data it may be to late for another activity to show/use any of those changes. Same thing applies to onStart, your activity may not need to be restarted if it was just in the background so you'll have stale data. Using onResume and onPause guarantees that your data will always be current, commits are made as soon as the activity goes to the background and new data is loaded as soon as it becomes visible.
Yes, it is just a guideline (and generally a good one). It is up to you exactly when you want to commit changes. I personally like to create Store Objects that allow a simplification of Databases or SharedPreferences, and when a change is made, I commit those changes immediately. For simple data storage, this will be quick and invisible to the user. For large data sets, this may take more time, and you may wish to make those writes on a time interval, as well as in onPause.
As for when to read - you can read whenever, but again longer reads will often affect the user experience, unless you have taken care of it in another thread, such as with an AsyncTask.
To Further answer your update:
It depends on the developer, however I would write in onPause() and if necessary, read in a separate thread, probably initialized with onResume(). I may also write data out on a scheduled interval using a Timer thread, depending on how it would affect the user experience for the current session, and if it would be catastrophic for the phone to turn off and lose all data before onPause() is called.
The true answer to this is, onPause is the only method you are guaranteed to get called before Android can destroy your process. If a user leaves your app to take a phone call, and Android decides to close your process, its entirely legal for you to only get an onPause call. If you hadn't saved your state there, when the user hits the back button, you will end up recreating your activity in a different state than the user left it in.
I'm working on my first Android app. It has a model that is persisted to a database as the user makes updates.
When onSaveInsanceState is called, I want to save an id that can be used to load the document the user was working on from the database. But this can only happen once the document has fully hit the database. In some cases, persisting a complex document can take several seconds (I'm hoping this will speed up once I take all the verbose logging out, and in actual use a complex document will be built up by the user in stages, each of which will be persisted to the database, so it's not very likely for a complex document to have to all be saved in one go).
Now, the #1 rule of threading on Android is "don't block the UI thread", so of course the DB interactions happen on a separate thread. But my understanding of the Android lifecycle is that in many cases onSaveInstanceState is being called because the Android system wants to kill the process. That suggests I can't allow this method to return until the DB thread finishes saving the document (and in fact with my current design, I don't actually know what the id number of the document is until it's been saved to the DB, so I can't even put that in the bundle of saved state).
Is it appropriate under these circumstances to block the UI thread waiting for the persist task to be done? When onSaveInstanceState is called because the process is being killed, the app is no longer visible in the foreground, so there's no interface to become unresponsive.
But onSaveInstanceState is also called when the Activity instance is being trashed by a config update, which happens when the screen orientation changes. It's very unfortunate when rotating the screen sideways fails to do anything for several seconds. In this case the process (and therefore memory space) is still around, so I don't strictly need to ensure the document hits the database, if I can just store a reference to it in the Bundle instead of its id. But I'm not aware of a way to tell the difference between these two cases.
Is there an accepted practice for these situations? Should I just block the thread to be safe? Can I just use normal Java thread primitives to block and wait? Is there something I can do that doesn't block the thread but ensures the persist task will be finished before Android closes the process?
All this also applies to onPause, as onSaveInstanceState isn't necessarily going to be called.
You don't have to do to the persistent saving in onSaveInstanceState, you can pretty much just save the instance state in the Bundle so that the instance can be quickly resumed in onRestoreInstanceState.
The Documentation states that you should write crucial persistent data (such as user edits) to storage in onPause, but it also states that it should be fast so that the next activity can start doing whatever it is it wants to do.
I think my recommendation here would be to just save the document text and whatever in the Bundle in onSaveInstanceState and restore it in onRestoreInstanceState. Use onPause to save a "backup copy" somewhere fast (temporary file maybe?) which can then be restored in onResume if it hasn't been saved to the database. And use onStop (which is called when the activity is already in the background) to actually save the data to the database.
Note that the activity might get killed after onPause has been called (never before, unless the system has very very few resources left...), that's why I would save a quick backup before trying to commit it in the database.
Edit - Extra based on comments
To make sure the background thread that's doing the saving process is done saving before the application can be killed by the system, I think it's fine to block and wait for the saving thread to complete before returning from onPause but I recommend using android:configChanges="orientation" to prevent activity restart (and onPause call) when the orientation changes.
You should try AsyncTask, which will block your ui but wont show blank screen, will load the necessary xml elements and then will get call from Async task, in async task save your doc in database.
Follow this link: AyncTask Exmaple