it-swarm.com.de

Fragmente onResume vom hinteren Stapel

Ich verwende das Kompatibilitätspaket, um Fragmente mit Android 2.2 zu verwenden. Wenn Sie Fragmente verwenden und Übergänge zwischen ihnen zum Backstack hinzufügen, möchte ich dasselbe Verhalten von onResume einer Aktivität erreichen, dh, wenn ein Fragment nach dem Einfügen in den "Vordergrund" (sichtbar für den Benutzer) gebracht wird Aus dem Backstack heraus möchte ich eine Art Callback innerhalb des Fragments aktivieren (z. B. um bestimmte Änderungen an einer gemeinsam genutzten UI-Ressource vorzunehmen).

Ich habe gesehen, dass im Fragment-Framework kein Callback eingebaut ist. Gibt es eine gute Praxis, um dies zu erreichen?

91
oriharel

Aus Mangel an einer besseren Lösung habe ich Folgendes erhalten: Angenommen, ich habe 1 Aktivität (MyActivity) und wenige Fragmente, die sich gegenseitig ersetzen (nur eine ist zu einem Zeitpunkt sichtbar).

Fügen Sie in MyActivity diesen Listener hinzu:

getSupportFragmentManager().addOnBackStackChangedListener(getListener());

(Wie Sie sehen, verwende ich das Kompatibilitätspaket).

getListener Implementierung:

private OnBackStackChangedListener getListener()
    {
        OnBackStackChangedListener result = new OnBackStackChangedListener()
        {
            public void onBackStackChanged() 
            {                   
                FragmentManager manager = getSupportFragmentManager();

                if (manager != null)
                {
                    MyFragment currFrag = (MyFragment) manager.findFragmentById(R.id.fragmentItem);

                    currFrag.onFragmentResume();
                }                   
            }
        };

        return result;
    }

MyFragment.onFragmentResume() wird aufgerufen, nachdem ein "Zurück" gedrückt wurde. Ein paar Einschränkungen:

  1. Es wird davon ausgegangen, dass Sie alle Transaktionen zum Backstack hinzugefügt haben (mithilfe von FragmentTransaction.addToBackStack()).
  2. Es wird bei jedem Stack Change aktiviert (Sie können andere Inhalte im Hintergrundstack speichern, z. B. Animationen), so dass Sie möglicherweise mehrere Aufrufe für die Gleiche Instanz von fragment erhalten.
108
oriharel

Ich habe die vorgeschlagene Lösung etwas geändert. Funktioniert für mich besser so:

private OnBackStackChangedListener getListener() {
    OnBackStackChangedListener result = new OnBackStackChangedListener() {
        public void onBackStackChanged() {
            FragmentManager manager = getSupportFragmentManager();
            if (manager != null) {
                int backStackEntryCount = manager.getBackStackEntryCount();
                if (backStackEntryCount == 0) {
                    finish();
                }
                Fragment fragment = manager.getFragments()
                                           .get(backStackEntryCount - 1);
                fragment.onResume();
            }
        }
    };
    return result;
}
31
Brotoo25

Nach einer popStackBack() können Sie den folgenden Rückruf verwenden: onHiddenChanged(boolean hidden) in Ihrem Fragment

5
user2230304

Der folgende Abschnitt bei Android Developers beschreibt einen Kommunikationsmechanismus Erstellen von Ereignisrückrufen für die Aktivität . Um eine Zeile daraus zu zitieren:

Eine gute Möglichkeit, dies zu tun, besteht darin, eine Rückmeldeschnittstelle innerhalb des Fragments zu definieren und von der Host-Aktivität eine Implementierung zu erfordern. Wenn die Aktivität einen Rückruf über die Schnittstelle erhält, kann sie die Informationen bei Bedarf mit anderen Fragmenten im Layout teilen.

Edit: Das Fragment hat eine onStart(...), die aufgerufen wird, wenn das Fragment für den Benutzer sichtbar ist. Ebenso eine onResume(...), wenn sie sichtbar ist und aktiv ausgeführt wird. Diese sind an ihre Aktivitätspartner gebunden. Kurz gesagt: Verwenden Sie onResume().

3
PJL

Ein wenig verbessert und in eine Managerlösung verpackt.

