Android onActivityResult and onResume Lifecycle after low memory cleanup - android

I have two activities: ActivityA and ActivityB. ActivityA starts Activity B for result, and expects a certain resultCode. If it does not get it, ActivityA finishes. The idea is that this closes the application.
ActivityA also has an onResume method that does some stuff. I do not want this stuff to be done if ActivityA decides to finish in the onActivityResult method.
This works in most cases, except in low memory situations where android removes both ActivityA and ActivityB from memory and reloads them.
For example: ActivityA starts ActivityB. Background the application. Then android does its memory cleanup whatever. We can simulate that in DDMS.
Bring App To Foreground.
onCreate() called for ActivityB
Back Button to finish ActivityB
onCreate() called for ActivityA
onActivityResult() called for ActivityA
result is a cancel, call finish()
onResume() called for ActivityA
on resume does stuff
These last two steps are not desirable. Without the low memory issues, the normal workflow looks like this:
Bring App to Foreground
Back Button to finish ActivityB
onActivityResult() called for ActivityA
result is a cancel, call finish()
I have seen this on both a phone running Gingerbread and a Nexus 7 running Jellybean.
My first question: Am I missing something obvious in the Activity Lifecycle?
Failing that, is this the expected behavior from Android? Is there an elegant way to resolve this, or do I have to hack something, or should I try a different approach all together?
Thanks in advance. If anyone needs more information or code, just let me know.

You can declare a class member private boolean mShouldFinished. Set it to true in onActivityResult when called finish. In onResume check mShouldFinished and if true call finish.

Related

Android : Returning to prior Activity

When you're in an an Activity (we'll call it A), and you invoke a subsequent Activity (B), perhaps as a result of clicking a button in A, and then RETURN to that prior Activity A, either by clicking the Back button or explicitly calling finish() from within B, it causes A to be completely rebuilt, calling its constructor and its OnCreate() method, etc.
Is there any way to prevent that from happening, so that it actually does return to the prior, already existing, Activity A?
Correct me if I'm wrong, but it should not call onCreate() here's a gross over simplification, but let's say activity's are managed much like a simple stack, let's call it AppStack
When a onCreate() for Activity A is called, the OS pushes the Activity Instance onto the AppStack
________ _________________
Activity|
___A____|_________________
When you click a button on Activity A, it launches a new intent to Activity B
Intent actB = new Intent(this, ActivityB.class);
and subsequently puts Activity A into Stopped state
When Activity B's onCreate() is called the OS pushes that Activity Instance onto the AppStack
________ __________________
Activity|Activity|
___A____|___B____|_________
Now if you call finish() or super.onBackPressed() in Activity B, the OS will pop() the Activity from the AppStack
________ __________________
Activity|
___A____|__________________
When the OS returns to the previous activity, it sees that it is Stopped and begins the process of Resuming it through onResume().
Now if there is some data that you require to be persistent, you can add it in by Overriding onResume()
Check out the activity lifecycle docs, for more info:
This is by design:
If an activity is paused or stopped, the system can drop it from memory either by asking it to finish (calling its finish() method), or simply killing its process. When the activity is opened again (after being finished or killed), it must be created all over.
See Activity Lifecycle. It's also why the Service class exists:
A Service is an application component that can perform long-running operations in the background and does not provide a user interface. Another application component can start a service and it will continue to run in the background even if the user switches to another application.
It's not a typical scenario but when onCreate() is called when going back to that activity that means the Android OS kills it in the background.
Reason: Android is experiencing some memory shortage so killing some of the background task will be a must.
Is there any way to prevent that from happening?
No, you don't have a control over it, there are many reasons why its having a memory shortage e.g. other app installed that certain device is consuming more than expected. Although you can handle this use-case by storing the current information in onSaveInstanceState() and recovering the value from onCreate().
Calling finish() on ActivityB or pressing back will just destroy ActivityB.
ActivityA will not be completely rebuilt. This means it will not call onCreate method. It will just call onResume.
This is the normal behaviour.
However, on special situations, the system could destroy ActivityA (maybe because it needs memory to perform another task), so when you go back to it, the system will have to rebuild it.
To simulate this situation, there is a setting that you can check/uncheck, called "Don't keep activities".
If you have it checked, you will be simulating the situation explained above, it will always destroy the ActivityA as soon as it is not shown, and when you come back to it, the system will have to rebuild it calling onCreate.

Difference between finish() and System.exit(0)

