2017-02-08 3 views
0

Ich habe erstellen Sie einfach eine Demo die ersetzen Methode von FragmentTransaction zu verstehen, und ich bin nicht Ergebnis nach Developer Guide bekommen.Seltsames Verhalten von fragmentTransaction.replace() -Methode

Aktivität und Fragment

public class MainActivity extends AppCompatActivity { 

    private int count; 
    private Fragment prevFragment; 


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

     final Button button = (Button) findViewById(R.id.activity_main_bv_add); 


     button.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View view) { 
       count++; 

       final FragmentTransaction transaction = getFragmentManager().beginTransaction(); 
       final TestFragment fragment = new TestFragment(count); 

       if (count == 1) { 
        transaction.add(R.id.activity_main_rl_container, fragment, fragment.getClass().getSimpleName()); 

       } else if (count == 5) { 
        transaction.replace(R.id.activity_main_rl_container, fragment, fragment.getClass().getSimpleName()); 
        transaction.addToBackStack(null); 
        if (prevFragment != null) { 
         transaction.hide(prevFragment); 
        } 
       } else { 
        transaction.add(R.id.activity_main_rl_container, fragment, fragment.getClass().getSimpleName()); 
        transaction.addToBackStack(null); 
        if (prevFragment != null) { 
         transaction.hide(prevFragment); 
        } 
       } 
       prevFragment = fragment; 

       transaction.commit(); 


      } 
     }); 
    } 

    public class TestFragment extends Fragment { 
     private final String TAG = this.getClass().getSimpleName(); 
     private int number; 


     public TestFragment(final int number) { 
      this.number = number; 
     } 

     public TestFragment() { 
     } 

     @Nullable 
     @Override 
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
      Log.e(TAG, "onCreateView : " + number); 

      final View view = inflater.inflate(R.layout.row_button, null); 

      final Button button = (Button) view.findViewById(R.id.button); 
      button.setText("" + number); 

      return view; 
     } 

     @Override 
     public void onDestroyView() { 
      super.onDestroyView(); 
      Log.e(TAG, "onDestroyView : " + number); 
     } 
    } 
} 

Fragment xml

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
       android:layout_width="match_parent" 
       android:layout_height="match_parent" 
       android:background="@color/colorPrimary" 
       android:orientation="vertical"> 

    <Button 
     android:id="@+id/button" 
     android:layout_width="match_parent" 
     android:layout_height="40dp" 
     android:focusable="false" 
     android:focusableInTouchMode="false" 
     /> 

</LinearLayout> 

Aktivität xml

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout android:id="@+id/activity_currency_select" 
       xmlns:android="http://schemas.android.com/apk/res/android" 
       android:layout_width="match_parent" 
       android:layout_height="match_parent" 
       android:descendantFocusability="blocksDescendants" 
    > 

    <Button 
     android:id="@+id/activity_main_bv_add" 
     android:layout_width="match_parent" 
     android:layout_height="40dp" 
     android:text="Add More"/> 

    <RelativeLayout 
     android:id="@+id/activity_main_rl_container" 
     android:layout_width="match_parent" 
     android:layout_height="300dp" 
     android:layout_below="@id/activity_main_bv_add" 
     android:layout_marginTop="20dp" 
     android:background="@color/colorAccent"></RelativeLayout> 


</RelativeLayout> 

FragmentTransaction ersetzen Methode: Per Android Dokument, ein vorhandenes Fragment ersetzen, die in einen Behälter gegeben wurde. Dies ist im Wesentlichen dasselbe wie das Aufrufen von remove (Fragment) für alle aktuell hinzugefügten Fragmente, die mit der gleichen containerViewId hinzugefügt wurden, und dann das Hinzufügen (int, Fragment, String) mit denselben Argumenten, die hier angegeben sind.

Angenommen Fall 1: Die Methode replace entfernt das aktuelle (letzte und letzte) Fragment und fügt ein neues in der Containeransicht hinzu.

Angenommen Fall 2: Die Methode replace entfernt die Fragmente, die in derselben Containeransicht hinzugefügt wurden.

Aber nach oben Code nicht von dem oben genannten Fall scheint recht.

