Issue
I have two activities; let's say A and B. In activity A
there is a broadcast receiver registered that listens for a particular event which will finish activity A. I am registering the broadcast receiver in onCreate()
, and destroying it in onDestroy()
of activity A
.
For simplicity, there is one button
in activity B
named "Destroy Activity A". When a user clicks on button
, activity A
should be destroyed.
Normally all of this is running smoothly without any issues,but the problem occurs in following scenarios:
1) Suppose I am in activity B
and i press the Home key to move the application to the background then if i use other resource-heavy applications, Android system will kill my application to free memory. Then If I open my application from recent tasks, activity B
will be resumed, and it's onCreate()
, onResume()
etc method will be called. Now I press button
to destroy activity A
, but activity A has already been destroyed, so activity A
's onCreate()
, onResume()
etc methods will not be called until and unless i go to activity A
by pressing the back button
. Thus broadcast receiver
is not registered to listen for the event.
2) The same problem will arise when user has selected "Don't keep activities" from Developer options in the device's settings.
I have been looking to solve this issue for a long time, but i am unable to find a proper answer. What is the best way to handle this scenario? Is this an Android bug? There should be some solution for this issue.
Please help me.
Solution
This cannot be fixed while keeping your current broadcast logic.
Killing activities from the backstack, imo, is not a correct approach. You should strongly consider changing the logic of your navigation.
But if your project is big and time is a problem, and refactoring is out of the question, A.J. 's approach works, but you mentioned that you have lots of activities that needs to be killed, his solution becomes very tricky to implement.
What I suggest is the following. This might not be the best idea, but I cannot think of another. So maybe that could help.
You should have the following:
- A Base Activity for all your activities.
- A
ArrayList<String> activitiesToKill
object at the application level. (If you did not extendApplication
you can have it as static variable
First we have to make sure that the activitiesToKill
is not lost when the OS kills the app in low memory. In the BaseActivity
we save the list during onSaveInstanceState
and restore it in the onRestoreInstanceState
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable("activitiesToKill", activitiesToKill);
}
private void onRestoreInstanceState(Bundle state) {
if (state != null) {
activitiesToKill = (ArrayList<String>) state.getSerializable("activitiesToKill");
super.onRestoreInstanceState(state);
}
}
The idea here is to save which activities should be killed in the list, by using their name.
The logic is as follow:
Let's say you have Activities A, B, C, D and E
From Activity E, you press the button and you want to kill B and D
When you press the Button in E, you add the names of B and D to the activitiesToKill
object.
activitiesToKill.add(B.class.getSimpleName()
activitiesToKill.add(D.class.getSimpleName()
In the onCreate
method of the BaseActivity, we have to check if the
if(savedInstanceState != null)
{
//The activity is being restored. We check if the it is in the lest to Kill and we finish it
if(activitiesToKill.contains(this.getClass().getSimpleName()))
{
activitiesToKill.remove(this.getClass().getSimpleName())
finish();
}
}
Make sure to remove the name of the activity if it is killed through the broadcast.
So basically this is what happens in every scenario.
If the app is running normally, and you click the button, the broadcast gets sent and B and D will get killed. Make sure to remove B and D from the activitiesToKill
If the app was killed and restored, you press the button, the broadcast will have no effect, but you have added B and D to the activitiesToKill
object. So when you click back, the activity is created and the savedInstanceState is not null, the activity is finished.
This approach consider that activity E knows which activities it has to kill.
In case you DON'T know which activities to kill from E, you have to modify this logic slightly:
Instead of using an ArrayList use a HashMap<String, bool>
When Activity B is created, it will register it self to the hashmap:
activitiesToKill.put(this.class.getSimpleName(), false)
Then from Activity E, all you have to do is set all the entries to true
Then in the on create of the base activity you have to check if this activity is registered in the activitiesToKill (the hashmap contains the key) AND the boolean is true
you kill it (don't forget to return it to false, or remove the key)
This ensure that each activity register itself to the HashMap and Activity E doesn't have top know all the activities to kill. And don't forget to remove them in case the broadcast kills them.
This approach also ensure that the activity is not killed when opened normally from an intent because in that case onSaveInstanceState would be null in the onCreate, so nothing will happen.
More advanced checks can be accomplished in case you have groups of activities that needs to be terminated through different conditions (not only a button click) so you can have a HashMap of a HashMap to divide them in categories.
Also note, that you can use getName instead of getSimpleName if you have multiple activities with same name but different bundles.
I hope my explanation is clear enough as I wrote it from my head, let me know if any area is not clear.
Best of luck
Answered By - Y2theZ
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.