Fix slowdowns in stream list views

Now the playback state of a stream is loaded only when needed (i.e. when the stream is visible), just as it is done with thumbnails.
Removed `StateObjectsListAdapter.java`, which used to load the state of every stream at list instantiation, generating slowdowns and freezes.
This commit is contained in:
Stypox 2019-08-14 11:42:39 +02:00
parent 5053d470f6
commit e6617ff8e8
No known key found for this signature in database
GPG Key ID: 4BDF1B40A49FDD23
22 changed files with 96 additions and 284 deletions

View File

@ -64,7 +64,6 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
@Override
public void onDetach() {
infoListAdapter.dispose();
super.onDetach();
}
@ -97,8 +96,6 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
}
updateFlags = 0;
}
itemsList.post(infoListAdapter::updateStates);
}
/*//////////////////////////////////////////////////////////////////////////

View File

@ -24,6 +24,7 @@ import org.schabi.newpipe.info_list.holder.PlaylistInfoItemHolder;
import org.schabi.newpipe.info_list.holder.PlaylistMiniInfoItemHolder;
import org.schabi.newpipe.info_list.holder.StreamInfoItemHolder;
import org.schabi.newpipe.info_list.holder.StreamMiniInfoItemHolder;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.util.OnClickGesture;
/*
@ -61,14 +62,14 @@ public class InfoItemBuilder {
this.context = context;
}
public View buildView(@NonNull ViewGroup parent, @NonNull final InfoItem infoItem, @Nullable StreamStateEntity state) {
return buildView(parent, infoItem, state, false);
public View buildView(@NonNull ViewGroup parent, @NonNull final InfoItem infoItem, final HistoryRecordManager historyRecordManager) {
return buildView(parent, infoItem, historyRecordManager, false);
}
public View buildView(@NonNull ViewGroup parent, @NonNull final InfoItem infoItem,
@Nullable StreamStateEntity state, boolean useMiniVariant) {
final HistoryRecordManager historyRecordManager, boolean useMiniVariant) {
InfoItemHolder holder = holderFromInfoType(parent, infoItem.getInfoType(), useMiniVariant);
holder.updateFromItem(infoItem, state);
holder.updateFromItem(infoItem, historyRecordManager);
return holder.itemView;
}

View File

@ -1,6 +1,7 @@
package org.schabi.newpipe.info_list;
import android.app.Activity;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.GridLayoutManager;
@ -27,6 +28,7 @@ import org.schabi.newpipe.info_list.holder.PlaylistMiniInfoItemHolder;
import org.schabi.newpipe.info_list.holder.StreamGridInfoItemHolder;
import org.schabi.newpipe.info_list.holder.StreamInfoItemHolder;
import org.schabi.newpipe.info_list.holder.StreamMiniInfoItemHolder;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.util.FallbackViewHolder;
import org.schabi.newpipe.util.OnClickGesture;
@ -53,7 +55,7 @@ import java.util.List;
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
*/
public class InfoListAdapter extends StateObjectsListAdapter {
public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final String TAG = InfoListAdapter.class.getSimpleName();
private static final boolean DEBUG = false;
@ -74,6 +76,7 @@ public class InfoListAdapter extends StateObjectsListAdapter {
private final InfoItemBuilder infoItemBuilder;
private final ArrayList<InfoItem> infoItemList;
private final HistoryRecordManager recordManager;
private boolean useMiniVariant = false;
private boolean useGridVariant = false;
private boolean showFooter = false;
@ -89,9 +92,9 @@ public class InfoListAdapter extends StateObjectsListAdapter {
}
}
public InfoListAdapter(Activity a) {
super(a.getApplicationContext());
infoItemBuilder = new InfoItemBuilder(a);
public InfoListAdapter(Context context) {
this.recordManager = new HistoryRecordManager(context);
infoItemBuilder = new InfoItemBuilder(context);
infoItemList = new ArrayList<>();
}
@ -121,7 +124,7 @@ public class InfoListAdapter extends StateObjectsListAdapter {
public void addInfoItemList(@Nullable final List<InfoItem> data) {
if (data != null) {
loadStates(data, infoItemList.size(), () -> addInfoItemListImpl(data));
addInfoItemListImpl(data);
}
}
@ -149,7 +152,7 @@ public class InfoListAdapter extends StateObjectsListAdapter {
public void addInfoItem(@Nullable InfoItem data) {
if (data != null) {
loadState(data, infoItemList.size(), () -> addInfoItemImpl(data));
addInfoItemImpl(data);
}
}
@ -174,18 +177,11 @@ public class InfoListAdapter extends StateObjectsListAdapter {
}
}
public void updateStates() {
if (!infoItemList.isEmpty()) {
updateAllStates(infoItemList);
}
}
public void clearStreamItemList() {
if (infoItemList.isEmpty()) {
return;
}
infoItemList.clear();
clearStates();
notifyDataSetChanged();
}
@ -304,7 +300,7 @@ public class InfoListAdapter extends StateObjectsListAdapter {
// If header isn't null, offset the items by -1
if (header != null) position--;
((InfoItemHolder) holder).updateFromItem(infoItemList.get(position), getState(position));
((InfoItemHolder) holder).updateFromItem(infoItemList.get(position), recordManager);
} else if (holder instanceof HFHolder && position == 0 && header != null) {
((HFHolder) holder).view = header;
} else if (holder instanceof HFHolder && position == sizeConsideringHeaderOffset() && footer != null && showFooter) {
@ -317,11 +313,9 @@ public class InfoListAdapter extends StateObjectsListAdapter {
if (!payloads.isEmpty() && holder instanceof InfoItemHolder) {
for (Object payload : payloads) {
if (payload instanceof StreamStateEntity) {
((InfoItemHolder) holder).updateState(infoItemList.get(header == null ? position : position - 1),
(StreamStateEntity) payload);
((InfoItemHolder) holder).updateState(infoItemList.get(header == null ? position : position - 1), recordManager);
} else if (payload instanceof Boolean) {
((InfoItemHolder) holder).updateState(infoItemList.get(header == null ? position : position - 1),
null);
((InfoItemHolder) holder).updateState(infoItemList.get(header == null ? position : position - 1), recordManager);
}
}
} else {
@ -329,11 +323,6 @@ public class InfoListAdapter extends StateObjectsListAdapter {
}
}
@Override
protected void onItemStateChanged(int position, @Nullable StreamStateEntity state) {
notifyItemChanged(header == null ? position : position + 1, state != null ? state : false);
}
public GridLayoutManager.SpanSizeLookup getSpanSizeLookup(final int spanCount) {
return new GridLayoutManager.SpanSizeLookup() {
@Override

View File

@ -1,180 +0,0 @@
package org.schabi.newpipe.info_list;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.util.SparseArray;
import org.schabi.newpipe.BuildConfig;
import org.schabi.newpipe.R;
import org.schabi.newpipe.database.LocalItem;
import org.schabi.newpipe.database.stream.model.StreamStateEntity;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.util.SparseArrayUtils;
import java.util.List;
import java.util.Objects;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
public abstract class StateObjectsListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final SparseArray<StreamStateEntity> states;
private final HistoryRecordManager recordManager;
private final CompositeDisposable stateLoaders;
private final Context context;
public StateObjectsListAdapter(Context context) {
this.states = new SparseArray<>();
this.recordManager = new HistoryRecordManager(context);
this.context = context;
this.stateLoaders = new CompositeDisposable();
}
@Nullable
public StreamStateEntity getState(int position) {
return states.get(position);
}
protected void clearStates() {
states.clear();
}
private void appendStates(List<StreamStateEntity> statesEntities, int offset) {
for (int i = 0; i < statesEntities.size(); i++) {
final StreamStateEntity state = statesEntities.get(i);
if (state != null) {
states.append(offset + i, state);
}
}
}
private void appendState(StreamStateEntity statesEntity, int offset) {
if (statesEntity != null) {
states.append(offset, statesEntity);
}
}
protected void removeState(int index) {
states.remove(index);
}
protected void moveState(int from, int to) {
final StreamStateEntity item = states.get(from);
if (from < to) {
SparseArrayUtils.shiftItemsDown(states, from, to);
} else {
SparseArrayUtils.shiftItemsUp(states, to, from);
}
states.put(to, item);
}
protected void loadStates(List<InfoItem> list, int offset, Runnable callback) {
if (isPlaybackStatesVisible()) {
List<StreamStateEntity> streamStateEntities = null;
try {
streamStateEntities = recordManager.loadStreamStateBatch(list).blockingGet();
} catch (Exception e) {
if (BuildConfig.DEBUG) e.printStackTrace();
}
if(streamStateEntities != null) appendStates(streamStateEntities, offset);
callback.run();
} else {
callback.run();
}
}
protected void loadState(InfoItem item, int offset, Runnable callback) {
if (isPlaybackStatesVisible()) {
StreamStateEntity[] streamStateEntities = null;
try {
streamStateEntities = recordManager.loadStreamState(item).blockingGet();
} catch (Exception e) {
if (BuildConfig.DEBUG) e.printStackTrace();
}
if(streamStateEntities != null && streamStateEntities.length > 0) appendState(streamStateEntities[0], offset);
callback.run();
} else {
callback.run();
}
}
protected void loadStatesForLocal(List<? extends LocalItem> list, int offset, Runnable callback) {
if (isPlaybackStatesVisible()) {
List<StreamStateEntity> streamStateEntities = null;
try {
streamStateEntities = recordManager.loadLocalStreamStateBatch(list).blockingGet();
} catch (Exception e) {
if (BuildConfig.DEBUG) e.printStackTrace();
}
if(streamStateEntities != null) appendStates(streamStateEntities, offset);
callback.run();
} else {
callback.run();
}
}
private void processStatesUpdates(List<StreamStateEntity> streamStateEntities) {
for (int i = 0; i < streamStateEntities.size(); i++) {
final StreamStateEntity newState = streamStateEntities.get(i);
if (!Objects.equals(states.get(i), newState)) {
if (newState == null) {
states.remove(i);
} else {
states.put(i, newState);
}
onItemStateChanged(i, newState);
}
}
}
protected void updateAllStates(List<InfoItem> list) {
if (isPlaybackStatesVisible()) {
stateLoaders.add(
recordManager.loadStreamStateBatch(list)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::processStatesUpdates, throwable -> {
if (BuildConfig.DEBUG) throwable.printStackTrace();
})
);
} else {
final int[] positions = SparseArrayUtils.getKeys(states);
states.clear();
for (int pos : positions) onItemStateChanged(pos, null);
}
}
protected void updateAllLocalStates(List<? extends LocalItem> list) {
if (isPlaybackStatesVisible()) {
stateLoaders.add(
recordManager.loadLocalStreamStateBatch(list)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::processStatesUpdates, throwable -> {
if (BuildConfig.DEBUG) throwable.printStackTrace();
})
);
} else {
final int[] positions = SparseArrayUtils.getKeys(states);
states.clear();
for (int pos : positions) onItemStateChanged(pos, null);
}
}
public void dispose() {
stateLoaders.dispose();
}
protected boolean isPlaybackStatesVisible() {
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getBoolean(context.getString(R.string.enable_watch_history_key), true)
&& prefs.getBoolean(context.getString(R.string.enable_playback_resume_key), true)
&& prefs.getBoolean(context.getString(R.string.enable_playback_state_lists_key), true);
}
protected abstract void onItemStateChanged(int position, @Nullable StreamStateEntity state);
}

View File

@ -9,6 +9,7 @@ import org.schabi.newpipe.database.stream.model.StreamStateEntity;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
import org.schabi.newpipe.info_list.InfoItemBuilder;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.util.Localization;
/*
@ -40,8 +41,8 @@ public class ChannelInfoItemHolder extends ChannelMiniInfoItemHolder {
}
@Override
public void updateFromItem(final InfoItem infoItem, @Nullable final StreamStateEntity state) {
super.updateFromItem(infoItem, state);
public void updateFromItem(final InfoItem infoItem, final HistoryRecordManager historyRecordManager) {
super.updateFromItem(infoItem, historyRecordManager);
if (!(infoItem instanceof ChannelInfoItem)) return;
final ChannelInfoItem item = (ChannelInfoItem) infoItem;

View File

@ -9,6 +9,7 @@ import org.schabi.newpipe.database.stream.model.StreamStateEntity;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
import org.schabi.newpipe.info_list.InfoItemBuilder;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.Localization;
@ -32,7 +33,7 @@ public class ChannelMiniInfoItemHolder extends InfoItemHolder {
}
@Override
public void updateFromItem(final InfoItem infoItem, @Nullable final StreamStateEntity state) {
public void updateFromItem(final InfoItem infoItem, final HistoryRecordManager historyRecordManager) {
if (!(infoItem instanceof ChannelInfoItem)) return;
final ChannelInfoItem item = (ChannelInfoItem) infoItem;

View File

@ -9,6 +9,7 @@ import org.schabi.newpipe.database.stream.model.StreamStateEntity;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
import org.schabi.newpipe.info_list.InfoItemBuilder;
import org.schabi.newpipe.local.history.HistoryRecordManager;
/*
* Created by Christian Schabesberger on 12.02.17.
@ -41,8 +42,8 @@ public class CommentsInfoItemHolder extends CommentsMiniInfoItemHolder {
}
@Override
public void updateFromItem(final InfoItem infoItem, @Nullable final StreamStateEntity state) {
super.updateFromItem(infoItem, state);
public void updateFromItem(final InfoItem infoItem, final HistoryRecordManager historyRecordManager) {
super.updateFromItem(infoItem, historyRecordManager);
if (!(infoItem instanceof CommentsInfoItem)) return;
final CommentsInfoItem item = (CommentsInfoItem) infoItem;

View File

@ -13,6 +13,7 @@ import org.schabi.newpipe.database.stream.model.StreamStateEntity;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
import org.schabi.newpipe.info_list.InfoItemBuilder;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.util.CommentTextOnTouchListener;
import org.schabi.newpipe.util.ImageDisplayConstants;
@ -67,7 +68,7 @@ public class CommentsMiniInfoItemHolder extends InfoItemHolder {
}
@Override
public void updateFromItem(final InfoItem infoItem, @Nullable final StreamStateEntity state) {
public void updateFromItem(final InfoItem infoItem, final HistoryRecordManager historyRecordManager) {
if (!(infoItem instanceof CommentsInfoItem)) return;
final CommentsInfoItem item = (CommentsInfoItem) infoItem;
@ -76,20 +77,17 @@ public class CommentsMiniInfoItemHolder extends InfoItemHolder {
itemThumbnailView,
ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS);
itemThumbnailView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(StringUtil.isBlank(item.getAuthorEndpoint())) return;
try {
final AppCompatActivity activity = (AppCompatActivity) itemBuilder.getContext();
NavigationHelper.openChannelFragment(
activity.getSupportFragmentManager(),
item.getServiceId(),
item.getAuthorEndpoint(),
item.getAuthorName());
} catch (Exception e) {
ErrorActivity.reportUiError((AppCompatActivity) itemBuilder.getContext(), e);
}
itemThumbnailView.setOnClickListener(view -> {
if(StringUtil.isBlank(item.getAuthorEndpoint())) return;
try {
final AppCompatActivity activity = (AppCompatActivity) itemBuilder.getContext();
NavigationHelper.openChannelFragment(
activity.getSupportFragmentManager(),
item.getServiceId(),
item.getAuthorEndpoint(),
item.getAuthorName());
} catch (Exception e) {
ErrorActivity.reportUiError((AppCompatActivity) itemBuilder.getContext(), e);
}
});

View File

@ -8,6 +8,7 @@ import android.view.ViewGroup;
import org.schabi.newpipe.database.stream.model.StreamStateEntity;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.info_list.InfoItemBuilder;
import org.schabi.newpipe.local.history.HistoryRecordManager;
/*
* Created by Christian Schabesberger on 12.02.17.
@ -37,8 +38,8 @@ public abstract class InfoItemHolder extends RecyclerView.ViewHolder {
this.itemBuilder = infoItemBuilder;
}
public abstract void updateFromItem(final InfoItem infoItem, @Nullable final StreamStateEntity state);
public abstract void updateFromItem(final InfoItem infoItem, final HistoryRecordManager historyRecordManager);
public void updateState(final InfoItem infoItem, @Nullable final StreamStateEntity state) {
public void updateState(final InfoItem infoItem, final HistoryRecordManager historyRecordManager) {
}
}

View File

@ -10,6 +10,7 @@ import org.schabi.newpipe.database.stream.model.StreamStateEntity;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem;
import org.schabi.newpipe.info_list.InfoItemBuilder;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.util.ImageDisplayConstants;
public class PlaylistMiniInfoItemHolder extends InfoItemHolder {
@ -32,7 +33,7 @@ public class PlaylistMiniInfoItemHolder extends InfoItemHolder {
}
@Override
public void updateFromItem(final InfoItem infoItem, @Nullable final StreamStateEntity state) {
public void updateFromItem(final InfoItem infoItem, final HistoryRecordManager historyRecordManager) {
if (!(infoItem instanceof PlaylistInfoItem)) return;
final PlaylistInfoItem item = (PlaylistInfoItem) infoItem;

View File

@ -10,6 +10,7 @@ import org.schabi.newpipe.database.stream.model.StreamStateEntity;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.info_list.InfoItemBuilder;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.util.Localization;
/*
@ -42,8 +43,8 @@ public class StreamInfoItemHolder extends StreamMiniInfoItemHolder {
}
@Override
public void updateFromItem(final InfoItem infoItem, @Nullable final StreamStateEntity state) {
super.updateFromItem(infoItem, state);
public void updateFromItem(final InfoItem infoItem, final HistoryRecordManager historyRecordManager) {
super.updateFromItem(infoItem, historyRecordManager);
if (!(infoItem instanceof StreamInfoItem)) return;
final StreamInfoItem item = (StreamInfoItem) infoItem;

View File

@ -13,6 +13,7 @@ import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.extractor.stream.StreamType;
import org.schabi.newpipe.info_list.InfoItemBuilder;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.util.AnimationUtils;
import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.Localization;
@ -43,7 +44,7 @@ public class StreamMiniInfoItemHolder extends InfoItemHolder {
}
@Override
public void updateFromItem(final InfoItem infoItem, @Nullable final StreamStateEntity state) {
public void updateFromItem(final InfoItem infoItem, final HistoryRecordManager historyRecordManager) {
if (!(infoItem instanceof StreamInfoItem)) return;
final StreamInfoItem item = (StreamInfoItem) infoItem;
@ -55,10 +56,12 @@ public class StreamMiniInfoItemHolder extends InfoItemHolder {
itemDurationView.setBackgroundColor(ContextCompat.getColor(itemBuilder.getContext(),
R.color.duration_background_color));
itemDurationView.setVisibility(View.VISIBLE);
if (state != null) {
StreamStateEntity state2 = historyRecordManager.loadStreamState(infoItem).blockingGet()[0];
if (state2 != null) {
itemProgressView.setVisibility(View.VISIBLE);
itemProgressView.setMax((int) item.getDuration());
itemProgressView.setProgress((int) TimeUnit.MILLISECONDS.toSeconds(state.getProgressTime()));
itemProgressView.setProgress((int) TimeUnit.MILLISECONDS.toSeconds(state2.getProgressTime()));
} else {
itemProgressView.setVisibility(View.GONE);
}
@ -101,8 +104,10 @@ public class StreamMiniInfoItemHolder extends InfoItemHolder {
}
@Override
public void updateState(final InfoItem infoItem, @Nullable final StreamStateEntity state) {
public void updateState(final InfoItem infoItem, final HistoryRecordManager historyRecordManager) {
final StreamInfoItem item = (StreamInfoItem) infoItem;
StreamStateEntity state = historyRecordManager.loadStreamState(infoItem).blockingGet()[0];
if (state != null && item.getDuration() > 0 && item.getStreamType() != StreamType.LIVE_STREAM) {
itemProgressView.setMax((int) item.getDuration());
if (itemProgressView.getVisibility() == View.VISIBLE) {
@ -130,4 +135,4 @@ public class StreamMiniInfoItemHolder extends InfoItemHolder {
itemView.setLongClickable(false);
itemView.setOnLongClickListener(null);
}
}
}

View File

@ -76,8 +76,6 @@ public abstract class BaseLocalListFragment<I, N> extends BaseStateFragment<I>
}
updateFlags = 0;
}
itemsList.post(itemListAdapter::updateStates);
}
/*//////////////////////////////////////////////////////////////////////////
@ -152,7 +150,6 @@ public abstract class BaseLocalListFragment<I, N> extends BaseStateFragment<I>
public void onDestroyView() {
super.onDestroyView();
itemsList = null;
itemListAdapter.dispose();
itemListAdapter = null;
}

View File

@ -1,6 +1,7 @@
package org.schabi.newpipe.local;
import android.app.Activity;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.GridLayoutManager;
@ -11,7 +12,7 @@ import android.view.ViewGroup;
import org.schabi.newpipe.database.LocalItem;
import org.schabi.newpipe.database.stream.model.StreamStateEntity;
import org.schabi.newpipe.info_list.StateObjectsListAdapter;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.local.holder.LocalItemHolder;
import org.schabi.newpipe.local.holder.LocalPlaylistGridItemHolder;
import org.schabi.newpipe.local.holder.LocalPlaylistItemHolder;
@ -49,7 +50,7 @@ import java.util.List;
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
*/
public class LocalItemListAdapter extends StateObjectsListAdapter {
public class LocalItemListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final String TAG = LocalItemListAdapter.class.getSimpleName();
private static final boolean DEBUG = false;
@ -68,6 +69,7 @@ public class LocalItemListAdapter extends StateObjectsListAdapter {
private final LocalItemBuilder localItemBuilder;
private final ArrayList<LocalItem> localItems;
private final HistoryRecordManager recordManager;
private final DateFormat dateFormat;
private boolean showFooter = false;
@ -75,12 +77,12 @@ public class LocalItemListAdapter extends StateObjectsListAdapter {
private View header = null;
private View footer = null;
public LocalItemListAdapter(Activity activity) {
super(activity.getApplicationContext());
localItemBuilder = new LocalItemBuilder(activity);
public LocalItemListAdapter(Context context) {
recordManager = new HistoryRecordManager(context);
localItemBuilder = new LocalItemBuilder(context);
localItems = new ArrayList<>();
dateFormat = DateFormat.getDateInstance(DateFormat.SHORT,
Localization.getPreferredLocale(activity));
Localization.getPreferredLocale(context));
}
public void setSelectedListener(OnClickGesture<LocalItem> listener) {
@ -93,7 +95,7 @@ public class LocalItemListAdapter extends StateObjectsListAdapter {
public void addItems(@Nullable List<? extends LocalItem> data) {
if (data != null) {
loadStatesForLocal(data, localItems.size(), () -> addItemsImpl(data));
addItemsImpl(data);
}
}
@ -124,16 +126,9 @@ public class LocalItemListAdapter extends StateObjectsListAdapter {
}
}
public void updateStates() {
if (!localItems.isEmpty()) {
updateAllLocalStates(localItems);
}
}
public void removeItem(final LocalItem data) {
final int index = localItems.indexOf(data);
localItems.remove(index);
removeState(index);
notifyItemRemoved(index + (header != null ? 1 : 0));
}
@ -145,7 +140,6 @@ public class LocalItemListAdapter extends StateObjectsListAdapter {
if (actualFrom >= localItems.size() || actualTo >= localItems.size()) return false;
localItems.add(actualTo, localItems.remove(actualFrom));
moveState(actualFrom, actualTo);
notifyItemMoved(fromAdapterPosition, toAdapterPosition);
return true;
}
@ -155,7 +149,6 @@ public class LocalItemListAdapter extends StateObjectsListAdapter {
return;
}
localItems.clear();
clearStates();
notifyDataSetChanged();
}
@ -276,7 +269,7 @@ public class LocalItemListAdapter extends StateObjectsListAdapter {
// If header isn't null, offset the items by -1
if (header != null) position--;
((LocalItemHolder) holder).updateFromItem(localItems.get(position), getState(position), dateFormat);
((LocalItemHolder) holder).updateFromItem(localItems.get(position), recordManager, dateFormat);
} else if (holder instanceof HeaderFooterHolder && position == 0 && header != null) {
((HeaderFooterHolder) holder).view = header;
} else if (holder instanceof HeaderFooterHolder && position == sizeConsideringHeader()
@ -290,11 +283,9 @@ public class LocalItemListAdapter extends StateObjectsListAdapter {
if (!payloads.isEmpty() && holder instanceof LocalItemHolder) {
for (Object payload : payloads) {
if (payload instanceof StreamStateEntity) {
((LocalItemHolder) holder).updateState(localItems.get(header == null ? position : position - 1),
(StreamStateEntity) payload);
((LocalItemHolder) holder).updateState(localItems.get(header == null ? position : position - 1), recordManager);
} else if (payload instanceof Boolean) {
((LocalItemHolder) holder).updateState(localItems.get(header == null ? position : position - 1),
null);
((LocalItemHolder) holder).updateState(localItems.get(header == null ? position : position - 1), recordManager);
}
}
} else {
@ -302,11 +293,6 @@ public class LocalItemListAdapter extends StateObjectsListAdapter {
}
}
@Override
protected void onItemStateChanged(int position, @Nullable StreamStateEntity state) {
notifyItemChanged(header == null ? position : position + 1, state != null ? state : false);
}
public GridLayoutManager.SpanSizeLookup getSpanSizeLookup(final int spanCount) {
return new GridLayoutManager.SpanSizeLookup() {
@Override

View File

@ -113,7 +113,6 @@ public final class PlaylistAppendDialog extends PlaylistDialog {
super.onDestroyView();
if (playlistReactor != null) playlistReactor.dispose();
if (playlistAdapter != null) {
playlistAdapter.dispose();
playlistAdapter.unsetSelectedListener();
}

View File

@ -8,6 +8,7 @@ import android.view.ViewGroup;
import org.schabi.newpipe.database.LocalItem;
import org.schabi.newpipe.database.stream.model.StreamStateEntity;
import org.schabi.newpipe.local.LocalItemBuilder;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import java.text.DateFormat;
@ -40,8 +41,8 @@ public abstract class LocalItemHolder extends RecyclerView.ViewHolder {
this.itemBuilder = itemBuilder;
}
public abstract void updateFromItem(final LocalItem item, @Nullable final StreamStateEntity state, final DateFormat dateFormat);
public abstract void updateFromItem(final LocalItem item, HistoryRecordManager historyRecordManager, final DateFormat dateFormat);
public void updateState(final LocalItem localItem, @Nullable final StreamStateEntity state) {
public void updateState(final LocalItem localItem, HistoryRecordManager historyRecordManager) {
}
}

View File

@ -8,6 +8,7 @@ import org.schabi.newpipe.database.LocalItem;
import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry;
import org.schabi.newpipe.database.stream.model.StreamStateEntity;
import org.schabi.newpipe.local.LocalItemBuilder;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.util.ImageDisplayConstants;
import java.text.DateFormat;
@ -23,7 +24,7 @@ public class LocalPlaylistItemHolder extends PlaylistItemHolder {
}
@Override
public void updateFromItem(final LocalItem localItem, @Nullable final StreamStateEntity state, final DateFormat dateFormat) {
public void updateFromItem(final LocalItem localItem, HistoryRecordManager historyRecordManager, final DateFormat dateFormat) {
if (!(localItem instanceof PlaylistMetadataEntry)) return;
final PlaylistMetadataEntry item = (PlaylistMetadataEntry) localItem;
@ -34,6 +35,6 @@ public class LocalPlaylistItemHolder extends PlaylistItemHolder {
itemBuilder.displayImage(item.thumbnailUrl, itemThumbnailView,
ImageDisplayConstants.DISPLAY_PLAYLIST_OPTIONS);
super.updateFromItem(localItem, state, dateFormat);
super.updateFromItem(localItem, historyRecordManager, dateFormat);
}
}

View File

@ -14,12 +14,14 @@ import org.schabi.newpipe.database.playlist.PlaylistStreamEntry;
import org.schabi.newpipe.database.stream.model.StreamStateEntity;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.local.LocalItemBuilder;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.util.AnimationUtils;
import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.views.AnimatedProgressBar;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
public class LocalPlaylistStreamItemHolder extends LocalItemHolder {
@ -47,7 +49,7 @@ public class LocalPlaylistStreamItemHolder extends LocalItemHolder {
}
@Override
public void updateFromItem(final LocalItem localItem, @Nullable final StreamStateEntity state, final DateFormat dateFormat) {
public void updateFromItem(final LocalItem localItem, HistoryRecordManager historyRecordManager, final DateFormat dateFormat) {
if (!(localItem instanceof PlaylistStreamEntry)) return;
final PlaylistStreamEntry item = (PlaylistStreamEntry) localItem;
@ -60,6 +62,8 @@ public class LocalPlaylistStreamItemHolder extends LocalItemHolder {
itemDurationView.setBackgroundColor(ContextCompat.getColor(itemBuilder.getContext(),
R.color.duration_background_color));
itemDurationView.setVisibility(View.VISIBLE);
StreamStateEntity state = historyRecordManager.loadLocalStreamStateBatch(new ArrayList<LocalItem>() {{ add(localItem); }}).blockingGet().get(0);
if (state != null) {
itemProgressView.setVisibility(View.VISIBLE);
itemProgressView.setMax((int) item.duration);
@ -94,9 +98,11 @@ public class LocalPlaylistStreamItemHolder extends LocalItemHolder {
}
@Override
public void updateState(LocalItem localItem, @Nullable StreamStateEntity state) {
public void updateState(LocalItem localItem, HistoryRecordManager historyRecordManager) {
if (!(localItem instanceof PlaylistStreamEntry)) return;
final PlaylistStreamEntry item = (PlaylistStreamEntry) localItem;
StreamStateEntity state = historyRecordManager.loadLocalStreamStateBatch(new ArrayList<LocalItem>() {{ add(localItem); }}).blockingGet().get(0);
if (state != null && item.duration > 0) {
itemProgressView.setMax((int) item.duration);
if (itemProgressView.getVisibility() == View.VISIBLE) {

View File

@ -2,6 +2,7 @@ package org.schabi.newpipe.local.holder;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
@ -13,12 +14,14 @@ import org.schabi.newpipe.database.stream.StreamStatisticsEntry;
import org.schabi.newpipe.database.stream.model.StreamStateEntity;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.local.LocalItemBuilder;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.util.AnimationUtils;
import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.views.AnimatedProgressBar;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
/*
@ -76,7 +79,7 @@ public class LocalStatisticStreamItemHolder extends LocalItemHolder {
}
@Override
public void updateFromItem(final LocalItem localItem, @Nullable final StreamStateEntity state, final DateFormat dateFormat) {
public void updateFromItem(final LocalItem localItem, HistoryRecordManager historyRecordManager, final DateFormat dateFormat) {
if (!(localItem instanceof StreamStatisticsEntry)) return;
final StreamStatisticsEntry item = (StreamStatisticsEntry) localItem;
@ -88,6 +91,8 @@ public class LocalStatisticStreamItemHolder extends LocalItemHolder {
itemDurationView.setBackgroundColor(ContextCompat.getColor(itemBuilder.getContext(),
R.color.duration_background_color));
itemDurationView.setVisibility(View.VISIBLE);
StreamStateEntity state = historyRecordManager.loadLocalStreamStateBatch(new ArrayList<LocalItem>() {{ add(localItem); }}).blockingGet().get(0);
if (state != null) {
itemProgressView.setVisibility(View.VISIBLE);
itemProgressView.setMax((int) item.duration);
@ -124,9 +129,11 @@ public class LocalStatisticStreamItemHolder extends LocalItemHolder {
}
@Override
public void updateState(LocalItem localItem, @Nullable StreamStateEntity state) {
public void updateState(LocalItem localItem, HistoryRecordManager historyRecordManager) {
if (!(localItem instanceof StreamStatisticsEntry)) return;
final StreamStatisticsEntry item = (StreamStatisticsEntry) localItem;
StreamStateEntity state = historyRecordManager.loadLocalStreamStateBatch(new ArrayList<LocalItem>() {{ add(localItem); }}).blockingGet().get(0);
if (state != null && item.duration > 0) {
itemProgressView.setMax((int) item.duration);
if (itemProgressView.getVisibility() == View.VISIBLE) {

View File

@ -9,6 +9,7 @@ import org.schabi.newpipe.R;
import org.schabi.newpipe.database.LocalItem;
import org.schabi.newpipe.database.stream.model.StreamStateEntity;
import org.schabi.newpipe.local.LocalItemBuilder;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import java.text.DateFormat;
@ -33,7 +34,7 @@ public abstract class PlaylistItemHolder extends LocalItemHolder {
}
@Override
public void updateFromItem(final LocalItem localItem, @Nullable final StreamStateEntity state, final DateFormat dateFormat) {
public void updateFromItem(final LocalItem localItem, HistoryRecordManager historyRecordManager, final DateFormat dateFormat) {
itemView.setOnClickListener(view -> {
if (itemBuilder.getOnItemSelectedListener() != null) {
itemBuilder.getOnItemSelectedListener().selected(localItem);

View File

@ -8,6 +8,7 @@ import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity;
import org.schabi.newpipe.database.stream.model.StreamStateEntity;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.local.LocalItemBuilder;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.Localization;
@ -23,7 +24,7 @@ public class RemotePlaylistItemHolder extends PlaylistItemHolder {
}
@Override
public void updateFromItem(final LocalItem localItem, @Nullable final StreamStateEntity state, final DateFormat dateFormat) {
public void updateFromItem(final LocalItem localItem, HistoryRecordManager historyRecordManager, final DateFormat dateFormat) {
if (!(localItem instanceof PlaylistRemoteEntity)) return;
final PlaylistRemoteEntity item = (PlaylistRemoteEntity) localItem;
@ -35,6 +36,6 @@ public class RemotePlaylistItemHolder extends PlaylistItemHolder {
itemBuilder.displayImage(item.getThumbnailUrl(), itemThumbnailView,
ImageDisplayConstants.DISPLAY_PLAYLIST_OPTIONS);
super.updateFromItem(localItem, state, dateFormat);
super.updateFromItem(localItem, historyRecordManager, dateFormat);
}
}

View File

@ -130,7 +130,6 @@ public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEnt
@Override
public void onDetach() {
infoListAdapter.dispose();
super.onDetach();
}
@ -153,8 +152,6 @@ public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEnt
}
updateFlags = 0;
}
itemsList.post(infoListAdapter::updateStates);
}
@Override