I am facing a strange issue
Activity A gets called and Fragment A has been attached to it.
Method gets called (onCreate, onStart,onResume) .
: I received the notification and I tab on that with intent for Activity A.
Blockquote
(intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
)
When Activity A is opened it call the below method.
(onPause,onCreate, onStart,onResume (Fragment detached) and than onDestroy)
Why on destroy is called for the old instance of the activity when I have already called CLEAR_TOP.
Can someone help me what can be the cause for this?
How can I check if there is any instance is pending in stack already or how can I clear everything?
I can not use singleInstance as on notification tab I am redirecting to different fragment.
If you use only FLAG_ACTIVITY_CLEAR_TOP then all instances of activities will be cleared, back to and including the instance of the target Activity, and then a new instance of the target Activity will be created.
If you want to reuse an existing instance, you need to specify both FLAG_ACTIVITY_CLEAR_TOP and FLAG_ACTIVITY_SINGLE_TOP like this:
intent.addFlags(FLAG_ACTIVITY_CLEAR_TOP|FLAG_ACTIVITY_SINGLE_TOP);
This will clear all instances of activities back to (but excluding the target Activity, and call onNewIntent() on the target Activity with the new Intent.
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 want to keep a single instance of every Activity I start in my application. The launchMode singleTask was an option but it is working for only one Activity.
I want
to start an Activity if there is no instance and it is called.
and if any other instance of that Activity is present already then
that instance will brought to front without creating a new instance
of that Activity.
This property will be applied to more than one Activity.
No Activity does guarantee that it will be always on the top of the history stack.
My work until now:
I got many suggestions which are not valid for my case, so I want to point these out so that no other person would give the same suggestion.
I have set the launchMode to singleTop and this works only if the Activity is at the top of the history stack. onNewIntent() only gets called if Activity is at the top of history stack. and in my case the Activity may be at any position in stack. So this is not working.
When you launch an Activity, do it like this:
Intent intent = new Intent(this, MyActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent);
If an instance of this Activity already exists, then it will be moved to the front. If an instance does NOT exist, a new instance will be created.
You can set the android:launchMode of your activity to singleTop
In this case the if the activity already exists, new intents will bring it to front will be delivered to the activity's onNewIntent()
http://developer.android.com/guide/topics/manifest/activity-element.html#lmode
This will work if your activity is on the top of the stack.
if you want to have a single instance of the activity, then you can set your launchMode to singleTask, but this is not recommended as it will make your activity reside in a separate task , which can be confusing to the users.
Use singleTop launch mode instead (docs): if there already is an Activity instance with the same type at the top of stack in the caller Task, there would not be any new Activity created, instead an Intent will be sent to an existed Activity instance through onNewIntent() method.
See can also this article for details on launch modes.
I have created an activity , set it's filter as a Home activity and set launchMode with singleTask. When I press home ,the activity will be in onpause state then onStop . What confuse me is why the activity will be re-launched when back from icon displayed on "home pick" dialog ? It calls onCreate() again without invoked onDestroy().
I know there is a way to solve this problem that is to set launcherMode as singleIstance, but this way is not good enough, because it will cause an other issue that the activity will not be able to process onActivityResult.
You may want to tell what you wish to achieve. Because that's how singleTask is. It delivers existing intent to onNewIntent() of the existing instance of activity. So activity will not be destroyed but onCreate() will be called, as it will reCreate activity with existing intent.
Quoting the documentation
The system creates the activity at the root of a new task and routes the intent to it. However, if an instance of the activity already exists, the system routes the intent to existing instance through a call to its onNewIntent() method, rather than creating a new one.
I have 2 activities (A and B) and they have 2 buttons to switch between.
A oncreate
B oncreate
A oncreate
A onresume
what I wanted to do is after sending intent from B to A oncreate should not be called but at this point it does. To overcome that I found FLAG_ACTIVITY_REORDER_TO_FRONT (from here) and thought it could called only onresume but it didn't.
FLAG_ACTIVITY_REORDER_TO_FRONT does exactly what you think it should do. However, if you start ActivityA and then ActivityA starts ActivityB and calls finish() on itself, then when ActivityB starts ActivityA with an Intent that has FLAG_ACTIVITY_REORDER_TO_FRONT there will be no instance of ActivityA to bring to the front. In this case Android will simply create a new one. I can only assume that is what you are seeing.
FLAG_ACTIVITY_REORDER_TO_FRONT changes activity history. If the requested activity is found in the history of previously visited activities (in a task), the older history record for this activity is cleared. So, while pressing back button, user will not encounter this activity in a task.
This flag won't affect the call to onCreate(), If activity does not exists in the task (not loaded or destroyed), onCreate() will be called to create it.
You can't just cancel onCreate. If B is full screen activity android can kill A activity and will recreate it when you try to restart it with FLAG_ACTIVITY_REORDER_TO_FRONT flag and call it's onCreate method. If Activity A will be still alive at the monent when you try to bring it to front, onCreate method should not be called.
Maybe in your case you should try to use fragments?
I have an Activity A with a button on it which when clicked navigates to Activity B. Now from this Activity B when the back button is pressed i get back to Activity A which is quite obvious. But once again when i click on the button on Activity A a new instance of Activity B is launched.
My query: Is there a way so that when i press the back button on Activity B it's instance is stored and so when i again click the button on Activity A the saved instance of B is launched instead of a new one.
Hoping for a solution..
if you don't want to pass data.. or just want to go back on Previous activity
finish() in onClick
http://developer.android.com/reference/android/app/Activity.html
In addition, the method onSaveInstanceState(Bundle) is called before placing the activity in such a background state, allowing you to save away any dynamic instance state in your activity into the given Bundle, to be later received in onCreate(Bundle) if the activity needs to be re-created.
To think that it won't be easy to deal with it. The activity in the android can be store but you cannot call the android system to using that instance of your when you navigate to the activity B.
Read this link http://developer.android.com/reference/android/app/Activity.html
it give all information that you can do with it but not all as you want.
When you navigate from activity B to activity A the android itself has been store your activity B's instance temporarily in the memory and that instance will destroy completely anytime later. If you navigate it from A to B again, then the instance of Activity B will be reuse again if it still exist in the memory otherwise it recreate the activity again. In any case the activity B is reuse or recreate, the method onCreate is always call (all method in Lifecycle like onResume ...etc) then all data of your activity B is now new data that's not your old data before you navigate it to the activity A. This is what android system doing so that you cannot launch activity B without calling those method.
if you want the activity B look like the same as before navigate to activity A you should probably saving the necessary data in the method onPause() on the activity B then set those data back to the component of activity B when it call onCreate(). The method onSaveInstanceState(Bundle) should not be use in this case because the android os version which is before honeycomb (3.0) is not invoked that method.
This could be difficult to deal if you are working with online data or listview, webview ...etc and also save data by your own it could the risk to your application itself.
Anyway I hope this could be some help to you.