Skip to content

Commit e758b5f

Browse files
Adapt header handling changes from other recyclerview adapters to fix...
... Crash in lists (ViewHolder views not attached) in StatisticsPlaylistFragment Co-Authored-By: j-haldane <200528955+j-haldane@users.noreply.github.com>
1 parent 7283701 commit e758b5f

4 files changed

Lines changed: 40 additions & 29 deletions

File tree

app/src/main/java/org/schabi/newpipe/local/BaseLocalListFragment.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
import static org.schabi.newpipe.ktx.ViewUtils.animateHideRecyclerViewAllowingScrolling;
2929
import static org.schabi.newpipe.util.ThemeHelper.getItemViewMode;
3030

31+
import java.util.function.Supplier;
32+
3133
/**
3234
* This fragment is design to be used with persistent data such as
3335
* {@link org.schabi.newpipe.database.LocalItem}, and does not cache the data contained
@@ -100,7 +102,7 @@ private void refreshItemViewMode() {
100102
//////////////////////////////////////////////////////////////////////////*/
101103

102104
@Nullable
103-
protected ViewBinding getListHeader() {
105+
protected Supplier<View> getListHeaderSupplier() {
104106
return null;
105107
}
106108

@@ -131,9 +133,9 @@ protected void initViews(final View rootView, final Bundle savedInstanceState) {
131133
itemsList = rootView.findViewById(R.id.items_list);
132134
refreshItemViewMode();
133135

134-
headerRootBinding = getListHeader();
135-
if (headerRootBinding != null) {
136-
itemListAdapter.setHeader(headerRootBinding.getRoot());
136+
final Supplier<View> listHeaderSupplier = getListHeaderSupplier();
137+
if (listHeaderSupplier != null) {
138+
itemListAdapter.setHeaderSupplier(listHeaderSupplier);
137139
}
138140
footerRootBinding = getListFooter();
139141
itemListAdapter.setFooter(footerRootBinding.getRoot());

app/src/main/java/org/schabi/newpipe/local/LocalItemListAdapter.java

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import android.content.Context;
44
import android.util.Log;
5+
import android.view.LayoutInflater;
56
import android.view.View;
67
import android.view.ViewGroup;
78

@@ -37,6 +38,7 @@
3738
import java.time.format.FormatStyle;
3839
import java.util.ArrayList;
3940
import java.util.List;
41+
import java.util.function.Supplier;
4042

4143
/*
4244
* Created by Christian Schabesberger on 01.08.16.
@@ -82,13 +84,14 @@ public class LocalItemListAdapter extends RecyclerView.Adapter<RecyclerView.View
8284
private static final int REMOTE_PLAYLIST_CARD_HOLDER_TYPE = 0x3002;
8385
private static final int REMOTE_BOOKMARK_PLAYLIST_HOLDER_TYPE = 0x3003;
8486

87+
private final LayoutInflater layoutInflater;
8588
private final LocalItemBuilder localItemBuilder;
8689
private final ArrayList<LocalItem> localItems;
8790
private final HistoryRecordManager recordManager;
8891
private final DateTimeFormatter dateTimeFormatter;
8992

9093
private boolean showFooter = false;
91-
private View header = null;
94+
private Supplier<View> headerSupplier = null;
9295
private View footer = null;
9396
private ItemViewMode itemViewMode = ItemViewMode.LIST;
9497
private boolean useItemHandle = false;
@@ -97,6 +100,8 @@ public LocalItemListAdapter(final Context context) {
97100
recordManager = new HistoryRecordManager(context);
98101
localItemBuilder = new LocalItemBuilder(context);
99102
localItems = new ArrayList<>();
103+
layoutInflater = LayoutInflater.from(context);
104+
100105
dateTimeFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT)
101106
.withLocale(Localization.getPreferredLocale(context));
102107
}
@@ -124,7 +129,7 @@ public void addItems(@Nullable final List<? extends LocalItem> data) {
124129
if (DEBUG) {
125130
Log.d(TAG, "addItems() after > offsetStart = " + offsetStart + ", "
126131
+ "localItems.size() = " + localItems.size() + ", "
127-
+ "header = " + header + ", footer = " + footer + ", "
132+
+ "header = " + hasHeader() + ", footer = " + footer + ", "
128133
+ "showFooter = " + showFooter);
129134
}
130135
notifyItemRangeInserted(offsetStart, data.size());
@@ -144,7 +149,7 @@ public void removeItem(final LocalItem data) {
144149
final int index = localItems.indexOf(data);
145150
if (index != -1) {
146151
localItems.remove(index);
147-
notifyItemRemoved(index + (header != null ? 1 : 0));
152+
notifyItemRemoved(index + (hasHeader() ? 1 : 0));
148153
} else {
149154
// this happens when
150155
// 1) removeItem is called on infoItemDuplicate as in showStreamItemDialog of
@@ -189,9 +194,9 @@ public void setUseItemHandle(final boolean useItemHandle) {
189194
this.useItemHandle = useItemHandle;
190195
}
191196

192-
public void setHeader(final View header) {
193-
final boolean changed = header != this.header;
194-
this.header = header;
197+
public void setHeaderSupplier(@Nullable final Supplier<View> headerSupplier) {
198+
final boolean changed = headerSupplier != this.headerSupplier;
199+
this.headerSupplier = headerSupplier;
195200
if (changed) {
196201
notifyDataSetChanged();
197202
}
@@ -201,6 +206,10 @@ public void setFooter(final View view) {
201206
this.footer = view;
202207
}
203208

209+
protected boolean hasHeader() {
210+
return this.headerSupplier != null;
211+
}
212+
204213
public void showFooter(final boolean show) {
205214
if (DEBUG) {
206215
Log.d(TAG, "showFooter() called with: show = [" + show + "]");
@@ -218,11 +227,11 @@ public void showFooter(final boolean show) {
218227
}
219228

220229
private int adapterOffsetWithoutHeader(final int offset) {
221-
return offset - (header != null ? 1 : 0);
230+
return offset - (hasHeader() ? 1 : 0);
222231
}
223232

224233
private int sizeConsideringHeader() {
225-
return localItems.size() + (header != null ? 1 : 0);
234+
return localItems.size() + (hasHeader() ? 1 : 0);
226235
}
227236

228237
public ArrayList<LocalItem> getItemsList() {
@@ -232,7 +241,7 @@ public ArrayList<LocalItem> getItemsList() {
232241
@Override
233242
public int getItemCount() {
234243
int count = localItems.size();
235-
if (header != null) {
244+
if (hasHeader()) {
236245
count++;
237246
}
238247
if (footer != null && showFooter) {
@@ -242,7 +251,7 @@ public int getItemCount() {
242251
if (DEBUG) {
243252
Log.d(TAG, "getItemCount() called, count = " + count + ", "
244253
+ "localItems.size() = " + localItems.size() + ", "
245-
+ "header = " + header + ", footer = " + footer + ", "
254+
+ "header = " + hasHeader() + ", footer = " + footer + ", "
246255
+ "showFooter = " + showFooter);
247256
}
248257
return count;
@@ -255,9 +264,9 @@ public int getItemViewType(int position) {
255264
Log.d(TAG, "getItemViewType() called with: position = [" + position + "]");
256265
}
257266

258-
if (header != null && position == 0) {
267+
if (hasHeader() && position == 0) {
259268
return HEADER_TYPE;
260-
} else if (header != null) {
269+
} else if (hasHeader()) {
261270
position--;
262271
}
263272
if (footer != null && position == localItems.size() && showFooter) {
@@ -318,7 +327,7 @@ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull final ViewGroup paren
318327
}
319328
switch (type) {
320329
case HEADER_TYPE:
321-
return new HeaderFooterHolder(header);
330+
return new HeaderFooterHolder(headerSupplier.get());
322331
case FOOTER_TYPE:
323332
return new HeaderFooterHolder(footer);
324333
case LOCAL_PLAYLIST_HOLDER_TYPE:
@@ -366,14 +375,14 @@ public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, int
366375

367376
if (holder instanceof LocalItemHolder) {
368377
// If header isn't null, offset the items by -1
369-
if (header != null) {
378+
if (hasHeader()) {
370379
position--;
371380
}
372381

373382
((LocalItemHolder) holder)
374383
.updateFromItem(localItems.get(position), recordManager, dateTimeFormatter);
375-
} else if (holder instanceof HeaderFooterHolder && position == 0 && header != null) {
376-
((HeaderFooterHolder) holder).view = header;
384+
} else if (holder instanceof HeaderFooterHolder && position == 0 && hasHeader()) {
385+
((HeaderFooterHolder) holder).view = headerSupplier.get();
377386
} else if (holder instanceof HeaderFooterHolder && position == sizeConsideringHeader()
378387
&& footer != null && showFooter) {
379388
((HeaderFooterHolder) holder).view = footer;
@@ -387,10 +396,10 @@ public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, fina
387396
for (final Object payload : payloads) {
388397
if (payload instanceof StreamStateEntity) {
389398
((LocalItemHolder) holder).updateState(localItems
390-
.get(header == null ? position : position - 1), recordManager);
399+
.get(hasHeader() ? position - 1 : position), recordManager);
391400
} else if (payload instanceof Boolean) {
392401
((LocalItemHolder) holder).updateState(localItems
393-
.get(header == null ? position : position - 1), recordManager);
402+
.get(hasHeader() ? position - 1 : position), recordManager);
394403
}
395404
}
396405
} else {

app/src/main/java/org/schabi/newpipe/local/history/StatisticsPlaylistFragment.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313

1414
import androidx.annotation.NonNull;
1515
import androidx.annotation.Nullable;
16-
import androidx.viewbinding.ViewBinding;
1716

1817
import com.evernote.android.state.State;
1918
import com.google.android.material.snackbar.Snackbar;
@@ -45,6 +44,7 @@
4544
import java.util.Comparator;
4645
import java.util.List;
4746
import java.util.Objects;
47+
import java.util.function.Supplier;
4848

4949
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
5050
import io.reactivex.rxjava3.disposables.CompositeDisposable;
@@ -126,12 +126,12 @@ protected void initViews(final View rootView, final Bundle savedInstanceState) {
126126
}
127127

128128
@Override
129-
protected ViewBinding getListHeader() {
129+
protected Supplier<View> getListHeaderSupplier() {
130130
headerBinding = StatisticPlaylistControlBinding.inflate(activity.getLayoutInflater(),
131131
itemsList, false);
132132
playlistControlBinding = headerBinding.playlistControl;
133133

134-
return headerBinding;
134+
return headerBinding::getRoot;
135135
}
136136

137137
@Override

app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
import androidx.appcompat.app.AlertDialog;
3030
import androidx.recyclerview.widget.ItemTouchHelper;
3131
import androidx.recyclerview.widget.RecyclerView;
32-
import androidx.viewbinding.ViewBinding;
3332

3433
import com.evernote.android.state.State;
3534
import org.reactivestreams.Subscriber;
@@ -67,6 +66,7 @@
6766
import java.util.Collections;
6867
import java.util.List;
6968
import java.util.concurrent.atomic.AtomicBoolean;
69+
import java.util.function.Supplier;
7070
import java.util.stream.Collectors;
7171

7272
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
@@ -158,14 +158,14 @@ protected void initViews(final View rootView, final Bundle savedInstanceState) {
158158
}
159159

160160
@Override
161-
protected ViewBinding getListHeader() {
161+
protected Supplier<View> getListHeaderSupplier() {
162162
headerBinding = LocalPlaylistHeaderBinding.inflate(activity.getLayoutInflater(), itemsList,
163-
false);
163+
false);
164164
playlistControlBinding = headerBinding.playlistControl;
165165

166166
headerBinding.playlistTitleView.setSelected(true);
167167

168-
return headerBinding;
168+
return headerBinding::getRoot;
169169
}
170170

171171
@Override

0 commit comments

Comments
 (0)