Question about the Up button and the loss of state


#1

The book suggests two solutions for the problem where using the Up button means losing state on the new activity being shown. It says that the first solution (to override the up navigation mechanism and call finish on the current activity) is not ideal in more realistic apps because it would only pop back one activity.

That makes sense, but isn’t that kind of the whole point of the Up button, to go “up” to the previous activity? Seems to me that the first solution would work well almost all of the time. Can someone provide an example of a situation where using this method would NOT work well?


#2

Navigation up and navigating with the back button are not always going to do the same thing. There is some rather lengthy documentation about the differences http://developer.android.com/design/patterns/navigation.html#within-app.

In particular, take a look at the Play Store Books example.


#3

I implemented the second suggestion. However, I don’t know if this is how the author mentoined it?
It makes the code somewhat less modular in Fragment use, as I have to check for intent extra’s in CrimeListFragment

Changes in CrimePagerAcivity:

public class CrimePagerActivity extends AppCompatActivity {

    private boolean mSubtitleVisible;

    public static Intent newIntent(Context packageContext, UUID crimeId, boolean showSubtitle){
        Intent intent = new Intent(packageContext,CrimePagerActivity.class);
        intent.putExtra(CrimeListFragment.EXTRA_SUBTITLE_VISIBLE, showSubtitle);
        intent.putExtra(EXTRA_CRIME_ID,crimeId);
        return intent;
    }

    @Override
    public Intent getParentActivityIntent() {
        Intent intent = new Intent(this,CrimeListActivity.class);
        intent.putExtra(CrimeListFragment.EXTRA_SUBTITLE_VISIBLE,mSubtitleVisible);
        Log.i("CRIMEPAGERACTIVITY","in getParentAcitivty");
        return intent;
    }
}

However, in CrimeListFragment, you need to get this Extra in onCreateView:

mSubtitleVisible = getActivity().getIntent().getBooleanExtra(EXTRA_SUBTITLE_VISIBLE,false);


#4

Yea, overriding getParentActivityIntent is the way to go if you are implementing this the “right” way. Other than that, I don’t recommend having your fragment reach in to the Activity’s intent extras because it limits how you can reuse that fragment in other activities. Instead, you could use fragment arguments (from chapter 10).

Doing this correctly can be a lot of work which explains why many developers will cheat and just have the up button call finish(). In my experience, very few users know how the up button is supposed to differ from the back button. It’s definitely something to think about.


#5

So to keep with the book’s design pattern:

In CrimeListFragment, call CrimePagerActivity.newIntent(Context context, UUID crime_id, boolean showSubtitle) when a crime is clicked
In CrimePagerActivity, call CrimeListActivity.newIntent(Context contect, boolean showSubtitle) in the getParentActivityIntent() to return.
Next, in CrimeListActivity, call CrimeListFragment.newInstance(boolean showSubtitle), thus returning to CrimeListFragment.


#6

Yes. That is the way to go if you’re following the book’s design pattern.


#7

dikkemulle,

I would greatly appreciate you help if you could give a little more detail on how you got the up button to hold the subtitle? I’m a little lost on the CrimeListActivity call to CrimeListFragment.netInstance.

Thank you!


#8

I have solved this problem like this

[code]public class CrimePagerActivity extends AppCompatActivity {

@Nullable
@Override
public Intent getParentActivityIntent() {
    Intent parent = super.getParentActivityIntent();
    parent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    return parent;
}

}[/code]
i have used FLAG_ACTIVITY_CLEAR_TOP because according to docs.

But one thing i don’t understand, according to book up navigation is already using FLAG_ACTIVITY_CLEAR_TOP. So why it creates a new instance of activity if already one activity is running?


#9

But we can’t use getActivity() in CrimePagerActivity like this:

@Override
public Intent getSupportParentActivityIntent() { // getParentActivityIntent

    //Intent intent = super.getSupportParentActivityIntent(); // or new Intent(this,CrimeListActivity.class);
    //intent.putExtra(CrimeListFragment.SAVED_SUBTITLE_VISIBLE, mSubtitleVisible);
    //return intent;

    return CrimeListActivity.newIntent(getActivity(), mSubtitleVisible);
}

#10

I write some codes about the second suggestion with dikkemulle’s idea. Here are the code. Am I right? Or there is anything I can improve?
In CrimePagerAcitvity:

private boolean mSubtitleVisible;

@Nullable
@Override
public Intent getParentActivityIntent() {
	return CrimeListActivity.newIntent(CrimePagerActivity.this, mSubtitleVisible);
}

public static Intent newIntent(Context packageContext, UUID crimeId, boolean showSubtitle) {
	Intent intent = new Intent(packageContext, CrimePagerActivity.class);
	intent.putExtra(EXTRA_CRIME_ID, crimeId);
	intent.putExtra(CrimeListFragment.SAVED_SUBTITLE_VISIBLE, showSubtitle);
	return intent;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
...
mSubtitleVisible = (boolean) getIntent().getBooleanExtra(CrimeListFragment
			.SAVED_SUBTITLE_VISIBLE, false);
}

In CrimeListActivity:

@Override
protected Fragment createFragment() {
	return CrimeListFragment.newInstance(getIntent().getBooleanExtra(CrimeListFragment
			.SAVED_SUBTITLE_VISIBLE, false));
}

public static Intent newIntent(Context packageContext, boolean showSubtitle) {
	Intent intent = new Intent(packageContext, CrimeListActivity.class);
	intent.putExtra(CrimeListFragment.SAVED_SUBTITLE_VISIBLE, showSubtitle);
	return intent;
}

In CrimrListFragment:

public static final String SAVED_SUBTITLE_VISIBLE = "subtitle";
private boolean mSubtitleVisible;

public static CrimeListFragment newInstance(boolean showSubtitle) {
	Bundle args = new Bundle();
	args.putBoolean(CrimeListFragment.SAVED_SUBTITLE_VISIBLE, showSubtitle);

	CrimeListFragment fragment = new CrimeListFragment();
	fragment.setArguments(args);
	return fragment;
}

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);

	mSubtitleVisible = getArguments().getBoolean(SAVED_SUBTITLE_VISIBLE);
	setHasOptionsMenu(true);
}

#11

It works! based on the indications of the book and the ideas of dedikkemulle and AlexZwh. Thanks a lot…


#12

Hey,

I just used android:launchMode=“singleTask” in my parent activity it seems to be working and also android:launchMode=“singleTop” is giving the required results.

Can you please tell me is it a correct method or should i use something different?

Thanks & Regards
Abhishek Ruhela


#13

Following code works good. and very easy.
Up button can be caught by onOptionsItemSelected with android.R.id.home ItemId.

How about this code?

CrimePagerActivity.java

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            onBackPressed();
            return true;

        default:
            return super.onOptionsItemSelected(item);
    }
}

#14

@Nevmind That’s basically what many people do who don’t implement the up button the “correct” way as laid out in the design spec.

I wouldn’t call onBackPressed(). I’d just call finish() on your activity. In the end they will do the same thing however.


#16

I’m just curious if using a Singleton for this is a sensible work-around. Not implementing it right now because it’s not a huge deal, and I’m eager to keep going, but if anyone has any insight why that’s a bad idea, I’d love to hear it.