2

I have an app project where there is 10 Fragments. When user open a Fragment I want to in code know this and save the Fragment as the last Fragment user has visited.

If user close app and open it again this last visited Fragment will be showed to user.

I read many answers about this and there does not seam to be a consensus on a solution to know what Fragment is currently visible for User.

I was thinking to subclass FragmentManager maybe to detect popping and monitor queue state.

Or maybe put some GestureDetector.OnGestureListener in the Fragment and when that fires I can save the last Fragment user has visited.

Any help on this would be grate

This is what happen when user in the Fragment press back press button

  /**
     * user press back button
     */
    @Override
    public void onBackPressed() {
        //Fragment fragment = getVisibleFragment();

        //get the name from the topmost BackStackEntry which is also the fragment tag.
        String fragmentTag = mFragManager.getBackStackEntryAt(mFragManager.getBackStackEntryCount()-1).getName();

        Fragment currentFrag = mFragManager.findFragmentByTag(fragmentTag);
        if (currentFrag == null ) {
            super.onBackPressed();
        }

        if (currentFrag != null) {
            if (currentFrag.getTag().equals(SettingsManager.FragmentsModel.CHAT_FRAGMENT.toString())) {
                if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
                    openDrawer(false);
                } else
                    requestBeginTransaction(SettingsManager.FragmentsModel.LAUNCHER_FRAGMENT.toString(), true, false);
            } else if (currentFrag.getTag().equals(SettingsManager.FragmentsModel.BILLBOARD_FRAGMENT.toString())) {

            } else if (currentFrag.getTag().equals(SettingsManager.FragmentsModel.NEWS_FRAGMENT.toString())) {

            } else if (currentFrag.getTag().equals(SettingsManager.FragmentsModel.INFO_FRAGMENT.toString())) {
                super.onBackPressed();
            } else if (currentFrag.getTag().equals(SettingsManager.FragmentsModel.SEARCH_FRAGMENT.toString())) {
                // exit app if the search address view is visible
                if (currentFrag.getView().findViewById(R.id.search_address_layout).getVisibility() == View.VISIBLE) {
                    exitApp();
                } else if (currentFrag.getView().findViewById(R.id.show_search_result_layout).getVisibility() == View.VISIBLE) {
                    // show search address view if Address already exist view is visible
                    currentFrag.getView().findViewById(R.id.search_address_layout).setVisibility(View.VISIBLE);
                    currentFrag.getView().findViewById(R.id.history).setVisibility(View.VISIBLE);
                    currentFrag.getView().findViewById(R.id.show_search_result_layout).setVisibility(View.INVISIBLE);
                    ((SearchFragment)currentFrag).onSearchLayoutVisible();
                }
            } else if (currentFrag.getTag().equals(SettingsManager.FragmentsModel.PREFERENCE_FRAGMENT.toString())) {
                super.onBackPressed();
                //requestBeginTransaction(SettingsManager.FragmentsModel.LAUNCHER_FRAGMENT.toString(), true, false);
            } else if (currentFrag.getTag().equals(SettingsManager.FragmentsModel.PREFERENCE_FRAGMENT_CHAT_SETTINGS.toString())) {
                super.onBackPressed();
                //requestBeginTransaction(SettingsManager.FragmentsModel.LAUNCHER_FRAGMENT.toString(), true, false);
            } else if (currentFrag.getTag().equals(SettingsManager.FragmentsModel.PREFERENCE_FRAGMENT_THEME_SETTINGS.toString())) {
                super.onBackPressed();
                //requestBeginTransaction(SettingsManager.FragmentsModel.LAUNCHER_FRAGMENT.toString(), true, false);
            } else if (currentFrag.getTag().equals(SettingsManager.FragmentsModel.LAUNCHER_FRAGMENT.toString())) {
                super.onBackPressed();
                //requestBeginTransaction(SettingsManager.FragmentsModel.LAUNCHER_FRAGMENT.toString(), true, false);
            }
        } else
            exitApp();
    }

In the code above i pop Fragment and dont know what Fragment is under the popt Fragment.

