From e6617ff8e80a9977425aa165eb4e77e47d8a57d4 Mon Sep 17 00:00:00 2001
From: Stypox <stypox@pm.me>
Date: Wed, 14 Aug 2019 11:42:39 +0200
Subject: [PATCH] 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.
---
 .../fragments/list/BaseListFragment.java      |   3 -
 .../newpipe/info_list/InfoItemBuilder.java    |   9 +-
 .../newpipe/info_list/InfoListAdapter.java    |  35 ++--
 .../info_list/StateObjectsListAdapter.java    | 180 ------------------
 .../holder/ChannelInfoItemHolder.java         |   5 +-
 .../holder/ChannelMiniInfoItemHolder.java     |   3 +-
 .../holder/CommentsInfoItemHolder.java        |   5 +-
 .../holder/CommentsMiniInfoItemHolder.java    |  28 ++-
 .../info_list/holder/InfoItemHolder.java      |   5 +-
 .../holder/PlaylistMiniInfoItemHolder.java    |   3 +-
 .../holder/StreamInfoItemHolder.java          |   5 +-
 .../holder/StreamMiniInfoItemHolder.java      |  15 +-
 .../newpipe/local/BaseLocalListFragment.java  |   3 -
 .../newpipe/local/LocalItemListAdapter.java   |  38 ++--
 .../local/dialog/PlaylistAppendDialog.java    |   1 -
 .../newpipe/local/holder/LocalItemHolder.java |   5 +-
 .../local/holder/LocalPlaylistItemHolder.java |   5 +-
 .../holder/LocalPlaylistStreamItemHolder.java |  10 +-
 .../LocalStatisticStreamItemHolder.java       |  11 +-
 .../local/holder/PlaylistItemHolder.java      |   3 +-
 .../holder/RemotePlaylistItemHolder.java      |   5 +-
 .../subscription/SubscriptionFragment.java    |   3 -
 22 files changed, 96 insertions(+), 284 deletions(-)
 delete mode 100644 app/src/main/java/org/schabi/newpipe/info_list/StateObjectsListAdapter.java

diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java
index 279b396df..38a322285 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java
@@ -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);
     }
 
     /*//////////////////////////////////////////////////////////////////////////
diff --git a/app/src/main/java/org/schabi/newpipe/info_list/InfoItemBuilder.java b/app/src/main/java/org/schabi/newpipe/info_list/InfoItemBuilder.java
index 39f7971dd..46b9bf709 100644
--- a/app/src/main/java/org/schabi/newpipe/info_list/InfoItemBuilder.java
+++ b/app/src/main/java/org/schabi/newpipe/info_list/InfoItemBuilder.java
@@ -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;
     }
 
diff --git a/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java b/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java
index 7f5b07dbe..b57a3d2fd 100644
--- a/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java
+++ b/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java
@@ -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
diff --git a/app/src/main/java/org/schabi/newpipe/info_list/StateObjectsListAdapter.java b/app/src/main/java/org/schabi/newpipe/info_list/StateObjectsListAdapter.java
deleted file mode 100644
index 17ac919d9..000000000
--- a/app/src/main/java/org/schabi/newpipe/info_list/StateObjectsListAdapter.java
+++ /dev/null
@@ -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);
-
-}
diff --git a/app/src/main/java/org/schabi/newpipe/info_list/holder/ChannelInfoItemHolder.java b/app/src/main/java/org/schabi/newpipe/info_list/holder/ChannelInfoItemHolder.java
index 317934455..13adadc7b 100644
--- a/app/src/main/java/org/schabi/newpipe/info_list/holder/ChannelInfoItemHolder.java
+++ b/app/src/main/java/org/schabi/newpipe/info_list/holder/ChannelInfoItemHolder.java
@@ -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;
diff --git a/app/src/main/java/org/schabi/newpipe/info_list/holder/ChannelMiniInfoItemHolder.java b/app/src/main/java/org/schabi/newpipe/info_list/holder/ChannelMiniInfoItemHolder.java
index a191707c0..c5ec1b187 100644
--- a/app/src/main/java/org/schabi/newpipe/info_list/holder/ChannelMiniInfoItemHolder.java
+++ b/app/src/main/java/org/schabi/newpipe/info_list/holder/ChannelMiniInfoItemHolder.java
@@ -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;
 
diff --git a/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsInfoItemHolder.java b/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsInfoItemHolder.java
index 4ecf86961..27338a730 100644
--- a/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsInfoItemHolder.java
+++ b/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsInfoItemHolder.java
@@ -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;
diff --git a/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsMiniInfoItemHolder.java b/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsMiniInfoItemHolder.java
index 3d3a9bb09..baf5e9a6e 100644
--- a/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsMiniInfoItemHolder.java
+++ b/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsMiniInfoItemHolder.java
@@ -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);
             }
         });
 
diff --git a/app/src/main/java/org/schabi/newpipe/info_list/holder/InfoItemHolder.java b/app/src/main/java/org/schabi/newpipe/info_list/holder/InfoItemHolder.java
index 3bc0d9e54..666604993 100644
--- a/app/src/main/java/org/schabi/newpipe/info_list/holder/InfoItemHolder.java
+++ b/app/src/main/java/org/schabi/newpipe/info_list/holder/InfoItemHolder.java
@@ -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) {
     }
 }
diff --git a/app/src/main/java/org/schabi/newpipe/info_list/holder/PlaylistMiniInfoItemHolder.java b/app/src/main/java/org/schabi/newpipe/info_list/holder/PlaylistMiniInfoItemHolder.java
index f9d617e66..d2cd1440c 100644
--- a/app/src/main/java/org/schabi/newpipe/info_list/holder/PlaylistMiniInfoItemHolder.java
+++ b/app/src/main/java/org/schabi/newpipe/info_list/holder/PlaylistMiniInfoItemHolder.java
@@ -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;
 
diff --git a/app/src/main/java/org/schabi/newpipe/info_list/holder/StreamInfoItemHolder.java b/app/src/main/java/org/schabi/newpipe/info_list/holder/StreamInfoItemHolder.java
index 25502bc81..cbe026606 100644
--- a/app/src/main/java/org/schabi/newpipe/info_list/holder/StreamInfoItemHolder.java
+++ b/app/src/main/java/org/schabi/newpipe/info_list/holder/StreamInfoItemHolder.java
@@ -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;
diff --git a/app/src/main/java/org/schabi/newpipe/info_list/holder/StreamMiniInfoItemHolder.java b/app/src/main/java/org/schabi/newpipe/info_list/holder/StreamMiniInfoItemHolder.java
index aa2a3f878..ba18b1e94 100644
--- a/app/src/main/java/org/schabi/newpipe/info_list/holder/StreamMiniInfoItemHolder.java
+++ b/app/src/main/java/org/schabi/newpipe/info_list/holder/StreamMiniInfoItemHolder.java
@@ -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);
     }
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/schabi/newpipe/local/BaseLocalListFragment.java b/app/src/main/java/org/schabi/newpipe/local/BaseLocalListFragment.java
index 94672bd49..abdf82353 100644
--- a/app/src/main/java/org/schabi/newpipe/local/BaseLocalListFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/local/BaseLocalListFragment.java
@@ -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;
     }
 
diff --git a/app/src/main/java/org/schabi/newpipe/local/LocalItemListAdapter.java b/app/src/main/java/org/schabi/newpipe/local/LocalItemListAdapter.java
index d29e85ee3..29079b1d0 100644
--- a/app/src/main/java/org/schabi/newpipe/local/LocalItemListAdapter.java
+++ b/app/src/main/java/org/schabi/newpipe/local/LocalItemListAdapter.java
@@ -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
diff --git a/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistAppendDialog.java b/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistAppendDialog.java
index 5973ad920..204d52e69 100644
--- a/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistAppendDialog.java
+++ b/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistAppendDialog.java
@@ -113,7 +113,6 @@ public final class PlaylistAppendDialog extends PlaylistDialog {
         super.onDestroyView();
         if (playlistReactor != null) playlistReactor.dispose();
         if (playlistAdapter != null) {
-            playlistAdapter.dispose();
             playlistAdapter.unsetSelectedListener();
         }
 
diff --git a/app/src/main/java/org/schabi/newpipe/local/holder/LocalItemHolder.java b/app/src/main/java/org/schabi/newpipe/local/holder/LocalItemHolder.java
index c00fa1fb4..605af95b8 100644
--- a/app/src/main/java/org/schabi/newpipe/local/holder/LocalItemHolder.java
+++ b/app/src/main/java/org/schabi/newpipe/local/holder/LocalItemHolder.java
@@ -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) {
     }
 }
diff --git a/app/src/main/java/org/schabi/newpipe/local/holder/LocalPlaylistItemHolder.java b/app/src/main/java/org/schabi/newpipe/local/holder/LocalPlaylistItemHolder.java
index 0e6eca9ba..3b41dd461 100644
--- a/app/src/main/java/org/schabi/newpipe/local/holder/LocalPlaylistItemHolder.java
+++ b/app/src/main/java/org/schabi/newpipe/local/holder/LocalPlaylistItemHolder.java
@@ -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);
     }
 }
diff --git a/app/src/main/java/org/schabi/newpipe/local/holder/LocalPlaylistStreamItemHolder.java b/app/src/main/java/org/schabi/newpipe/local/holder/LocalPlaylistStreamItemHolder.java
index 0c4e66c9d..8f0b5cdb9 100644
--- a/app/src/main/java/org/schabi/newpipe/local/holder/LocalPlaylistStreamItemHolder.java
+++ b/app/src/main/java/org/schabi/newpipe/local/holder/LocalPlaylistStreamItemHolder.java
@@ -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) {
diff --git a/app/src/main/java/org/schabi/newpipe/local/holder/LocalStatisticStreamItemHolder.java b/app/src/main/java/org/schabi/newpipe/local/holder/LocalStatisticStreamItemHolder.java
index b24051a4f..387e98549 100644
--- a/app/src/main/java/org/schabi/newpipe/local/holder/LocalStatisticStreamItemHolder.java
+++ b/app/src/main/java/org/schabi/newpipe/local/holder/LocalStatisticStreamItemHolder.java
@@ -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) {
diff --git a/app/src/main/java/org/schabi/newpipe/local/holder/PlaylistItemHolder.java b/app/src/main/java/org/schabi/newpipe/local/holder/PlaylistItemHolder.java
index 2a81f9571..f8c625a92 100644
--- a/app/src/main/java/org/schabi/newpipe/local/holder/PlaylistItemHolder.java
+++ b/app/src/main/java/org/schabi/newpipe/local/holder/PlaylistItemHolder.java
@@ -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);
diff --git a/app/src/main/java/org/schabi/newpipe/local/holder/RemotePlaylistItemHolder.java b/app/src/main/java/org/schabi/newpipe/local/holder/RemotePlaylistItemHolder.java
index bdcd42f67..da7df7456 100644
--- a/app/src/main/java/org/schabi/newpipe/local/holder/RemotePlaylistItemHolder.java
+++ b/app/src/main/java/org/schabi/newpipe/local/holder/RemotePlaylistItemHolder.java
@@ -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);
     }
 }
diff --git a/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionFragment.java b/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionFragment.java
index 9a53e7e94..c194e664a 100644
--- a/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionFragment.java
@@ -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