I'm working on an Android application which pretty much works like this:
There are two activities.
Activity A leads to activity B.
While pressing back from activity B, the user goes back to Activity A.
I have listeners listening to internet connectivity on a fragment of Activity B.
If I press back button from activity B after staying in B for a considerable amount of time, the app crashes immediately after going to the activity A.
On seeing the error logs, I verified that the activity B is paused, Activity A is resumed and that the Fragment in activity B is stopped. But I could also see that the internet listeners in fragment in activity B are still alive even after coming back to activity A, and so it receives the ping response and the fragment seems to be coming alive.
here is the exception message I got:
main Thread[main,5, main] Disallowed call from unknown notification listener: "android.service.notification.INotificationListener$Stub$Proxy#ecbe517java.lang.SecurityException: Disallowed call from unknown notification listener: android.service.notification.INotificationListener$Stub$Proxy#ecbe517"
In the onStop() method of my fragment, i have done something like this:
myContext.unregisterReceiver(myReceiver) .
myWifiScanner.pause()
myHandler.quitSafely()
I figured out that this is the problem. How can I fix it?
I tried removing all callbacks from all handlers involved in the fragment.
Take a look at your activity life cycle.
Make sure you are pausing or destroying your activities when jumping from one to the next.
https://developer.android.com/guide/components/activities/activity-lifecycle.html
Related
I have researched numerous posts regarding Activity back stacks, as well as the Android Developer website, but still can't find a solution to a problem I'm having.
Scenario:
I have Activity A, I navigate to Actvity B, from A and then press the back button to go to Activity A again:
Actvity A --> Activity B --> Actvity A
Nothing out of the ordinary..
Problem
When I press the back button to go to from Activity B --> Activity A, Activity B is not destroyed straight away, as expected it goes into a pause state and this is where I have strange problem. If I want to return to Activity B from Activity A and IF Activity B is still in a pause state all its life cycle methods are called when use startActivity(B) from Activity A:
Activity B - onCreate() > onPause > onStop > onDestroy <-- why is this happening
At this point, to me it shouldn't exist anymore, and I can't explain why it went through all its lifecycle methods, rather than just the start initialisation lifecycle methods. The fall out from this strange behaviour is that the Activity is still visible on screen but doesn't populate a RecyclerView which in first initialisation did so as expected. At this point if I press back Activity B enters a pause state again.
If Activity B is in a pause state (Activity A is at top of stack) and the framework ends Activity B through lifecycle callbacks and I navigate to Activity B again from A it works as expected (RecyclerView is populated), basically a fresh instance always works fine.
All I can assume, when referring to the Activity Lifecycle diagram, is that Activity B enters a pause state, however is destroyed without calling onStop, onDestroy etc.. meaning any Activity clean up operations I have in those callbacks aren't happening?
Things I've Tried
Changing various Intent filters, and combinations, when starting Activity B:
FLAG_ACTIVITY_NEW_TASK
FLAG_ACTIVITY_CLEAR_TOP
FLAG_ACTIVITY_SINGLE_TOP
Calling finish() when onBackPressed() is called in Activity B
Various other fingers crossed and hope changes, nothing seems to work.
Can anyone help please!
Ok, so I found the answer to the problem - not obvious at first, but now I understand what was happening.
The root cause of the problem was to do with 2 instances of the same Activity (Activity B) referencing the same Objects (Objects supplied from DI library).
Firstly when returning to Activity A from Activity B, Activity B was not immediately destroyed, and this causes a complication - this instance would never be reused, however still existed for a period of a few seconds. In this situation when using startActivity(B) from Activity A it would create a new instance and destroy the old (hence why I was seeing logging in both creation and activity ending callbacks), if it still existed. In this scenario both instances were sharing the same object, and this object "cleaned up" the Activity when destroyed. So the object (Presenter in this case) was being told by the old instance that it should clean up the Activity as its being destroyed, however this was not the case, because a new instance had been created.
The solution
Quite simple really, every time a new instance of Activity B was created, store in the Presenter a unique number (startId), and when Activity B called onDestroy() pass its current unique number, and check they match - if they don't match its not the latest instance, so do nothing. Very similar idea when you want to stop a Service, and check its the latest Activity calling the service from the startId.
Personally I don't know why Activities aren't destroyed straight away on pressing back, but thats the reason why this was happening.
I create a child activity "B" from activity "A". if the user should leave the app for any reason (most likely hitting the home button), I would like activity "B" to end and the app to be at activity "A" once the user resumes.
If I call finish() manually, activity B ends and it returns to activity A. This is the behaviour I would like to happen when the user leaves the app.
I have tried to call finish() in the onPause(), onStop() and in the onUserLeavingHint() of activity B. In each case, this appears to work correctly, and I can see mParent.finishFromChild(this); being called inside activity B.
However, as soon as the user switches back to the app, the onCreate() of activity B gets called and the user ends up in activity B.
How can I ensure I end up in the parent activity when I call finish() from within an onStop() (or similar) handler?
UPDATE: It appears that the issue is related to activity B being declared as using a SingleInstance launch mode. Removing this feature seems to have resolved the issue. Changing this has introduced other issues that I have since managed to fix.
The reason for this happening is that Activity B is set as a SingleInstance Launch Mode. The reason it was set to this (by another developer) is somewhat related to the reason I had wished the activity was ended when the app is in the background - it was to ensure the user could not reach this activity by hitting back on any other activities subsequently dispatched from Activity B.
To resolve this. I first ensured no activities could be created from B. To instead return from B and pass any required Intents on to A. Simplifying the back stack. (Calling activity B with startActivityForResult() is one possible way of doing this.)
Now, the reason SingleInstance causes this issue to arise in this scenario, is because Activity B is launched in a seperate new task. When the user attempts to resume, they re-enter this single-activity task. The rest of the app is running in a seperate task. The only thing the task can reasonably be expected to do is relaunch the activity. When the user presses back, the only thing it can do from there is to close the task (and hence appear to exit the app). For the expected behaviour to occur the user would have had to have selected the other, first task (through a long click of the task list).
Hopefully this self-answer can help someone who has encountered a similar issue.
I wrote an Android app with several Activities and a Main Activity. When I go from the Main Activity to lets say Activity B, I want to "pause" the Main Activity, when the back button is pressed it should go back and reactivate the Main Activity instead of calling onCreate().
This shall work with all Activities, so if I click on a button to start Activity B, it shall also reactivate the old Activity B instead of creating a new state with onCreate().
How can I realize this?
PS: I already tried it with parcelable, but this do only work, if I close the application or something unexpected happens.
It's always possible that the first activity may be destroyed when you start another activity. It will be recreated when you go back to it. Every app should be written with this possibility in mind. To make sure your activities can handle being destroyed and recreated, turn on the "don't keep activities" developer option.
It is by default in Android. If you Start Activity B from Activity A then activity A goes in stopped state. Below methods will be called of Activity A
onPause()
onStop()
When you tap on Back key on Activity B. Below methods of Activity A will be called.
onRestart()
onStart()
onResume()
For reactivating Activity B, you can set Activity B launch mode as singleInstance. This will make sure that only single instance of Activity B will be created. onCreate will be not be called again. onNewIntent will be called when that activity is reactivated.
Refer: http://developer.android.com/guide/topics/manifest/activity-element.html#lmode
Activities live in stack order. Each activity has its life cycle. When you close an activity (Activity B in your example) it eventually reaches onDestroy() method and removed from the stack order. It is by default in Android and there's nothing you can do about it.
What you can do is rewrite the onStop() method in Activity B and save some activity data (like text in EditText, for example) in SharedPreferences - read here. Then in your onCreate() method you can call for SharedPreferences, check if it's not empty and restore the text in the EditText by pulling appropriate value by key.
Can someone help me replicate the following scenario:
I'm having a activity A with some specific tasks from which the app goes to activity B. When the user goes to B and presses back the app should close (maybe meaning that activity A performed finish()). But in some cases the app (not on the user action) goes back to Activity A, with the state preserved to when it went to B. The thing is that the app can never know if it should preserve activity A to be re-displayed later or not.
Hope I made it clear. Many thanks
You can start the Activity B with startActivityForResult() and in function of the result, when we come back to the activity A, Activity A finish() himself or not.
You can populate your Activity A every time in its onResume(). For persistence you can use SharedPreferences.
You can setup a BroadcastReceiver in Activity A which will call finish() for Activity A upon receiving a message. In the Activity B just before you close you then send that message to Activity A's broadcast receiver.
So, I have written an app that has a Main activity (A), and various other sub-activities that all do something, report the work back to main, and finish.
What I am running into is that if the user leaves my app at Screens B or C, when they come back at a later time and dalvik has destroyed my activities for more RAM... the app starts back at B or C, and reads all the initialization stuff from the saved intent, and continues on as if nothing happened. Until they return back to activity A, where we get a force close from unexpected things.
I've twiddled with overriding onStop() and calling finish, but i think this is a bit scorched earth, I'd like to let them leave on that activity and come back. But i'd also like to detect if the underlying main activity has been destroyed, and then destroy my entire activity stack.
From reading around, I get the idea that onDestroy() is not always called, so it isnt reliable for me to insert some logic into Activity A's onDestroy.... Any ideas?
Try starting your sub activities B and C with the flag FLAG_ACTIVITY_NO_HISTORY.