So behalten Sie RecyclerView position nach Ausrichtung ändern, während mit FB & ChildEventListener?
Arbeite ich an einem einfachen APOD-app implementiert:
RecyclerView
CardView
Firebase
Picasso
Die app packt Bilder und text aus Firebase
und Firebase Storage
, zeigt Sie in einem CardView
, und setzt ein OnClickListener
jedem View
. Wenn der Benutzer klickt auf ein Bild, öffne ich ein neues Activity
durch eine Intent
. Die zweite Activity
zeigt das original-Bild geklickt, und mehr info über es.
Habe ich umgesetzt, diese mit einem GridLayoutManager
1 Spalte, wenn der Benutzer das Telefon SENKRECHT, 3 Spalten, wenn der Benutzer das Telefon HORIZONTAL.
Das problem das ich habe ist ich kann nicht scheinen, um speichern Sie die RecyclerView
's position auf Orientierung ändern. Ich habe versucht, jede einzelne option, die ich finden konnte, aber keiner scheint zu funktionieren. Die einzige Schlussfolgerung, die ich kommen könnte, ist, dass auf rotation, ich Zerstöre Firebase
's ChildEventListener
um Speicherlecks zu vermeiden, und sobald die Ausrichtung abgeschlossen ist, wird Firebase
re-Abfragen der Datenbank, weil die neue Instanz von ChildEventListener
.
Gibt es eine Möglichkeit, ich kann speichern mein RecyclerView
's position auf die Ausrichtung ändern? Ich will nicht android:configChanges
wie es lässt mich nicht ändern, mein layout, und ich habe auch schon versucht das speichern als Parcelable
, die nicht erfolgreich war. Ich bin sicher, es ist etwas einfach, ich bin fehlt, aber hey, ich bin neu zu entwickeln. Jede Hilfe oder Anregungen zu meinem code ist sehr geschätzt. Danke!
Unten sind meine Klassen, die ich verkürzt nur den erforderlichen code.
MainActivity
public class MainActivity extends AppCompatActivity {
private RecyclerAdapter mRecyclerAdapter;
private DatabaseReference mDatabaseReference;
private RecyclerView mRecyclerView;
private Query query;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
setContentView(R.layout.activity_main);
getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
final int columns = getResources().getInteger(R.integer.gallery_columns);
mDatabaseReference = FirebaseDatabase.getInstance().getReference();
query = mDatabaseReference.child("apod").orderByChild("date");
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(new GridLayoutManager(this, columns));
mRecyclerAdapter = new RecyclerAdapter(this, query);
mRecyclerView.setAdapter(mRecyclerAdapter);
}
@Override
public void onDestroy() {
mRecyclerAdapter.cleanupListener();
}
}
RecyclerAdapter
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ApodViewHolder> {
private final Context mContext;
private final ChildEventListener mChildEventListener;
private final Query mDatabaseReference;
private final List<String> apodListIds = new ArrayList<>();
private final List<Apod> apodList = new ArrayList<>();
public RecyclerAdapter(final Context context, Query ref) {
mContext = context;
mDatabaseReference = ref;
ChildEventListener childEventListener = new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
int oldListSize = getItemCount();
Apod apod = dataSnapshot.getValue(Apod.class);
//Add data and IDs to the list
apodListIds.add(dataSnapshot.getKey());
apodList.add(apod);
//Update the RecyclerView
notifyItemInserted(oldListSize - getItemCount() - 1);
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
String apodKey = dataSnapshot.getKey();
int apodIndex = apodListIds.indexOf(apodKey);
if (apodIndex > -1) {
//Remove data and IDs from the list
apodListIds.remove(apodIndex);
apodList.remove(apodIndex);
//Update the RecyclerView
notifyDataSetChanged();
}
}
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
};
ref.addChildEventListener(childEventListener);
mChildEventListener = childEventListener;
}
@Override
public int getItemCount() {
return apodList.size();
}
public void cleanupListener() {
if (mChildEventListener != null) {
mDatabaseReference.removeEventListener(mChildEventListener);
}
}
}
- Ich denke, das problem ist, dass die neue RV nach einer Konfigurationsänderung, die nicht wissen, etwas über seinen Inhalt anzeigen am Ende von onCreate, da diese Daten kommt nur, nachdem alle untergeordneten Zuhörer auslösen. Damit es nicht zu wissen, wie vollständig wiederherzustellen, da es denkt, dass es leer zu dieser Zeit. Ich weiß nicht, eine Lösung ohne weiteres, wollte aber um diese info. Sie können die Abfrage eines RV der scroll-offset, wenn das hilft.
- Vielen Dank, Doug, ich habe versucht, das speichern und wiederherstellen der position, konnte aber nicht zum laufen bekommen. Ich dachte dieser Beitrag würde mehr Aufmerksamkeit bekommen, da bin ich entweder völlig fehlt etwas, oder FB macht es schwer zu realisieren, diese Art der Sache. Ich werde es weiter versuchen und werde zu aktualisieren meinem Beitrag, wenn ich nichts anderes findest.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Während der Drehung-Aktivität zerstört und neu erstellt, wieder einmal, dass bedeutet, dass alle Ihre Objekte zerstört und neu erstellt und auch das layout neu gezeichnet wieder.
Möchten Sie zu stoppen, re-Schaffung von Aktivität, die Sie verwenden können, android:configChanges aber es ist eine schlechte Praxis und auch nicht der richtige Weg.
Einzige, was jetzt bleibt, ist das speichern der position der recyclerview bevor die rotation und erhalten es nach Aktivität neu erstellt.
//speichern recyclerview position
//wiederherstellen-Wert
Hoffe, dass diese Ihnen helfen.
Handler
. Als ich endlich in der Lage, damit es funktioniert, es hatte immer noch eine schreckliche Verzögerung, in denen es erfrischt den ganzen Bildschirm, ich vermute, weilnotifyItemInserted(oldListSize - getItemCount() - 1);
genannt wurde, wieder auf die neueActivity
. Der einzige Weg, um dies zu nutzen, um dieandroid:configChanges
ich weiß, es ist verpönt, aber es sieht eine verdammt viel weniger hässlicher während die änderung der Ausrichtung.RecyclerView.getAdapterPosition()
getAdapterPosition()
EDIT:
War ich endlich in der Lage, diese Arbeit mit mehreren Faktoren. Wenn einer dieser Links wurden, es einfach nicht funktionieren würde.
Erstellen neue
GridLayoutManager
in meiner onCreateSpeichern Sie die RecyclerView Staat in onPause
Gehören
configChanges
imAndroidManifest.xml
Speichern und wiederherstellen der
RecyclerView
Zustand war nicht genug. Ich hatte auch gegen den Strich zu gehen, und ändern Sie meineAndroidManifest.xml
zu " android:configChanges="orientation|screenSize"'Wiederherstellung der
RecyclerView
Staat inonConfigurationChanged
mit einemHandler
Handler war einer der wichtigsten Teile, wenn es nicht enthalten, es wird einfach nicht funktionieren und die position der
RecyclerView
wird auf 0 zurückgesetzt. Ich denke, dies war ein Fehler, gehen wir zurück ein paar Jahre, und wurde nie behoben. Ich änderte dann dieGridLayoutManager
'ssetSpanCount
je nach Ausrichtung.Wie gesagt, alle diese änderungen, die notwendig ist, zumindest für mich. Ich weiß nicht, ob dies der effizienteste Weg ist, aber nach viele Stunden damit zu verbringen, es funktioniert für mich.
Aktivität wird neu erstellt jedes mal, wenn es eine Orientierung ändern. So haben Sie zum speichern der position in dem Bündel und dann wieder verwenden, wenn die onCreate() wird aufgerufen 2. mal.
Haben möchten Sie vielleicht einen Blick auf RecyclerView.State() link weitere Optionen wie die Wiederherstellung des recycler-Ansicht Zustand.
Eigentlich gibt es viel bessere Ansatz zur Wiederherstellung der recycler Ansicht " position, sobald eine Aktivität erstellt, und diese wird durch die Verwendung der recycler-Ansicht-layout-manager die option zum speichern und wiederherstellen der letzten position (die letzten recycler layout der view-Zustand). Werfen Sie einen Blick dieser tutorial.
Mit ein paar Worten, müssen Sie rufen Sie die layout-manager-Methoden onSaveInstanceState() und onRestoreInstanceState(Parcelable-Zustand) innerhalb der entsprechenden Aktivität Methoden. Am Ende haben Sie die Wiederherstellung der layout-manager, Staat, Recht, nachdem Sie besiedelten den adapter mit Daten.
Wenn Sie einen Blick in die Umsetzung von LinearLayoutManager zum Beispiel, Sie werden sehen, wie diese Klasse verwaltet den Staat (speichern /wiederherstellen)