Lassen Sie uns Klick auf den Button per angezeigten Code ein. Auf jeden Knopf klicken bis Count == 4, neues Objekt von Fragment wird dem Container hinzugefügt.

Wenn wir auf die Schaltfläche klicken, wird für die Zählung == 5, hier Replacemethode zu diesem Zeitpunkt neues Objekt Fragment verwendet wird, wird in den Behälter und onDestroyView Verfahren ist für die 1. und 3. hinzugefügt Fragmente

genannt hinzugefügt werden Frage 1: Wenn replace alle Fragmente entfernt, die in demselben Container hinzugefügt wurden, warum wird onDestroyView nicht für das zweite und vierte hinzugefügte Fragment aufgerufen?

Frage 2: Wenn Ersetzungsmethode das zuletzt hinzugefügte Fragment im selben Container entfernt, warum zerstört es dann nicht das 4. Fragment, sondern das 1. und 3.?

Gemäß meinem Verständnis ist das Verhalten, das Dokument auf Developer site zeigt nicht folgen Dosis.

Korrigieren Sie mich, wenn ich falsch liege.

+0

Anteil der Komplettes Demo-Projekt auf GitHub. –

Antwort

2

Es scheint, einen Fehler von replace Verfahren durch die Arraylist Liste Looping. Beachten Sie, dass dies nicht mit der Support-Version des FragmentManager geschieht.

werde ich this und this beziehen.

Die erste ist als Veraltet markiert und der zweite als Assigned, aber beide scheinen sehr verwandt zu sein.

In beide markiert ist, dass die Entfernung der Fragmente (aus einer Arraylist) innerhalb einer for Schleife durchgeführt wird, und dann Arraylist von Fragmenten innerhalb dieser for Schleife seine Größe zu ändern, verursacht dies einige Indizes übersprungen, und dann die Entfernung von einigen (nicht allen) Fragmenten.

Hier ist die for-Schleife in den Links verwiesen:

for (int i = 0; i < mManager.mAdded.size(); i++) { 
    Fragment old = mManager.mAdded.get(i); 
    // ... 
    if (f == null || old.mContainerId == f.mContainerId) { 
     if (old == f) { 
      op.fragment = f = null; 
     } else { 
      if (op.removed == null) { 
       op.removed = new ArrayList<Fragment>(); 
      } 
      op.removed.add(old); 
      old.mNextAnim = op.exitAnim; 
      if (mAddToBackStack) { 
       old.mBackStackNesting += 1; 
       if (FragmentManagerImpl.DEBUG) { 
        Log.v(TAG, "Bump nesting of " 
          + old + " to " + old.mBackStackNesting); 
       } 
      } 
      mManager.removeFragment(old, mTransition, mTransitionStyle); 
     } 
    } 
} 

In Ihrem speziellen Fall, den Sie hinzufügen Fragmente 1,2,3,4. Nachdem Sie alle diese vier Fragmente durch das fünfte ersetzt haben, wird die obige for-Schleife ausgeführt. Sie entfernen also die erste (entsprechend i = 0 in der for-Schleife), und die Arraylist der Fragmente wird 2,3,4. Dann wählst du den nächsten Index in der for-Schleife (i = 1), aber in der Zwischenzeit hat sich die Arraylist geändert, also nimm das Fragment 3 (entsprechend i = 1) und entferne es. Schließlich wird diese Arraylist 2,4 und i = 2, und kein Fragment entspricht dem Index 2.

Ich hoffe, ich habe Ihnen geholfen zu verstehen, auch wenn ich nicht die 50 Punkte nehmen :)

0
for (int i=0; i<mManager.mAdded.size(); i++) {  
    Fragment old = mManager.mAdded.get(i); 
    if (f ==null ||old.mContainerId == f.mContainerId) { 
     mManager.removeFragment(old,mTransition, mTransitionStyle); 
    } 
} 

MManager.mAdded ist eine ArrayList-Liste, wenn sie beim Traversieren des mManagers aufgerufen wird.removeFragment-Methode, und die Methode ruft die ArrayList remove-Methode auf;

Public void removeFragment (Fragmentfragment, int transition, inttransitionStyle) { 
    MAdded.remove (fragment);  
} 

Dies bedeutet, dass Entfernen verwendet wird, wenn es mit einer for-Schleife