Was ist der Lebenszyklus für den RecyclerView-Adapter?
Lesezeit: 4 Minuten
Ich fordere Bilder vom Presenter im Adapter an:
@Override
public void onBindViewHolder(SiteAdapter.ViewHolder holder, int position)
{
Site site = sites.get(position);
holder.siteName.setText(site.getName());
requestHolderLogo(holder, site.getLinks().getLogoUrl());
}
private void requestHolderLogo(final ViewHolder holder, final String logoUrl)
{
compositeSubscription.add(
presenter.bitmap(logoUrl)
.subscribe(
bitmap -> {
holder.siteLogo.setImageBitmap(bitmap);
holder.siteLogo.setVisibility(View.VISIBLE);
},
error -> {
holder.siteName.setVisibility(View.VISIBLE);
})
);
}
Wann sollte ich mich abmelden? ViewHolder wird wiederverwendet. Es ist leicht.
Aber wie stoppen Sie alle Abonnements, wenn die Ansicht zerstört ist? Ich sollte wahrscheinlich auch die Presenter-Referenz annullieren, um Speicherverluste zu vermeiden
Bitte erklären Sie, warum Sie herabstimmen
– Eugen Martynow
7. Juni 2016 um 9:16 Uhr
Überprüfen Sie meine Antwort hier stackoverflow.com/a/68351804/6039240
– Amr
12. Juli 2021 um 17:43 Uhr
Bartek Lipinski
Ich denke, der beste Weg, dies zu tun, wäre:
Halte ein subscription Referenz in der SiteAdapter.ViewHolder
unsubscribe das subscription Objekt hinein onBindViewHolder (Es heißt, wenn die ViewHolder wird wiederverwendet)
Behalte das CompositeSubscription Objekt in Ihrem adapter
Verwenden Sie die onDetachedFromRecyclerView Methode von dir Adapter zu unsubscribe das compositeSubscription
So:
public class SiteAdapter extends RecyclerView.Adapter<SiteAdapter.ViewHolder> {
private CompositeSubscription compositeSubscription = new CompositeSubscription();
// other needed SiteAdapter methods
@Override
public void onBindViewHolder(SiteAdapter.ViewHolder holder, int position) {
if (holder.subscription != null && !holder.subscription.isUnsubscribed()) {
compositeSubscription.remove(holder.subscription);
// this will unsubscribe the subscription as well
}
Site site = sites.get(position);
holder.siteName.setText(site.getName());
requestHolderLogo(holder, site.getLinks().getLogoUrl());
}
private void requestHolderLogo(final SiteAdapter.ViewHolder holder, final String logoUrl) {
holder.subscription = presenter.bitmap(logoUrl)
.subscribe(
bitmap -> {
holder.siteLogo.setImageBitmap(bitmap);
holder.siteLogo.setVisibility(View.VISIBLE);
},
error -> {
holder.siteName.setVisibility(View.VISIBLE);
});
compositeSubscription.add(holder.subscription);
}
@Override
public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
compositeSubscription.unsubscribe();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public Subscription subscription;
// some holder-related stuff
public ViewHolder(View itemView) {
super(itemView);
// init holder
}
}
}
Cool, also gibt es keine Methode auf dem Adapter, die wann aufgerufen wird RecyclerView ist losgelöst von der Aktivität
– Eugen Martynow
7. Juni 2016 um 9:25 Uhr
Nun… eigentlich gibt es einen – onDetachedFromRecyclerView und es könnte leicht was machen recycle() derzeit tut. Gute Idee 🙂
– Bartek Lipinski
7. Juni 2016 um 9:29 Uhr
onDetachedFromRecyclerView wird aufgerufen, wenn Sie Adapter wechseln, aber es wird nicht aufgerufen, wenn die Konfiguration geändert wird :/
– Miha_x64
24. Januar 2017 um 10:23 Uhr
@ Miha_x64, das scheint ein ganz anderes Problem zu sein
– Bartek Lipinski
24. Januar 2017 um 11:26 Uhr
Wie werden Sie dasselbe Problem lösen, wenn das Abonnement etwas ist, das ständig nach mehr Daten lauscht? Für den Kontext verwende ich den Firebase Data Change Listener.
– Adi
21. November 2018 um 21:37 Uhr
eugstmann
Für andere, die das gleiche Problem haben: viewDetachedFromWindow im Adapter wird nur aufgerufen, wenn der Adapter in onPause (Aktivität, Fragment) oder onDetachFromWindow (Aktivität, Fragment) auf null gesetzt ist.
recyclerview.setAdapter(null)
Dann erhalten Sie viewDetachedFromWindow(…), wo Sie Ihre internen Zustände und Abonnements freigeben können. Ich würde Ihre Abonnements in Bindung einrichten, stellen Sie sicher, dass Sie vor jedem Bindungsanruf alte Abonnements freigeben, da eine Ansicht recycelt werden kann.
Eine andere Möglichkeit besteht darin, eine benutzerdefinierte Ansicht statt nur eines Layouts in Ihrer Fabrik aufzublasen. Dann können Sie die Bereinigung in der benutzerdefinierten Ansicht onDetachFromWindow() vornehmen. Sie erhalten das onDetachedFromWindow auch ohne den Adapter auf null zu setzen.
Wie werden Sie dasselbe Problem lösen, wenn das Abonnement etwas ist, das ständig nach mehr Daten lauscht? Für den Kontext verwende ich den Firebase Data Change Listener.
– Adi
21. November 2018 um 21:37 Uhr
@Adi Ich würde eine benutzerdefinierte Ansicht erstellen und onDetachFromWindow() verwenden
– eugstmann
26. November 2018 um 8:36 Uhr
Das würde das Problem glaube ich nicht lösen. onDetachFromWindow wird aufgerufen, wenn die Aktivität aktiv ist und eine Recycler-Ansicht aus dem Fenster gescrollt wird. Wenn Sie jedoch eine Aktivität schließen, wird diese Methode nicht für die zuletzt im Fenster sichtbaren Ansichten aufgerufen. Es würde also ein Speicherleck geben.
– Adi
27. November 2018 um 14:18 Uhr
@Adi onDetachFromWindow wird auch aufgerufen, wenn die Aktivität zerstört wird, beispielsweise wenn Sie die Android-Zurück-Taste drücken.
– eugstmann
29. November 2018 um 20:21 Uhr
So viele Stunden mit diesem Thema verschwendet. Vielen Dank.
– Rubén Viguera
6. Juni 2019 um 13:39 Uhr
Man kann anrufen public void onViewRecycled(@NonNull VH holder)
12450900cookie-checkWas ist der Lebenszyklus für den RecyclerView-Adapter?yes
Bitte erklären Sie, warum Sie herabstimmen
– Eugen Martynow
7. Juni 2016 um 9:16 Uhr
Überprüfen Sie meine Antwort hier stackoverflow.com/a/68351804/6039240
– Amr
12. Juli 2021 um 17:43 Uhr