Basically what I need is to recreate one Activity each time I call startActivity() moving the instance to the front and not destroy the other activities.
For instance, if I have in the activity stack
A->B->C->D
and from D I want to open B, the flag I currently use is FLAG_ACTIVITY_REORDER_TO_FRONT which leave the Activity stack in this state: A->C->D->B. That order in the activity stack is perfect, however, with that flag the Activity is not recreated and onNewIntent() is called.
Because the complexity of the Activity I do not want to refactor a lot of things, what I want is to recreate B from scratch (onCreate() has to be called) instead of execute my logic in onNewIntent() method. The activity stack should have the same state as if I use FLAG_ACTIVITY_REORDER_TO_FRONT. Any idea? Your help will be much appreciated. :)
If all of your work happens in onCreate() and you want the same stuff to work within onNewIntent(), then you could do potentially get away with a simple re-factor. Where all your code is in the setupActivity() call.
public void onCreate (Bundle savedInstanceStateF)
{
super.onCreate (savedInstanceStateF);
setupActivity();
}
public void onNewIntent(Intent intentF)
{
super.onNewIntent(intentF);
setupActivity();
}
Related
Suppose you have an app that has two activities: activity A (the launcher) with a button that launches activity B. The code of activity B that matters is:
final Thread.UncaughtExceptionHandler defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
#Override
protected void onCreate( Bundle savedInstanceState )
{
super.onCreate( savedInstanceState );
setContentView(....);
Thread.setDefaultUncaughtExceptionHandler( new Thread.UncaughtExceptionHandler()
{
#Override
public void uncaughtException( Thread thread, Throwable ex )
{
}
});
}
Activity B loads some bitmaps for its interface. It does NOT restore the old default uncaught exception handler on its exit. Doing A->B->A->B... causes an out of memory exception, because activity B is leaked. Why exactly activity B is leaked?
In my opinion this is the wrong architecture. For chained search you should only ever have a single instance of each Activity. You should flip between the different Activity instances by calling startActivity() and setting Intent.FLAG_ACTIVITY_REORDER_TO_FRONT in the Intent you use. Also add the data you want to display as "extras" in the Intent.
To be able to use the BACK button to back through the chain (no matter how long it is), each Activity should manage a stack that contains the data that it needs to recreate the page whenever the user backs into it. In onCreate() and in onNewIntent() the data (from the "extras") should be pushed onto the stack and displayed. You then override onBackPressed() and go back to the previous Activity by calling startActivity(), and setting Intent.FLAG_ACTIVITY_REORDER_TO_FRONT in the Intent you use. You also add an "extra" to the Intent that indicates the user wants to "go back". In onBackPressed() you should also discard the top element off the data stack of the Activity that is being left. This will ensure that the stack is correct when the user then backs into this Activity.
In onNewIntent() if the user just backed into the Activity, you just display the data that is already on top of the stack of managed data.
In this way, you only ever have one instance of each Activity, the user can chain all day through the set of activities and the BACK button always works and you don't have to worry about running out of memory.
Trying to accomplish this using taskAffinity or Intent flags or similar will not work. Don't waste your time. It is also bad programming style.
I hope this is clear.
and for memory exception useadd manifest
android > v3
<application
....
android:largeHeap="true">
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 the following situation:
Activity A
Activity B (marked on manifest as singleTop)
When I go from A to B, I call B.startActivity setting the flag
"FLAG_ACTIVITY_REORDER_TO_FRONT"
(in this way when already open I don't recreate the activity).
When from B I come back to A, i call A.startActivity so another activity "A" is started.
So, when i do these steps a lot of time after 20 times, android destroy all my activities and an exception is generated.
Question: how I can do to open the activity A only one time reloading the existing one from onCreate?
thank you
You may do it by override method onNewIntent, and add to Activity A or B in AndroidManifest.xml: android:launchMode="singleInstance"
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
// do something to reload....
}
It mean whenever you startActivity(intent) to A or B, the old instance of A or B will do something to reload.
Hope it help you.
I need to launch the same instance of an activity even if the user goes back and forth with the navigation. The user navigates in a stack of different activies (A, B, C), but when he goes to one of these activities it will show the same instance of that activity (like a static activity) calling only onResume.
You can't force your Activity to start up in onResume(). What you can do, however, is save your Activity's state to a Bundle in onPause() and onStop(). Then, in onStart() read this Bundle to get your Activity's state.
The closest you can get to this is to use FLAG_ACTIVITY_REORDER_TO_FRONT in the Intent you use with startActivity().
However, this will call more than onResume(). At minimum, your activities will be called with onRestart() and onStart(), assuming that whatever was in the foreground took over the whole screen.
Right now an activity gets destroyed when the BACK key is pressed. How can I make it just stop ( i.e. keep all the variables, etc. alive ), rather then be destroyed?
Thanks!
Why is it that you need to keep the variables alive? Given the established lifecycle of an Android application, I'm not sure that preventing the activity from being destroyed "just to keep the variables" makes sense.
Even if you stop the application without destroying it, there is always the chance that Android will kill it to free up memory. You will have to account for this in your code anyway, and so preventing the application from destroying doesn't save you from writing code.
Variables can be saved and restored relatively easily and quickly using SharedPreferences in your onPause() and onResume() methods. Unless you are storing a ton of data, preventing the application from destroying might not make much of a difference.
It sounds like you want to keep the variables in memory because you intend to return to this activity. Typically, you don't use the back button to navigate away from activities that you intend to come back to. Instead you would create an Intent and start a new activity. When you do this, Android places the current activity on the Back Stack calling onPause() and onStop(), which seems like exactly the sort of behavior you are looking for.
So if you still really want to prevent your activity from being destroyed (at least until Android decides it's using too much memory and kills it on it's own) you could always use Sagar's code and start a new activity in onBackPressed().
#Override
public void onBackPressed()
{
Intent intent = new Intent(this, Other.class);
startActivity(intent);
}
Just be certain that that is what you really want to do.
Simple one line
#Override
public void onBackPressed() {
mActivity.moveTaskToBack(true);
}
Pressing the BACK key triggers the onBackPressed callback method of Activity class. The default implementation of this callback calls the finish() method.
http://developer.android.com/reference/android/app/Activity.html#onBackPressed()
You can override this method to move the activity to background (mimick the action of pressing the HOME key.
eg:
#Override
public void onBackPressed() {
onKeyDown(KeyEvent.KEYCODE_HOME);
}
You could also instead consider moveTaskToBackground() mentioned here:
Override back button to act like home button
I have managed to work out exactly what you want: switch between 2 activities using Back button and keep them all not to be destroyed!
For example: you have 2 activities A & B. A will be started first, then A calls B. When B is loaded, user press Back button and switches back to activity A from B. From now B should not be destroyed and just goes to background, and when user starts activity B from A again, activity B will be brought to foreground, instead of being re-created again or created new instance! How to implement this:
1. Override onBackPressed() of activity B:
#Override
public void onBackPressed() {
Intent backIntent = new Intent(this, ActivityA.class);
backIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(backIntent);
}
2. On activity A, call activity B:
public void callActivityB() {
Intent toBintent = new Intent(this, ActivityB.class);
toBIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(toBintent);
}
remember to add flag: Intent.FLAG_ACTIVITY_REORDER_TO_FRONT when you call A&B.
This is similar to this question that was asked earlier.
Hope this helps!
N.S.
First of all, sorry for not answering the question, cause, I still have no optimal answer for it.
But, I really like when people start asking "what do you need this for". And, very rarely, the person who asked the question, really deserves this kind of question. I think not this time, but ok, this is not the issue...
Anyway, I will try to point out why some of us are convinced that
going from Activity A to Activity B(creating UI based on some data fetching) AND
going back from B to A(destroying all the created UI and/or fetched data in B) is sometimes a bad concept. Better solution would be to keep the stack as it is, so using something like finish() in Activity B, but keeping the Activity B in Pause state, so later when calling it again from Activity A - it just goes in onResume = nothing recreated in UI, no additional data fetching. The bonus of course is a fast and responsive UI, and the difference is really if you have a more complicated UI layout.
Just specify in the manifest for the activity as
android:persistent="true"
That should prevent your activity getting destroyed. To know more about this please refer to these below links which were answered by me
How to prevent call of onDestroy() after onPause()?
Prevent activity from being destroyed as long as possible
In the above posts I have explained in detail with a use case