Failback using navigateUpFromSameTask ()

I have two actions: A and B. When action A is first launched, it refers to the Intent passed to it (since Bundle is null , as it should be the first time), and accordingly displays information:

 CustInfo m_custInfo; ... protected void onCreate(Bundle savedInstanceState) { ... Bundle bundle = (savedInstanceState == null) ? getIntent().getExtras() : savedInstanceState; m_custInfo = (CustInfo) m_bundle.getSerializable("CustInfo"); if (m_custInfo != null ... } 

This works great for the first time. The EditText and ListView populated correctly.

Now, when an item in the list is clicked, action B starts to show the details:

 m_custInfo = m_arrCustomers.get(pos); Intent intent = new Intent(A.this, B.class); intent.putExtra("CustInfo", m_custInfo); // CustInfo is serializable // printing this intent, it shows to have extras and no flags startActivityForResult(intent, 1); 

Right before B starts, the framework calls A overridden onSaveInstanceState() :

 protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putSerializable("CustInfo", m_custInfo); } 

In step B, when the Up button is pressed on the action bar, I want to return to activity A and be in the same state as before:

 public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == android.R.id.home) { Intent intent = NavUtils.getParentActivityIntent(this); // printing this intent, it shows to have flags but no extras NavUtils.navigateUpFromSameTask(this); // tried finish() here but that created an even bigger mess return true; } ... } 

This is the problem when in the onCreate() activity A a second time, the Bundle parameter is null and getExtras() returns null . Since onSaveInstanceState() was called, I would expect the Bundle parameter to be non- null .

I read about this issue on other websites, tried suggestions, but nothing works.

+62
android android-activity android-actionbar up-button
Jan 22 '13 at 15:47
source share
4 answers

If you want your application to react in this way, you must declare your activity A launch mode as:

 android:launchMode="singleTop" 

in your AndroidManifest.xml.

Otherwise, the android uses the standard launch mode, which means

"The system always creates a new instance of the action in the target"

and your activity is recreated (see Android Documentation ).

With singleTop, the system reverts to your existing activity (with the original extra) if it is at the top of the back of the task. In this situation, there is no need to implement onSaveInstanceState.

savedInstanceState is null in your case, since your activity has not previously been disabled by the OS.

Please note (thanks, Android developer for pointing this out ) :

While this is a solution to the issue, it will not work if the action that is being returned is not at the top of the back stack. Consider a case of activity A starting with B, which starts with the parent activity of C and C, set to A. If you call NavigateUpFromSameTask() from C, the activity will recreate because A is not on top of the stack.

In this case, you can use this piece of code instead:

 Intent intent = NavUtils.getParentActivityIntent(this); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP); NavUtils.navigateUpTo(this, intent); 
+122
Apr 22 '13 at 12:27
source share

This is because NavUtils.navigateUpFromSameTask() basically just calls startActivity(intentForActivityA) . If action A uses the default value android:launchMode="standard" , a new instance of the action is created and the saved state is not used. There are three ways to fix this, with various advantages and disadvantages.

Option 1

Override getParentActivityIntent () in action B and specify the appropriate additional functions necessary for activity A:

 @Override public Intent getParentActivityIntent() { Intent intent = super.getParentActivityIntent(); intent.putSerializable("CustInfo", m_custInfo); return intent; } 

Note. If you use ActionBarActivity and the toolbar from the support library, you need to override getSupportParentActivityIntent () instead.

I feel that this is the most elegant solution, since it works regardless of how the user switched to activity B. The two options below do not work correctly if the user directly goes to activity B without going through activity A, for example, if action B is run from a notification handler or URL. I think this scenario is the reason that the up API is complex and doesn't just act like a dumb button.

One drawback of this solution is that instead of animating the return to the previous action, the standard animation of the transition to the beginning of a new action is used.

Option 2

Intercept the up button and treat it like a dumb back button by overriding onNavigateUp () :

 @Override public boolean onNavigateUp() { onBackPressed(); return true; } 

Note. If you use ActionBarActivity and the toolbar from the support library, you need to override onSupportNavigateUp () , instead.

This solution is a little hacky and works only for applications where the "up" and "back" should behave the same. This is probably rare, because if the up and back should behave the same, then why bother with the up button? One of the advantages of this solution is that it uses the standard animation of returning to a previous activity.

Option 3

As suggested by yonojoy, set android:launchMode="singleTop" to activity A. For more details see his answer . Please note that singleTop not suitable for all applications. You will have to try and / or spend some time reading the documentation to decide for yourself.

+15
Nov 06 '14 at 22:00
source share

Instead of calling NavUtils.navigateUpFromSameTask

You can get the parent's intention and change it before navigating. For example:

 Intent intent = NavUtils.getParentActivityIntent(this); intent.putExtra("CustInfo", m_custInfo); // CustInfo is serializable NavUtils.navigateUpTo(this, intent); 

This will behave exactly like NavUtils.navigateUpFromSameTask , but will allow you to add some additional properties to the intent. You can just take a look at the code for NavUtils.navigateUpFromSameTask .

 public static void navigateUpFromSameTask(Activity sourceActivity) { Intent upIntent = getParentActivityIntent(sourceActivity); if (upIntent == null) { throw new IllegalArgumentException("Activity " + sourceActivity.getClass().getSimpleName() + " does not have a parent activity name specified." + " (Did you forget to add the android.support.PARENT_ACTIVITY <meta-data> " + " element in your manifest?)"); } navigateUpTo(sourceActivity, upIntent); } 

Creating a parent activity SINGLE_TOP may work for some simple applications, but what if this activity was not started directly from it by the parent? OR you may legitimately want a parent to exist in several places in the background stack.

+4
Dec 19 '14 at 5:09
source share

You mentioned:

In step B, when the Up button is pressed on the action bar, I want to return to activity A and be in the same state as before.

If your content in action A is in the fragment, then call setRetainInstance (true) on the onCreate () of the fragment.

Then the copy of the fragment will be saved during outdoor activities.

-one
Feb 17 '14 at 22:00
source share



All Articles