-Fixed memory leak due to image loader overusing memory cache.

-Added disk cache for local item loading.
This commit is contained in:
John Zhen Mo 2018-01-29 18:06:48 -08:00
parent d3160eed9d
commit 6f9deea873
11 changed files with 33 additions and 23 deletions

View File

@ -10,6 +10,7 @@ import android.content.Intent;
import android.os.Build;
import android.util.Log;
import com.nostra13.universalimageloader.cache.memory.impl.WeakMemoryCache;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
@ -80,7 +81,9 @@ public class App extends Application {
initNotificationChannel();
// Initialize image loader
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(this).build();
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(this)
.memoryCache(new WeakMemoryCache())
.build();
ImageLoader.getInstance().init(config);
configureRxJavaErrorHandler();

View File

@ -1,8 +1,12 @@
package org.schabi.newpipe.fragments.local;
import android.content.Context;
import android.graphics.Bitmap;
import android.widget.ImageView;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.process.BitmapProcessor;
import org.schabi.newpipe.database.LocalItem;
@ -42,8 +46,9 @@ public class LocalItemBuilder {
return context;
}
public ImageLoader getImageLoader() {
return imageLoader;
public void displayImage(final String url, final ImageView view,
final DisplayImageOptions options) {
imageLoader.displayImage(url, view, options);
}
public OnLocalItemGesture<LocalItem> getOnItemSelectedListener() {

View File

@ -69,10 +69,10 @@ public class LocalItemListAdapter extends RecyclerView.Adapter<RecyclerView.View
localItemBuilder.setOnItemSelectedListener(listener);
}
public void addInfoItemList(List<? extends LocalItem> data) {
public void addItems(List<? extends LocalItem> data) {
if (data != null) {
if (DEBUG) {
Log.d(TAG, "addInfoItemList() before > localItems.size() = " +
Log.d(TAG, "addItems() before > localItems.size() = " +
localItems.size() + ", data.size() = " + data.size());
}
@ -80,7 +80,7 @@ public class LocalItemListAdapter extends RecyclerView.Adapter<RecyclerView.View
localItems.addAll(data);
if (DEBUG) {
Log.d(TAG, "addInfoItemList() after > offsetStart = " + offsetStart +
Log.d(TAG, "addItems() after > offsetStart = " + offsetStart +
", localItems.size() = " + localItems.size() +
", header = " + header + ", footer = " + footer +
", showFooter = " + showFooter);
@ -92,7 +92,7 @@ public class LocalItemListAdapter extends RecyclerView.Adapter<RecyclerView.View
int footerNow = sizeConsideringHeader();
notifyItemMoved(offsetStart, footerNow);
if (DEBUG) Log.d(TAG, "addInfoItemList() footer from " + offsetStart +
if (DEBUG) Log.d(TAG, "addItems() footer from " + offsetStart +
" to " + footerNow);
}
}

View File

@ -349,7 +349,7 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
animateView(headerRootLayout, true, 100);
animateView(itemsList, true, 300);
itemListAdapter.addInfoItemList(result);
itemListAdapter.addItems(result);
if (itemsListState != null) {
itemsList.getLayoutManager().onRestoreInstanceState(itemsListState);
itemsListState = null;

View File

@ -119,7 +119,7 @@ public final class PlaylistAppendDialog extends PlaylistDialog {
}
playlistAdapter.clearStreamItemList();
playlistAdapter.addInfoItemList(metadataEntries);
playlistAdapter.addItems(metadataEntries);
playlistRecyclerView.setVisibility(View.VISIBLE);
});
}

View File

@ -239,7 +239,7 @@ public class BookmarkFragment extends BaseStateFragment<List<PlaylistMetadataEnt
if (result.isEmpty()) {
showEmptyState();
} else {
itemListAdapter.addInfoItemList(infoItemsOf(result));
itemListAdapter.addItems(infoItemsOf(result));
if (itemsListState != null) {
itemsList.getLayoutManager().onRestoreInstanceState(itemsListState);
itemsListState = null;

View File

@ -249,7 +249,7 @@ public abstract class StatisticsPlaylistFragment
animateView(headerRootLayout, true, 100);
animateView(itemsList, true, 300);
itemListAdapter.addInfoItemList(processResult(result));
itemListAdapter.addItems(processResult(result));
if (itemsListState != null) {
itemsList.getLayoutManager().onRestoreInstanceState(itemsListState);
itemsListState = null;

View File

@ -1,10 +1,14 @@
package org.schabi.newpipe.fragments.local.holder;
import android.graphics.Bitmap;
import android.support.annotation.DimenRes;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.process.BitmapProcessor;
import org.schabi.newpipe.database.LocalItem;
import org.schabi.newpipe.fragments.local.LocalItemBuilder;
@ -52,5 +56,8 @@ public abstract class LocalItemHolder extends RecyclerView.ViewHolder {
public static final DisplayImageOptions BASE_DISPLAY_IMAGE_OPTIONS =
new DisplayImageOptions.Builder()
.cacheInMemory(true)
.cacheOnDisk(true)
.bitmapConfig(Bitmap.Config.RGB_565)
.resetViewBeforeLoading(false)
.build();
}

View File

@ -43,8 +43,7 @@ public class LocalPlaylistItemHolder extends LocalItemHolder {
itemStreamCountView.setText(String.valueOf(item.streamCount));
itemUploaderView.setVisibility(View.INVISIBLE);
itemBuilder.getImageLoader().displayImage(item.thumbnailUrl, itemThumbnailView,
DISPLAY_THUMBNAIL_OPTIONS);
itemBuilder.displayImage(item.thumbnailUrl, itemThumbnailView, DISPLAY_THUMBNAIL_OPTIONS);
itemView.setOnClickListener(view -> {
if (itemBuilder.getOnItemSelectedListener() != null) {

View File

@ -1,5 +1,6 @@
package org.schabi.newpipe.fragments.local.holder;
import android.graphics.Bitmap;
import android.support.v4.content.ContextCompat;
import android.view.MotionEvent;
import android.view.View;
@ -8,6 +9,7 @@ import android.widget.ImageView;
import android.widget.TextView;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
import org.schabi.newpipe.R;
import org.schabi.newpipe.database.LocalItem;
@ -59,8 +61,7 @@ public class LocalPlaylistStreamItemHolder extends LocalItemHolder {
}
// Default thumbnail is shown on error, while loading and if the url is empty
itemBuilder.getImageLoader().displayImage(item.thumbnailUrl, itemThumbnailView,
LocalPlaylistStreamItemHolder.DISPLAY_THUMBNAIL_OPTIONS);
itemBuilder.displayImage(item.thumbnailUrl, itemThumbnailView, DISPLAY_THUMBNAIL_OPTIONS);
itemView.setOnClickListener(view -> {
if (itemBuilder.getOnItemSelectedListener() != null) {

View File

@ -45,8 +45,8 @@ public class LocalStatisticStreamItemHolder extends LocalItemHolder {
public final TextView itemDurationView;
public final TextView itemAdditionalDetails;
LocalStatisticStreamItemHolder(LocalItemBuilder infoItemBuilder, int layoutId, ViewGroup parent) {
super(infoItemBuilder, layoutId, parent);
public LocalStatisticStreamItemHolder(LocalItemBuilder infoItemBuilder, ViewGroup parent) {
super(infoItemBuilder, R.layout.list_stream_item, parent);
itemThumbnailView = itemView.findViewById(R.id.itemThumbnailView);
itemVideoTitleView = itemView.findViewById(R.id.itemVideoTitleView);
@ -55,10 +55,6 @@ public class LocalStatisticStreamItemHolder extends LocalItemHolder {
itemAdditionalDetails = itemView.findViewById(R.id.itemAdditionalDetails);
}
public LocalStatisticStreamItemHolder(LocalItemBuilder infoItemBuilder, ViewGroup parent) {
this(infoItemBuilder, R.layout.list_stream_item, parent);
}
private String getStreamInfoDetailLine(final StreamStatisticsEntry entry,
final DateFormat dateFormat) {
final String watchCount = Localization.shortViewCount(itemBuilder.getContext(),
@ -88,8 +84,7 @@ public class LocalStatisticStreamItemHolder extends LocalItemHolder {
itemAdditionalDetails.setText(getStreamInfoDetailLine(item, dateFormat));
// Default thumbnail is shown on error, while loading and if the url is empty
itemBuilder.getImageLoader().displayImage(item.thumbnailUrl, itemThumbnailView,
DISPLAY_THUMBNAIL_OPTIONS);
itemBuilder.displayImage(item.thumbnailUrl, itemThumbnailView, DISPLAY_THUMBNAIL_OPTIONS);
itemView.setOnClickListener(view -> {
if (itemBuilder.getOnItemSelectedListener() != null) {