0

I have an activity A, which displays three fragments according to the groupName field. I have a menu button which lauches another activity B. When I click this button and then click the back button, groupName is null in activity A. I have also tried saving and restoring using savedInstanceState, but to no avail. I do not believe this is necessary, because activity A is never destroyed.

I have checked the Android manifest, both activities are properly registered and activity A is parent of activity B.

public class GroupOverviewActivity extends AppCompatActivity implements MyTasksInteractionListener, OnGroupTasksFragmentInteractionListener {

private static final String TAG = "GroupOverviewActivity";

private String groupName;

@Override
protected void onCreate(final Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_group_overview);

    if (savedInstanceState != null) {
        groupName = savedInstanceState.getString("groupname");
    } else if (getIntent() != null && getIntent().getExtras() != null) {
        groupName = getIntent().getExtras().getString("groupname");
    }
}

@Override
protected void onResume() {
    super.onResume();

    setSupportActionBar((Toolbar) findViewById(R.id.toolbar));
    final ActionBar bar = getSupportActionBar();
    if (bar != null) {
        bar.setDisplayHomeAsUpEnabled(true);
        bar.setTitle(groupName);
    }

    getSupportFragmentManager().beginTransaction()
        .add(R.id.group_overview_fragment, GroupMyTasksFragment.newInstance(groupName), null)
        .disallowAddToBackStack()
        .commit();

    final BottomNavigationView bottomNavigationView = findViewById(R.id.bottom_navigation);
    bottomNavigationView.setOnNavigationItemSelectedListener(
        new BottomNavigationView.OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(@NonNull final MenuItem item) {
                item.setChecked(true);
                switch (item.getItemId()) {
                    case R.id.item_activity:
                        getSupportFragmentManager().beginTransaction()
                            .replace(R.id.group_overview_fragment, GroupActivityFragment.newInstance(groupName))
                            .disallowAddToBackStack()
                            .commit();
                        break;
                    case R.id.item_schedule:
                        getSupportFragmentManager().beginTransaction()
                            .replace(R.id.group_overview_fragment, GroupScheduleFragment.newInstance(groupName))
                            .disallowAddToBackStack()
                            .commit();
                        break;
                    case R.id.item_tasks:
                        getSupportFragmentManager().beginTransaction()
                            .replace(R.id.group_overview_fragment, GroupMyTasksFragment.newInstance(groupName))
                            .disallowAddToBackStack()
                            .commit();
                        break;
                }
                return false;
            }
        });
}

@Override
protected void onSaveInstanceState(final Bundle outState) {
    outState.putString("groupname", groupName);

    super.onSaveInstanceState(outState);
}

@Override
public boolean onCreateOptionsMenu(final Menu menu) {
    getMenuInflater().inflate(R.menu.group_overview, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(final MenuItem item) {
    if (item.getItemId() == R.id.item_members) {
        final Intent intent = new Intent(this, GroupMembersActivity.class);

        intent.putExtra(GroupMembersActivity.ARG_PARAM1, groupName);
        startActivity(intent);
    }

    return true;
}

The layout of the activity:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="giphouse.nl.proprapp.ui.group.overview.GroupOverviewActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ProprTheme.AppBarOverlay"
        android:id="@+id/appBarLayout">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/ProprTheme.PopupOverlay" />

    </android.support.design.widget.AppBarLayout>


    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/appBarLayout"
        android:id="@+id/group_overview_fragment">

    </FrameLayout>

    <android.support.design.widget.BottomNavigationView
        android:id="@+id/bottom_navigation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:itemBackground="@color/colorPrimary"
        app:itemIconTint="@drawable/nav_item_color_state"
        app:itemTextColor="@drawable/nav_item_color_state"
        android:layout_alignParentBottom="true"
        app:menu="@menu/bottom_navigation_group_overview">

    </android.support.design.widget.BottomNavigationView>

</RelativeLayout>

The way the GroupOverviewActivity is started:

    final Intent intent = new Intent(context, GroupOverviewActivity.class);
    intent.putExtra("groupname", dto.getGroupName());

    itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(final View v) {
            context.startActivity(intent);
        }
    });

The relevant logging. Each statement is appended by the value of goupname:

11-20 08:32:16.181 4906-4906/giphouse.nl.proprapp E/GroupOverviewActivity: onCreate DEVTEAM
11-20 08:32:16.185 4906-4906/giphouse.nl.proprapp E/GroupOverviewActivity: onStart DEVTEAM
11-20 08:32:16.222 4906-4906/giphouse.nl.proprapp E/GroupOverviewActivity: onResume DEVTEAM

When the menu item is clicked launching activity B:

11-20 08:32:22.766 4906-4906/giphouse.nl.proprapp E/GroupOverviewActivity: Saving instance state DEVTEAM
11-20 08:32:22.038 4906-4906/giphouse.nl.proprapp E/GroupOverviewActivity: onPause DEVTEAM

After activity B is launched and visible:

11-20 08:32:22.769 4906-4906/giphouse.nl.proprapp E/GroupOverviewActivity: onStop DEVTEAM
11-20 08:32:27.122 4906-4906/giphouse.nl.proprapp E/GroupOverviewActivity: onDestroy DEVTEAM

After hitting back button:

11-20 08:32:27.299 4906-4906/giphouse.nl.proprapp E/GroupOverviewActivity: onCreate null
11-20 08:32:27.300 4906-4906/giphouse.nl.proprapp E/GroupOverviewActivity: onStart null
11-20 08:32:27.315 4906-4906/giphouse.nl.proprapp E/GroupOverviewActivity: onResume null

Note that onRestoreInstanceState is not called. In onCreate, the savedInstanceState is null.

For completeness, the relevant parts of the associated AndroidManifest:

    <activity
        android:name=".ui.group.overview.GroupOverviewActivity"
        android:label="@string/title_activity_group_tabbed"
        android:parentActivityName=".ui.group.GroupListActivity">
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value="giphouse.nl.proprapp.ui.group.GroupListActivity" />
    </activity>

    <activity android:name=".ui.group.GroupMembersActivity"
        android:label="@string/item_title_members"
        android:parentActivityName=".ui.group.overview.GroupOverviewActivity">
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value="giphouse.nl.proprapp.ui.group.overview.GroupOverviewActivity" />
    </activity>

SOLUTION

The solution (found by following kind pointers from realharry) was to manuallt override the onOptionsItemSelected, because the default implementation apparantly creates a new activity. (I found it here Up Button Calls OnDestroy of Parent Activity).

Hayeb
  • 3
  • 3

1 Answers1

2

Is it possible that your groupname variable is never set and hence it's null to begin with? Maybe, you are missing the logic to set this variable in a button click handler?

EDIT: Based on the comment/updated code sample, that seems unlikely. Your code looks fine. I don't see anything obvious that could have been causing this problem.

I have a few suggestions, though.

(1) Try overriding onRestoreInstanceState(), and set groupName there. See if that makes any difference.

(2) If that doesn't work, you can try storing/retrieving groupName in a singleton class (whose lifetime is longer than that of each activity). Clearly, this is a hack, but you can try this and see what happens. Regardless of whether it works (it should) or not (which will be even more bizarre), you will gain some insight, which will suggest how to proceed next.

(3) Obviously, the best thing to do is to run your app in the debugger, and see what happens to groupName as you go through various UI actions.

(4) If that's not feasible, again at the risk of stating the obvious, just print out/log groupName at various points in your program (e.g., before you call bar.setTitle(), etc.). You may have to override a few more activity lifecycle methods just for the purpose of adding logging (e.g., onPause(), onStart(), etc.). This way, you can narrow down where exactly groupName is reset to null, if ever.

realharry
  • 1,555
  • 8
  • 12
  • It is set, in the onCreateView function it is retrieved feom the intent used to create the activity. When the activity is started for the first time, I can see that groupname has the correct value. – Hayeb Nov 19 '17 at 09:08
  • Your example as posted above does not show that. In which activity is that being done? If you post the relevant code, we'll have a better idea of what's going on. Also, post `activity_group_overview`, or any other layout where the groupname is displayed. – realharry Nov 19 '17 at 09:37
  • I have added additonal code snippets to show how this is done. – Hayeb Nov 19 '17 at 12:36
  • Added a few suggestions to the answer (because of the character limit in comment). – realharry Nov 19 '17 at 18:19
  • I have tried 1, 3, and 4 of your suggestions. I have attached some more information in the question, alas no significant progress. – Hayeb Nov 20 '17 at 07:46
  • _In onCreate, the savedInstanceState is null._ Yes. you nailed it. I now remember I had the same problem some time ago. "Back" is very weird. (1) At first launch, you passed in the groupname param from another activity via intent's Extra param. When you do "back", however, that param does not exist. (2) When you do "back", savedInstanceState is not used either. So, your code, as is, will not work. (In fact, this will be a generic problem for everybody.) Unfortunately, I cannot remember how I resolved issues like this right now. Let me try and remember. Regardless, this is a big progress. – realharry Nov 20 '17 at 08:00
  • Just to clarify, when I say it's a "big progress", your code GroupOverviewActivity::onCreate() has `if() ... else if()" blocks, and neither one works. And, _they are not supposed to work_ when you do "back". It's not because you are doing something wrong, it's just the way it is. Based on this understanding, we can now explore other "solutions". – realharry Nov 20 '17 at 08:08
  • @Hayeb Can you show us the relevant part of your manifest file? – realharry Nov 20 '17 at 08:10
  • I have edited the original question. After some searching, I found a solution! (https://stackoverflow.com/questions/37222278/up-button-calls-ondestroy-of-parent-activity). It needed to override onOptionsItemSelected and manually handle clicking of the back button. – Hayeb Nov 20 '17 at 16:51