2016-06-02 10 views
1

Meine App besteht aus 1 Fragment. Dieses Fragment enthält eine Recyclerview mit einer großen Anzahl von Einträgen.Android: seltsame Probleme in meiner App mit 1 Fragment nach der Drehung des Geräts

Das Symptom war, dass es nach der Drehung des Geräts nicht möglich war, die Recycleransicht zur gespeicherten Position zu scrollen. Was auch immer ich tat, kein Scrollen war das Ergebnis. Also, seltsame Dinge sind in der Benutzeroberfläche passiert.

EDIT (die Ursache enthüllt) ...

In meiner Tätigkeit ich diesen Code hatte ...

if (findViewById(R.id.fragment_container) != null) { 
    FragmentCategoryChecklist f2 = new FragmentCategoryChecklist(); 
    Bundle b = new Bundle(); 
    b.putString("contents", "Category Fragment"); 
    f2.setArguments(b);   
    getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, f2).commit(); 
} 

Das ist falsch! Siehe den folgenden Code. Wenn das Gerät mit diesem Code gedreht wird, wird jedes Mal ein neues Fragment erstellt. Das ist falsch, weil Android ALREADY das (gespeicherte) Fragment neu erstellt.

Das Ergebnis ist, dass ein Fragment mit Instanzdaten durch den Code erstellt, dann sofort zerstört und dann ohne Instanzdaten neu erstellt wird. Keine gespeicherten Instanzdaten bedeuten, dass nicht zu einer zuvor gespeicherten Position gescrollt wird.

Der korrekte Code wird unten angezeigt. Entschuldigung, meine Frage war nur ein Symptom und nicht die Ursache.

Fragment f = getSupportFragmentManager().findFragmentById(R.id.fragment_container); 
if(f == null) { 
    if (findViewById(R.id.fragment_container) != null) { 
     FragmentCategoryChecklist f2 = new FragmentCategoryChecklist(); 
     Bundle b = new Bundle(); 
     b.putString("contents", "Category Fragment"); 
     f2.setArguments(b); 
     getSupportFragmentManager(). 
      beginTransaction(). 
      replace(R.id.fragment_container, f2). 
      commit(); 
    } 
} 
+0

Ich glaube, Sie können versuchen, eine Benutzeroberfläche mit Handler dafür. Veröffentlichen Sie ein "Runnable" in der UI-Nachrichtenwarteschlange und versuchen Sie dort "findLastCompletelyVisibleItemPosition" zu finden. Dies garantiert, dass dieses Runnable nach Lebenszyklus-Callbacks ausgeführt wird. Wenn das nicht funktioniert, poste hier einen Code, weil es schwierig ist, ein Problem zu finden. –

+0

Können Sie Ihre Antwort näher ausführen? – tjm1706

+0

Ich habe dies nicht als Antwort geschrieben, weil ich nicht 100% sicher bin, dass es funktioniert, also habe ich Sie gebeten, es zu versuchen. Funktioniert die @ bpr10-Lösung? –

Antwort

0

Die Ursache des Problems wird nach dem EDIT-Teil der Frage angezeigt.

Die Lösung korrekt Ausgangsfragmente nach einer Gerätedrehung:

Fragment f = getSupportFragmentManager().findFragmentById(R.id.fragment_container); 
if(f == null) { 
    if (findViewById(R.id.fragment_container) != null) { 
     FragmentCategoryChecklist f2 = new FragmentCategoryChecklist(); 
     Bundle b = new Bundle(); 
     b.putString("contents", "Category Fragment"); 
     f2.setArguments(b); getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, f2).commit(); 
    } 
} 

dies ein neues Fragment nach Gerätedrehung schaffen wird nur, wenn es nicht vorhanden ist.

Und die oririginal Frage?

Ist sehr einfach gelöst, nur durch Hinzufügen eines ...

((LinearLayoutManager) recyclerview.getLayoutManager()).scrollToPositionWithOffset(jumpToCurrentSelection, 20); 
1

Dies ist eine Art von hackish Art und Weise, darüber zu gehen, aber Sie können einen Thread einrichten regelmäßig Ihre RecyclerView

final LinearLayoutManager manager = (LinearLayoutManager) recyclerview.getLayoutManager(); 
new Thread(){ 
    @Override 
    public void run(){ 
     try { 
      while(true){ 
       Thread.sleep(543); 
       if(manager.findLastCompletelyVisibleItemPosition() != -1){ 
        //Return to the UI thread and continue your work 
        //Try runOnUiThread(Runnable) 
        break; 
       } 
      } 
     } catch (Exception ex) { 
      //Handle thread interruption, etc 
     } 
    } 
}.start(); 

Es gibt bessere Möglichkeiten darüber, dass Don‘zu gehen, sicher zu überprüfen t involvieren Threading. Es kann helfen, eine endliche Anzahl von Versuchen zu setzen, so dass du keinen streunenden Faden hast, der für immer läuft.

+0

Hinzugefügt 1 für Ihre Antwort. – tjm1706

1

Ich glaube, Sie können einen Rückruf des Layout-Renderings von der ersten und lastVisibleItem-Position erhalten. Diese answer erklärt dies in der besten Weise. hoffe das hilft.

private boolean canScroll = false; 
final LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false) { 
      @Override 
      public void onLayoutChildren(final Recycler recycler, final State state) { 
       super.onLayoutChildren(recycler, state); 
       final int firstVisibleItemPosition = findFirstVisibleItemPosition(); 
       if (firstVisibleItemPosition != 0) { 
        // this avoids trying to handle un-needed calls 
        if (firstVisibleItemPosition == -1) 
         //not initialized, or no items shown.Can't 
         canScroll = false; 
         return; 
       } 
       final int lastVisibleItemPosition = findLastVisibleItemPosition(); 
       canScroll = (lastVisibleItemPosition - firstVisibleItemPosition) > 0 
      } 
     }; 

Dann können Sie die canScroll Variable verwenden, um entscheiden, ob er blättern oder nicht.

+0

Leider funktioniert das nicht. Es erwähnt nur (Toast-Nachricht), dass die lastVisibleItemPosition wie 9 ist. Ich kann immer noch nicht zu einer Position blättern. Bei einem canScroll == true ist der folgende Scroll nicht wirksam. ((LinearLayoutManager) recyclerview.getLayoutManager()). ScrollToPositionWithOffset (jumpToCurrentSelection, 20); – tjm1706

+0

Hinzugefügt 1 für Ihre Antwort. – tjm1706

0

Auf dem Fragment fügen Sie diese:

@Override 
protected Parcelable onSaveInstanceState() { 
    Bundle bundle = new Bundle(); 
    bundle.putParcelable(SAVED_LAYOUT_MANAGER, recyclerView.getLayoutManager().onSaveInstanceState()); 
    return bundle; 
} 

und

@Override 
protected void onRestoreInstanceState(Parcelable state) { 
    if (state instanceof Bundle) { 
     layoutManagerSavedState = ((Bundle) state).getParcelable(SAVED_LAYOUT_MANAGER); 
    } 
    super.onRestoreInstanceState(state); 
} 

und Wiederherstellung Ihrer Recycler View-Daten mit:

public void setItems(List objects) { 
    adapter.setItems(objects); 
    restoreLayoutManagerPosition(); 
} 
private void restoreLayoutManagerPosition() { 
    if (layoutManagerSavedState != null) { 
     recyclerView.getLayoutManager().onRestoreInstanceState(layoutManagerSavedState); 
    } 
} 
Verwandte Themen