I have two Activities A1 and A2 , on firing some event i am calling A2 (through intent) from A1.
Now inside A2 i am firing some event and based on that i am calling A1 again and passing data through intent).
Now the problem is When A1 gets called from A2 with data , A1 activity load with itself with a new state but i want to maintain its old state when A1 was first loaded. indirectly i don't want to call onCreate.
so far i have tried following code in A1 activity , its a static method in A1 which load itself
public static void show(Context context , int index)
{
final Intent intent = new Intent();
intent.setAction(MC_MY_ACTION);
intent.putExtra("routeIndex", index);
context.startActivity(intent);
}
from A2 i am calling A1 as follows from onOptionsItemSelected and passing the selectedMenuIndex
A1.show(this,selectedMenuIndex);
If you want to save the state of your activity and have it persist through multiple onCreate() calls, you can use the Bundle object. You can save to the Activity's Bundle in onSaveInstanceState() and then load it back up in onCreate(). Take a look at http://developer.android.com/reference/android/app/Activity.html and http://developer.android.com/reference/android/os/Bundle.html.
If your activity has finish()'d, you're not going to avoid going through onCreate() again -- however there's no need to worry about that. Just let your onCreate() examine the contents of its intent extras, and if there are none then follow your default initialization but if there are extras, make them carry enough state data so you can be back in the previous state.
Related
I have two android activities(lets call them A1 and A2). The purpose of the first one ist to display several linear layout items. Also it features a button to add new items. When clicking on the add button using the following intent:
//...
Intent intent = new Intent(this, CreateActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
//...
the application should switch to A2 pausing the first one. When accessing a type on A2 I switch back to A1 with this:
//...
Intent intent = new Intent(super.getContext(), HomeActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.putExtra("type", this._type);
super.getContext().startActivity(intent);
//...
intent, adding a new item to the layout which works.
Now I've got the onCreate, onResume, onPause methods which are called every time I switch from A2 to A1. Is that the normal android behaviour?
As far as I understood the activity lifecycle the flags NEW_TASK, and CLEAR_TASK open up a new process pausing the Activity they're called in.
I've read several different documentations about switching Activities in android but didn't really get the point of how to explicitely tell an Activity to just pause and not call onCreate etc. again.
I think here your Activity A1 creates 2 times ,because u have one and create another one in A2 activity, so u can just start activity A2 without
(Intent.FLAG_ACTIVITY_NEW_TASK)
flag and than when you need to back to A1 call
A2.this.finish()
think this will help and A1 onPause will start calling
OnPause() is called when an activity is partially visible to the user but the user is not able to interact with it. In your case, when the next activity launches, the first activity calls onStop(). onPause() is only called when an alert box or a dialog bix is displayed in the screen. Try writing your code in onStop().
Now I've got the onCreate, onResume, onPause methods which are called every time I switch from A2 to A1.
This is normal because you query to recreate the activity with super.getContext().startActivity(intent);
Just call finish inside A2 to return to A1.
You can also put flag Intent.FLAG_ACTIVITY_REORDER_TO_FRONT to the Intent. The A2 activity will not be destroyed.
FLAG_ACTIVITY_NEW_TASK --> this flag will start new activity So first remove this.
Second if you want to send some data then A2 to A1 then startActivity by following method rather than startActivity()
startActivityForResult
And you will get a callback in
onActivityResult()
So in Activity A I pass some data to activity B through an intent. Ok, everything is fine and getStringExtra returns what I expect. Then from activity B, I pass the same data to activity C. Then, when I hit the back button in the toolbar (because of getSupportActionBar().setDisplayHomeAsUpEnabled(true)), the getStringExtra in activity B is now null.
So the flow is A (passes a string)-> B(passes the same string) -> C (back button in toolbar) -> B and now the variable passes from A to B is null. How can I fix that?
Mark this a rule : Whenever you are using the toolbar back button, you should take care of specifying the launchMode of the parent activity.
In your case, what happens after you press back button in Activity C, depends on what launchMode have you specified for your activity B.
If you have't specified any launch mode, the default launch mode is standard. In this case, the parent activity (B) is popped off the stack, and a new instance of that activity is created on top of the stack to receive the intent.
If you have specified launch mode as singleTop, the parent activity is brought to the top of the stack, and receives the intent through its onNewIntent() method. That is, the previous activity is preserved.
Refer http://developer.android.com/training/implementing-navigation/ancestral.html#NavigateUp.
In your case, you want to preserve the variable, therefore you should use singleTop launchMode.
If you are extracting the data in onCreate method of Activity B then when you hit the back button in Activity C, the onCreate method of Activity B is not called again. To get more clarity on the life cycle of an Activity I really suggest you go through this developer.android.com/reference/android/app/Activity.html
Coming to your question when you start Activity B from Activity A, store the string that you sent from A to B in a global variable rather than a local one, and perform check like
public Class B extends Activity {
private String stringData;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.xml_layout);
if(getIntent().hasExtra(yourKeyName)) {
stringData = getIntent().getStringExtra(yourKeyName);
}
//Do other stuff
}
}
In your activity B, always check before getting the String -
if(getIntent().hasExtra(KEY_NAME))
String s = getIntent().getStringExtra(KEY_NAME);
Reason being that when you press the back button then Activity B is not launched with the same intent that you create in Activity A. Hence the extras are not present.
You should be string the string extra as a global variable and always use a hasExtra check.
I think it is different processes.
The first one, when you start activity B from activity A, you pass
the data from activity A to activity B. It is obvious, so the data
will be present.
The second one, then you start activity C from activity B, because of
activity B is not on the foreground, then your data will be erased.
You can persist your data on activity B by many ways.
One of them you can implement a static global variable.
Second way, you can save your variables on activity B by saving the
data onSaveInstanceState and retrieve from onRestoreInstanceState or
onCreate
Third way you can listen onActivityResult on activity B from activity
C. When you starting activity C, you must use startActivityOnResult
and passing the data that you want to pass back on activity B. After
you finish your activity C, you must return the data that originally
from activity B.
And so on...
But the better way to achieve that is the second way, use bundle onSaveInstanceState and retrieve the bundle data when onCreate.
So i have AppCompatActivity A, B and C. From A, i start activity B, passing an Intent I0. In B´s onCreate i get I0 and initialize the UI based on that data. Now i open C (from B). When i press the app:navigationIcon back button of the android.support.v7.widget.Toolbar from C, B's onCreate is called again, but now the Intent I0 does not contain the data from getStringExtra("data") anymore.
I have tried to use onSaveInstanceState and onRestoreInstanceState as mentioned elsewhere, but onRestoreInstanceState is not called, and the savedInstanceState Bundle is null in onCreate.
So i'm wondering if there is a way to preserve either the UI state of Activity B (not destroy it?) or the Intent I0's extra data?
I've created an Example on Github
Thanks to #pskink for suggesting to set android:launchMode="singleTop" on Activity B. This solved the problem for me in that B is not recreated with an invalid Intent.
I have an activity that is resumed after a user picks a contact. Now before the user picks a contact onSavedInstanceState is called and i put a string in the Bundle. Now, After the user selects the contact and the results are returned. onRestoreInstanceState doesnt get called. only onResume() gets called. So how would i go about pulling my string back out of the bundle once the activity is resumed?
Lets say you have two Activities A and B, and Activity A starts Activity B. If you want to pass information from A to B, you can pass information from A to B with:
Intent i = new Intent(this. ActivityB.class);
i.putExtra("Key","Value");
startActivity(i);
Then in Activity B you can get the string with
String value = this.getIntent().getExtras().getString("keyName");
However, if you want to pass information from B to A you have to use a different method. Instead of using startActivity you need to use startActivityForResult. A description of this method is found here: How to return a result (startActivityForResult) from a TabHost Activity?
First, why onRestoreInstanceState isn't firing: According to the documentation, onRestoreInstanceState gets called after onStart(), which, according to the activity lifecycle diagram, only gets called after onCreate or onRestart. If your main activity isn't destroyed when the user goes to choose a contact, then onStart will never fire, and onRestoreInstanceState will never fire. The diagram shows this to be the case when "Another activity comes in front of the activity", and onPause is fired - From there your Activity will only be killed if the system needs more memory.
Second, how to get the data you saved before choosing a contact- A local variable should do it, since the activity is staying in memory. If you get to a point where the activity does not stay in memory, onRestoreInstanceState should fire.
I have two activities in which I need to pass an object array between them. From the main activity, I start the secondary activity with startActivityForResult(), and pass the array as a ParcelableArray in a Bundle. This works fine to get the array to the secondary activity; I can pull the array out of the Bundle and manipulate it from there.
The problem I'm having is when I want to pass the array back to the calling activity. I need it to occur when a user presses the back/return button on the device. I've tried placing the array back into a Bundle, calling setResult() from within onPause() on the secondary activity, but I'm assuming this is the incorrect location to perform the task. I've reached that conclusion as getCallingActivity() within onPause() returns null.
What's the proper way to return a Bundle to the calling activity in this situation?
Main Activity:
Bundle b = new Bundle();
b.putParcelableArray("com.whatever.data", items);
Intent folderView = new Intent(MainView.this, FolderView.class);
folderView.putExtras(b);
startActivityForResult(folderView, 1);
Secondary Activity:
protected void onPause () {
super.onPause();
Intent result = new Intent();
Bundle b = new Bundle();
b.putParcelableArray("com.whatever.data", items);
result.putExtras(b);
setResult(Activity.RESULT_OK, result);
}
IIRC, I've hooked onKeyDown() and watched for KeyEvent.BUTTON_BACK and called setResult() there. In Android 2.0, you'd hook onBackPressed() instead.
Another option (and one I use frequently when using activities) is the finish() method
Have you tried onDestroy instead of onPause? Alternatively, you could repeatedly call setResult within the second activity whenever the array is updated, as the result won't be passed back until the second activity is actually finished.
There's probably a better solution than either of those, but that's what came to mind.