Here is when I add or show Fragment

   /**
     * Change the current displayed fragment by a new one.
     * - if the fragment is in backstack, it will pop it
     * - if the fragment is already displayed (trying to change the fragment with the same), it will not do anything
     *
     * @param backStateName             the new fragment to display
     * @param saveInBackstack if we want the fragment to be in backstack
     * @param animate         if we want a nice animation or not
     */
    public void requestBeginTransaction(String backStateName, boolean saveInBackstack, boolean animate) {
        Fragment frag = null;
        if (mFragManager.findFragmentByTag(backStateName) != null) {
            frag = mFragManager.findFragmentByTag(backStateName);
        } else
            try {
                frag = (Fragment) Class.forName(backStateName).newInstance();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        try {
            FragmentManager manager = getSupportFragmentManager();
            boolean fragmentPopped = manager.popBackStackImmediate(backStateName, 0);

            if (!fragmentPopped && manager.findFragmentByTag(backStateName) == null) {
                //fragment not in back stack, create it.
                FragmentTransaction transaction = manager.beginTransaction();

                if (animate) {
                    LogManager.d(this, "Change Fragment: animate");
                    // transaction.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left, R.anim.slide_in_left, R.anim.slide_out_right);
                }

                transaction.add(R.id.frame, frag, backStateName);

                if (saveInBackstack) {
                    LogManager.d(this, "Change Fragment: addToBackTack " + backStateName);
                    transaction.addToBackStack(backStateName);
                    LogManager.d(this, "Change Fragment: NO addToBackTack");
                }

                transaction.commit();
            } else {
                mFragManager.beginTransaction().show(mFragManager.findFragmentByTag(backStateName)).commit();

                // custom effect if fragment is already instanciated
            }
        } catch (IllegalStateException exception) {
            LogManager.w(this, "Unable to commit fragment, could be activity as been killed in background. " + exception.toString());
        }
    }
Tord Larsen
  • 2,670
  • 8
  • 33
  • 76

2 Answers2

1

You can test it by looking at its instance.

Fragment fragment = getFragmentManager().findFragmentById(R.id.fragment_container);
if (fragment instanceOf Fragment1) {
 // It is fragment of class Fragment1
} else if (fragment instanceOf Fragment2) {
 // It is fragment of class Fragment2
}

When the user presses back button, have this in your activity (not fragment):

@Override
public void onBackPressed() {

    super.onBackPressed();

    Fragment fragment = getFragmentManager().findFragmentById(R.id.fragment_container);
    if (fragment instanceOf Fragment1) {
     // It is fragment of class Fragment1
    } else if (fragment instanceOf Fragment2) {
     // It is fragment of class Fragment2
    }

   // Save to prefs which fragment tag it is
}
zed
  • 3,180
  • 3
  • 27
  • 38
  • Do you mean I should call this inside the Fragment? naa When should I run this code? – Tord Larsen Feb 20 '17 at 19:52
  • Updated. You can just do this to check which fragment it is. – zed Feb 20 '17 at 19:57
  • Otherwise, you might want to do this: http://stackoverflow.com/questions/9294603/get-currently-displayed-fragment – zed Feb 20 '17 at 19:57
  • Interesting, @zed Do you mean I should create some daemon Thread periodically do this check? – Tord Larsen Feb 20 '17 at 20:00
  • I see that you have added code to your question. You should tag your fragments and whenever a fragment is changed, take the new fragment's tag and save it in the preferences. On application start, loop over all the tags you have, and according to the tag, create a new fragment of that type, and show it to the user. – zed Feb 20 '17 at 20:10
  • Yes exactly that was my thought also. The problem comes in the `AppCompatActivity` `public void onBackPressed() ` when user press backpress button and `super.onBackPressed();` is called popping frag. Now I dont know what to save in `preferences` – Tord Larsen Feb 20 '17 at 20:14
  • 1
    Updated answer. – zed Feb 20 '17 at 20:21
  • Thanks, I feel that your updated answer will give me the second last Fragment, because after that code is executed another Fragment is showed in the `onBackPressed()` and I dont know the name of that Fragment, that now is visible, because of `super.onBackPressed();` Maybe I´m wrong I hope..mmm – Tord Larsen Feb 20 '17 at 20:28
  • 1
    Yes you do require the second last fragment, because your last fragment will be replaced by the second last fragment. Hence the last second fragment is the one that should be displayed when the user launches the application again. Right? – zed Feb 20 '17 at 20:31
  • ok I see it now in your code update you do `super.onBackPressed();` **before** `getFragmentManager().findFragmentById(R.id.fragment_container);` . Yea that would give me the current frag right assuming `super.onBackPressed();` is synchronous all the way ..Great will run some tests..Thanks – Tord Larsen Feb 20 '17 at 21:01
  • It´s working and to clarify you can add this to you question and I will accept it. I hade to wrap the call to `.findFragmentById(R.id.fragment_container);` inside `runOnUiThread` to queue it up, because `transaction.commit();` is working like this from the docs: "call is Schedules a commit of this transaction. The commit does not happen immediately; it will be scheduled as work on the main thread to be done the next time that thread is ready. Thanks for your help – Tord Larsen Feb 21 '17 at 11:25
0

If you only need to know the last visible fragment to restore it if the user closes the app, I would suggest to simply store the fragment's tag (or some identifier) in the SharedPreferences when it's started. Then, you can use that preference value later to set the correct fragment when the application starts. You can do that by overriding the onStart() fragment method.

Juan Martinez
  • 770
  • 5
  • 16
  • That will work only if I do `transaction.replace`when adding frags, I don't I use `transaction.add` because I dont want Fragments to reboot loosing state – Tord Larsen Feb 20 '17 at 20:03