Dinge, die zu beachten sind. FragmentManager ist kein Singleton, es verwaltet nur Fragmente innerhalb von Activity, also wird es in jeder Aktivität neu sein. Bei dieser Lösung wird ViewPager bisher nicht berücksichtigt, da die Methode setUserVisibleHint () aufgerufen wird, um die Sichtbarkeit von Fragmenten zu steuern.

Fühlen Sie sich frei, die folgenden Klassen zu verwenden, wenn Sie sich mit diesem Problem befassen (verwendet Dagger2-Injektion). Aufruf in Aktivität:

//inject FragmentBackstackStateManager instance to myFragmentBackstackStateManager
FragmentManager fragmentManager = getSupportFragmentManager(); 
myFragmentBackstackStateManager.apply(fragmentManager);

FragmentBackstackStateManager.Java:

@Singleton
public class FragmentBackstackStateManager {

    private FragmentManager fragmentManager;

    @Inject
    public FragmentBackstackStateManager() {
    }

    private BackstackCallback backstackCallbackImpl = new BackstackCallback() {
        @Override
        public void onFragmentPushed(Fragment parentFragment) {
            parentFragment.onPause();
        }

        @Override
        public void onFragmentPopped(Fragment parentFragment) {
            parentFragment.onResume();
        }
    };

    public FragmentBackstackChangeListenerImpl getListener() {
        return new FragmentBackstackChangeListenerImpl(fragmentManager, backstackCallbackImpl);
    }

    public void apply(FragmentManager fragmentManager) {
        this.fragmentManager = fragmentManager;
        fragmentManager.addOnBackStackChangedListener(getListener());
    }
}

FragmentBackstackChangeListenerImpl.Java:

public class FragmentBackstackChangeListenerImpl implements FragmentManager.OnBackStackChangedListener {

    private int lastBackStackEntryCount = 0;
    private final FragmentManager fragmentManager;
    private final BackstackCallback backstackChangeListener;

    public FragmentBackstackChangeListenerImpl(FragmentManager fragmentManager, BackstackCallback backstackChangeListener) {
        this.fragmentManager = fragmentManager;
        this.backstackChangeListener = backstackChangeListener;
        lastBackStackEntryCount = fragmentManager.getBackStackEntryCount();
    }

    private boolean wasPushed(int backStackEntryCount) {
        return lastBackStackEntryCount < backStackEntryCount;
    }

    private boolean wasPopped(int backStackEntryCount) {
        return lastBackStackEntryCount > backStackEntryCount;
    }

    private boolean haveFragments() {
        List<Fragment> fragmentList = fragmentManager.getFragments();
        return fragmentList != null && !fragmentList.isEmpty();
    }


    /**
     * If we Push a fragment to backstack then parent would be the one before => size - 2
     * If we pop a fragment from backstack logically it should be the last fragment in the list, but in Android popping a fragment just makes list entry null keeping list size intact, thus it's also size - 2
     *
     * @return fragment that is parent to the one that is pushed to or popped from back stack
     */
    private Fragment getParentFragment() {
        List<Fragment> fragmentList = fragmentManager.getFragments();
        return fragmentList.get(Math.max(0, fragmentList.size() - 2));
    }

    @Override
    public void onBackStackChanged() {
        int currentBackStackEntryCount = fragmentManager.getBackStackEntryCount();
        if (haveFragments()) {
            Fragment parentFragment = getParentFragment();

            //will be null if was just popped and was last in the stack
            if (parentFragment != null) {
                if (wasPushed(currentBackStackEntryCount)) {
                    backstackChangeListener.onFragmentPushed(parentFragment);
                } else if (wasPopped(currentBackStackEntryCount)) {
                    backstackChangeListener.onFragmentPopped(parentFragment);
                }
            }
        }

        lastBackStackEntryCount = currentBackStackEntryCount;
    }
}

BackstackCallback.Java:

public interface BackstackCallback {
    void onFragmentPushed(Fragment parentFragment);

    void onFragmentPopped(Fragment parentFragment);
}
2
AAverin

Wenn ein Fragment auf einem Backstack abgelegt wird, zerstört Android einfach die Ansicht. Die Fragmentinstanz selbst wird nicht beendet. Eine einfache Möglichkeit, um zu beginnen, sollte das onViewCreated -Ereignis abgehört werden.