I'm talking about programming in android.
In early days I thought that, finish() closes current activity and go back to the previous in Activity stack, and System.exit(0) closes the whole application.
But I was wrong.
I made a small experiment and understood that Both will finish only the current Activity.
The only differences that I could notice is that, in Android 2.3.3
The ActivityResult is propagated back to onActivityResult() using finish(). Whereas onActivityResult() not called for System.exit(0).
But in Android 4.2.2, onActivityResult() is called for both! and Intent was null for exit().
(I tested only in these 2 devices)
There is a time lag when using exit() whereas finish() is faster.(seems like more background operations are there in exit())
So,
what's the difference between two?
In which situations, I can use exit()?
I believe there is something more that I'm missing in between the two methods.
Hope somebody can Explain more and correct me.
Thanks
EDIT UPON REQUEST:
Make an Android application with 2 Activities. Call second Activity from Launcher activity using Intent. Now, inside the second activity, upon a button click, call System.exit(0);.
"The VM stops further execution and program will exit."????(according to documentation)
I see first activity there. Why?
(You are welcome to prove that I'm wrong/ I was right)
Actually there is no difference if you have only one activity. However, if you have several activities on the stack, then:
finish() - finishes the activity where it is called from and you see the previous activity.
System.exit(0) - restarts the app with one fewer activity on the stack. So, if you called ActivityB from ActivityA, and System.exit(0) is called in ActivityB, then the application will be killed and started immediately with only one activity ActivityA
According to android Developer -
finish()
Call this when your activity is done and should be closed. The
ActivityResult is propagated back to whoever launched you via
onActivityResult().
System.exit(0)
The VM stops further execution and program will exit.
According to the documentation, The program will exit.
But it seems a bug in the documentation. In case of a java program, it is correct. But coming to Android, You will see the previous Activity from the stack.
Since Android coding is done using java coding, most of the documentation is same as those for java.
From documentation,
System.exit(0)
The VM stops further execution and program will exit.
For Android aspect, we have to replace the word 'program' with something else. May be Activity or Context.
Sa Qada answer is correct after my testing.
finish will close this activity and back to prevous.
but exit will close current activity too and empty all the activity in freeze and start again the previous activity
Actually there is no difference if you have only one activity.
However, if you have several activities on the stack, then:
finish() - finishes the activity where it is called from and you see
the previous activity. System.exit(0) - restarts the app with one
fewer activity on the stack. So, if you called ActivityB from
ActivityA, and System.exit(0) is called in ActivityB, then the
application will be killed and started immediately with only one
activity ActivityA

Understanding of the start and stop of a game in Android

I'm developing a videogame in Android. For it, I'm using a game loop and all the typical stuff it envolves. I have a doubt about the states of the activity in android.
I need an activity to create the GLSurfaceView and so, the problem is the activity, when it finishes its onCreate method, continues this way: onCreate -> onResume -> onStart -> onStop.
I guess it goes throught those states because the activity doesn't have anything to do and it's the loop who is working. But I have a problem with this behaviour:
How can I know when the user "minimize" or put the device in a stand by state? Again, the methods onStop -> onResume -> onStart will trigger, but, how can I difference this time with the first?
I need to stop the loop when the user switch the device to stand by, but not when it starts the first time.
I hope I have explained well. Thanks.
If onStop is running immediately after onStart, something is wrong. The activity will only be placed in the Stopped state only when it is no longer visible to the user. Unless maybe your code immediately creates another activity that displaces it as the foreground activity, I guess, but if the activity is visible on the screen, onStop shouldn't be firing. Some code would be helpful in diagnosing that.
onPause occurs when the activity is still visible but there is another activity that is being resumed. If you're trying to save game data or something when the user backs out of the app, gets a phone call, turns off the screen, etc., I'd use onPause, because onStop is not guaranteed to be called and you run the risk in certain situations of the system killing your activity before you can do what you need to do.
For more info on activity lifecycle, see the Activities guide.

Want to start a new activity but let the original activity finish first

I have an Android activity we'll call A which has a button and another activity B. When the user clicks the button in Activity A, I'd like to finish A (let both onStop and onDestroy finish running) and then start up the instance of B. When I put a finish() and startActivity() call in the button click listener, the instance of B starts up before the old instance of A finishes. Can someone help me figure out a way to do what I'm looking for?
What you are looking for is not possible and actually is against Android's activity lifecycle implementation.
Correction
It is possible with android:noHistory="true" tag in your manifest, but for what you are trying to do it seems wrong (read the EDIT)... Messing with the activity stack makes a non intuitive application!
Android OS doesn't let you control when activities will be removed from memory (or killed), and therefore all these fancy "Task killers" are so popular (DONT use them, they only make things worse).
When your activity's onStop() is being called, the activity stops completely, and it just hangs in your memory, but that's fine...
If you want to reset the state of activity A, or close the app when exiting activity B, just create a set of rules in both onResume() and onStop(), you can do everything you wish by creating a set of rules in those functions.
for example: have a boolean in activity A that turns true just before calling activity B,call finish() on your activity A's if this boolean is true
I suggest that you take a look at Android's Activity lifecycle diagram, and make sure that everything you do follows the best practice.
EDIT
I saw your comment, it seems like you are trying to create things that are already in your memory, don't recreate them, it's a waste of CPU time, memory, and battery.
Instead, create a static class with a singleton that will hold all your shared data !
I believe you're looking for
onPause()
which is what gets called when the activity is sent to the background. You can do whatever cleanup you want in there. onStop should only be called when a user is exiting out of your program (or launching another one)
onPause is a better place to do this cleanup. See the Saving Persistent State section of the Activity doc.
When an activity's onPause() method is called, it should commit to the backing content provider or file any changes the user has made. This ensures that those changes will be seen by any other activity that is about to run. You will probably want to commit your data even more aggressively at key times during your activity's lifecycle: for example before starting a new activity, before finishing your own activity, when the user switches between input fields, etc.
While I'm not definite that your cleanup is for user changes, the bold sentence above implies that onPause will complete before the next Activity is created. Of course that probably implies that you'll have to move some setup to onResume...
Alternatively, you could move all your cleanup code to a method, let's just call it cleanup and then just call it before you start activity B. You'll have to put in appropriate guards for your onDestroy cleanup too of course.
override finish() method.
implement cleanUp() method.
create boolean isClean=false in the activity
in cleanUp() write your clean up code.
call cleanUp() in your finish()
check for isCleaned in finish() or in cleanUp() if its true then ignore the clean
now before you start B , call cleanUp() and set isCleand=true
after you call B , call finish()
Start activity A
from inside A startService(c) and finsh A
from inside the service , start Activity B

Question on Application Lifecycle and onSaveInstanceState

My application interacts with the Browser in a couple of use cases:
First Case:
Start MyApplication ActivityA from launcher.
Start MyApplication ActivityB using startActivityForResult (ActivityA's onSaveInstanceState is called).
Start Browser using startActivity (ActivityB's onSaveInstanceState is called).
Close browser or press Back. ActivityB is restored from the saved instance state bundle.
Second Case:
Start MyApplication ActivityA from launcher.
Start Browser using startActivity (ActivityA's onSaveInstanceState is called).
Browser calls back MyApplication ActivityA (i have no control over how the browser calls back, as in what flags are using for starting the activity. How it calls back is that i am passing it a callback URL (Google OAuth callback URL), and i have an intent filter in my ActivityA to intercept that URL.)
Start MyApplication ActivityB using startActivityForResult (ActivityA's onSaveInstanceState is called).
Start Browser using startActivity (ActivityB's onSaveInstanceState is NOT called).
Close browser or press Back. ActivityB can't fully be restored, because onSaveInstanceState isn't called in the previous step.
My questions would be related to step 5 of the second case, where the onSaveInstanceState is NOT called.
Reading through the Android fundamentals on lifecycle, as well as the onSaveInstanceState API, i sort of understand why it was not called. This is from the API for onSaveInstanceState:
One example of when onPause() and onStop() is called and not this method is when a user navigates back from activity B to activity A: there is no need to call onSaveInstanceState(Bundle) on B because that particular instance will never be restored so the system avoids calling it.
i.e. Because the flow is like
ActivityA -> Browser -> ActivityA -> ActivityB -> Browser
since there is already a prior Browser activity, ActivityB is deemed to be navigating back to the Browser, hence onSaveInstanceState is not called.
Am i correct with the understanding above?
In this case, should i really be using onPause instead of onSaveInstanceState? (From a laziness point-of-view, onSaveInstanceState is much simpler because i can just dump stuffs into the bundle instead of having to design/create a SQLite table which i'll have to do for onPause.) But what is the best practice for this?
It would seem then, if i am correct on 1 and 2, that saving state using onPause is much more robust than using onSaveInstanceState. What cases then, should we really be using onSaveInstanceState instead of onPause?

Categories

Resources