I'm writing an application implementing a bar code scanner.
Several values are gathered and displayed in the same Activity. Everytime the user wants to get a new value, he calls an Intent on a another application in the device which handles the bar code scanning part, and returns a String containing the actual value held by the bar code.
In the end, mutliple values from multiple scans are meant to be displayed in the same Activity.
It works perfectly on two different devices (Nexus 7 on Android 4.4.2, Vuzix M100 on Android 4.0.4).
On those two, it goes well and on second intent return, my previous values are still stored in the Activity.
But on the Alcatel One Touch Mini s 2 (Android 4.3), everytime I come back to the first activity, it goes through the onCreate method of the relevant Activity and erases the previous scan values stored in global Activity variables.
I have searched over the web but I couldn't manage to find any clue.Why does only one phone out of three erases the Activity for every intent created, and how can I prevent it?
It doesn't seem to be a hardware ressource problem (as said in the doc, Paused intents can be destroyed to free memory) because the problematic device is almost the most powerful.
You need to be prepared for cases when your activity gets destroyed, and later recreated. For this Android calls onSaveInstanceState() where you can store the information that you need in the Bundle provided. Then when the activity is recreated, onCreate() will be called with this Bundle passed as a parameter, so you can read your data from it. You can read more about this here => Saving Activity State
"everytime I come back to the first activity, it goes through the onCreate method of the relevant Activity and erases the previous scan values stored in global Activity variables" --> could you store them in a shared preference that you read each time in onCreate?
Related
The detailed question is :
1.Whether the activity clicking order will get restore.In other words,if i click the back button again and again, whether the app's activity order will be normal.
2.what life cycle in activity will be triggered in last activity?Is it the same with the normal activity jump?
3.Was the state stored in physical memory(like sdcard)?How can i judge whether the important state was lost.
Taken from here:
Once an activity starts it goes to onCreate -> onStart -> onResume. If you minimize an activity (usually with the Home key) it will run onPause -> onStop and when android runs out of memory (because new app needs memory) then android will call onSaveInstance (where you save all the data you want) on your activity, then it will destroy it, calling onDestroy.
The next time the activity runs it will start again from onCreate and the rest, but it will pass a Bundle on the onCreate with the data you saved previously, for you to restore them. It will also run onRestoreState which gets the Bundle as well (you can use either one).
Basically, if onRestoreState runs, it means your app is restoring, or inside your onCreate check if the given Bundle is null, if it isn't then your activity is resuming.
I'm not sure if data are saved on sdcard, but I guess they are saved somewhere on physical memory, so android can free some RAM for another app.
My application is launched using a tag, and based on the information contained in tag, it further proceeds. Now my app can also be started by using touching icon, and later it asks user to touch the tag. Small flow would be as below.
So MainActivity may contains tag data(if started from TagProcessorActivity), or may not contain data (if started from icon launch). Data is passed as intent extra value from TagProcessorActivity to IconLaunchActivity then to MainActivity. After main activity, app operation proceeds. When I leave the main activity, all my previous activities gets finish. I have checked onDestroy() is called for each activity. Now if I logout after MainActivity, (Logout simply a feature that closes all existing activity), and relaunch my application from recent app, my tag details still appears in MainActivity, which I dont know why.
To make is more clear my questions are:
1) Why activity which was destroyed still contains the information from previous launch.
2) I know about removeExtra() method, but is there some better options to tackle this problem.
3) and none the less, is there some thing wrong in my code or android is keeping that instance of intent extra?
PS: Not clear which piece of code to post, so if required feel free to ask for code.
Applications never exit in Android. onDestroy only destroys the activity, not any static variables left in the app. These will keep their value the next time an Activity is launched. This can be combined with some other features (like launching from the recent tasks menu causing you to launch the same intent) and this is the behavior you will get. The answer I always used was to detect this case (by checking the intent, there's a field that says if this is a restart or fresh), and ignoring the intent extras if so.
A finished task launched from Recents (as opposed to home screen launcher icon) will receive the old Intent, including its Extras, Data, etc. There is a way to know that it was launched from Recents so you can handle the Intent appropriately.
protected boolean wasLaunchedFromRecents() {
return (getIntent().getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY;
}
In my humble opinion, that flag is poorly named (other flags referencing the Recents list actually use that word, e.g. FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS, FLAG_ACTIVITY_RETAIN_IN_RECENTS) and the documentation was never updated to reflect the fact that many popular Android devices have a dedicated button for Recents:
This flag is not normally set by application code, but set for you by the system if this activity is being launched from history (longpress home key).
What I have:
I have 3 activities in my app with a basic nested structure:
Activity 1 --> Activity 2 --> Activity 3
Activity 2 contains data embedded in an ArrayList<CustomClass>. CustomClass extends application (as taught here) and Activity 3 uses this to modify the CustomClass data for Activity 2.
What I want:
When the user hits the Home button and then opens my App again later, I want to return to whichever activity was on the top of my stack. (I thought this is supposed to be Android default behaviour.)
It works fine on my Eclipse emulator but on both my Google Nexus One and Huawei Honour, the task is completely restarted.
I have tried setting my activities to run in standard, singleTop and singleTask launch modes. The best result I could get on the phones was to return to Activity 1 (which is just a form) and still display what I had entered into the text fields before creating Activity 2.
I did also notice that if I hit Home then check the Running Applications under Settings, my app is not listed. Maybe Android might be destroying my task and I need to save the activity state. But this doesn't make sense if I press home and immediately re-enter the app?
Advice is appreciated.
There is no guarantee that once you hit the Home button and your Activity goes in onPause() it will keep its state (even it it keeps the same state, there is no guarantee on the actual amount of time the activity will remain in memory). This depends on the device in particular and how it handles its internal memory. (see this figure which shows the Android Activity Lifecycle).
The best practice is to always save your state in the onSaveInstanceState method. This post provides a good and easy example on how to do that.
My question is can i get to know when the entire application gets paused/resumed start/stop etc.
For example if i have 5 activities in my application. Whenever any activity gets paused/resumed android notify the activity by calling the onPause/onResume methods.
So there are two possible scenarios when my activity gets paused.
1. My activity-2 gets paused because my activity-3 gets invoked.
2. My activity-2 gets paused because of some outside activity like incoming call.
Here I am interested only tracking when my activity gets paused by outside activities not my own application activities.
So is there any android provided solution for this or do I have to write my customized solution.
Thanks
Dalvin
There is no solution provided by the API because it is not needed in most cases.
What you can do is to create an abstract activity and make all your activities inheriting from this abstract one.
In this abstract activity, by overriding onCreate, onResume, onPause, onDestroy, you can manage to count how many of your own activities are "alive", and then determine the state of your application.
This could work but it's not really the Android phylosophy
You can know the starting of the whole application on application.oncreate() but there is no indicator for the whole application pause. Most of the cases never needs it anyway.
So further read in the activity lifecycle and the application class.
Still you can do this option in your program by overriding the onPause in each class and save a value to the sharedPrefrences then check on this value all over the application
If I understand your question, you want your app to be able to distinguish between exiting the current activity within the context of your program or by an external event like a phone call. I have used the following method in the past to do this (although it may not be the best, it definitely works):
(1) Set up a value in SharedPreferences (the built in file for storing a program's data). Call it something like "exitStatus" which is set to 1 for an exit within the program code and 0 for an exit based on external events.
(2) Now, within each of your activities, set the value of exitStatus to 0 in onResume (which is called no matter how you enter). If your program exits due to an external event within that activity, this value will persist when the program is reloaded.
(3) At the end of your activity, at all points where you are going to transfer to another activity, first set exitStatus to 1. Then, when you arrive at the other activity, it will know that you arrived there from within your program.
(4) Thus, just to be clear, each of your activities can check exitStatus at the outset to see whether you are entering from within your program context (= 1) or after a non-local exit of some kind (= 0).
That's all there is to it. I use this method to be sure that load data for my app is present as it may be lost if a user turns off their device so that the app tries to pick up in the middle of things when they later reboot, etc.
Instead of making base activity and override onPause/onResume you can use
registerActivityLifecycleCallbacks(Application.ActivityLifecycleCallbacks callback)
where you can handle these states for application activities in one place.
I am using a separate class with only static fields, to store current application data.
It is partly populated from sharedpreferences on application startup. The rest is data like results of some action, used for further browsing these results (multiple activities that use the results).
I can go to the home screen, start other applications etc. and when I return to my own application it just works correctly.
However, since the new Error Reporting feature I get some bug reports all related to a nullreference error. The object that is null is a reference to the static field in the mentioned separate class.
Since I cannot reproduce the bug I am inclined to think this is due to the application getting killed due to low memory, and when it relaunches it calls the oncreate from the activity that the user was currently in. However all the static data in the separate class is not restored and thus it crashes.
I would like to know: Is there a way to force the application to "restart" completely, and not start with the last used activity if it gets killed? Or is that standard behaviour?
Can I do this programmatically? Like when the static fields are null, restart app?
Restarting the activity where the user was is normal behaviour - the idea is to make it look to the user like the app was never closed. There are two things you can look at:
protected void onSaveInstanceState(Bundle outState){
// This gets called by the system when it's about to kill your app
// Put all your data in the outState bundle
}
That bundle is the same one that gets passed to the activity in onCreate(). You can then get any necessary information out of it and restore the values in the static class.
The other way is to simply check the values in the onResume() method of any of your activities. If the values are null or wrong in some way, then you can call start the original activity and finish() the one being started.