boolean fragmentAlreadyLoaded = false;
    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onViewCreated(view, savedInstanceState);

        if (savedInstanceState == null && !fragmentAlreadyLoaded) {
            fragmentAlreadyLoaded = true;

            // Code placed here will be executed once
        }

        //Code placed here will be executed even when the fragment comes from backstack
    }
1
Franjo

In meiner Aktivität onCreate ()

getSupportFragmentManager().addOnBackStackChangedListener(getListener());

Verwenden Sie diese Methode, um ein bestimmtes Fragment abzufangen und onResume () aufzurufen.

private FragmentManager.OnBackStackChangedListener getListener()
    {
        FragmentManager.OnBackStackChangedListener result = new FragmentManager.OnBackStackChangedListener()
        {
            public void onBackStackChanged()
            {
                Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.fragment_container);
                if (currentFragment instanceof YOURFRAGMENT) {
                    currentFragment.onResume();
                }
            }
        };

        return result;
    }
1
Quan Nguyen

Mein Workaround ist, den aktuellen Titel der Aktionsleiste im Fragment abzurufen, bevor Sie den neuen Titel festlegen. Auf diese Weise kann ich nach dem Ablegen des Fragments wieder zu diesem Titel wechseln.

@Override
public void onResume() {
    super.onResume();
    // Get/Backup current title
    mTitle = ((ActionBarActivity) getActivity()).getSupportActionBar()
            .getTitle();
    // Set new title
    ((ActionBarActivity) getActivity()).getSupportActionBar()
        .setTitle(R.string.this_fragment_title);
}

@Override
public void onDestroy() {
    // Set title back
    ((ActionBarActivity) getActivity()).getSupportActionBar()
        .setTitle(mTitle);

    super.onDestroy();
}
0
Mahendran Candy

onResume () für das Fragment funktioniert gut ...

public class listBook extends Fragment {

    private String listbook_last_subtitle;
...

    @Override
       public void onCreate(Bundle savedInstanceState) {

        String thisFragSubtitle = (String) getActivity().getActionBar().getSubtitle();
        listbook_last_subtitle = thisFragSubtitle;
       }
...

    @Override
        public void onResume(){
            super.onResume();
            getActivity().getActionBar().setSubtitle(listbook_last_subtitle);
        }
...
0
Roshan Poudyal

Dies ist die richtige Antwort, die Sie onResume () aufrufen können, sofern das Fragment an die Aktivität angehängt ist. Alternativ können Sie onAttach und onDetach verwenden

0
iamlukeyb
public abstract class RootFragment extends Fragment implements OnBackPressListener {

 @Override
 public boolean onBackPressed() {
  return new BackPressImpl(this).onBackPressed();
 }

 public abstract void OnRefreshUI();

}


public class BackPressImpl implements OnBackPressListener {

 private Fragment parentFragment;

 public BackPressImpl(Fragment parentFragment) {
  this.parentFragment = parentFragment;
 }

 @Override
 public boolean onBackPressed() {
  ((RootFragment) parentFragment).OnRefreshUI();
 }
}

und erweitern Sie Ihr Fragment endgültig vom Wurzelfragment, um den Effekt zu sehen

0
Luu Quoc Thang

Ich habe enum FragmentTags verwendet, um alle meine Fragmentklassen zu definieren.

TAG_FOR_FRAGMENT_A(A.class),
TAG_FOR_FRAGMENT_B(B.class),
TAG_FOR_FRAGMENT_C(C.class)

FragmentTags.TAG_FOR_FRAGMENT_A.name() als Fragment-Tag übergeben.

und jetzt weiter 

@Override
public void onBackPressed(){
   FragmentManager fragmentManager = getFragmentManager();
   Fragment current
   = fragmentManager.findFragmentById(R.id.fragment_container);
    FragmentTags fragmentTag = FragmentTags.valueOf(current.getTag());

  switch(fragmentTag){
    case TAG_FOR_FRAGMENT_A:
        finish();
        break;
   case TAG_FOR_FRAGMENT_B:
        fragmentManager.popBackStack();
        break;
   case default: 
   break;
}
0
Ali