Commit 99faad42 authored by Geoffrey Métais's avatar Geoffrey Métais
Browse files

Use an object pool for image fetcher

parent 251be466
......@@ -30,6 +30,8 @@ import android.databinding.ViewDataBinding;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.support.v17.leanback.widget.ImageCardView;
import android.support.v4.util.Pools;
import android.support.v4.view.ViewCompat;
import android.text.TextUtils;
import android.view.View;
......@@ -64,25 +66,15 @@ public class AsyncImageLoader {
private static final BitmapCache sBitmapCache = BitmapCache.getInstance();
private static final Medialibrary sMedialibrary = VLCApplication.getMLInstance();
/*
* Custom bindings to trigger image (down)loading
*/
@BindingAdapter({"imageUri"})
public static void downloadIcon(final View v, final Uri imageUri) {
if (imageUri == null || !imageUri.getScheme().equals("http"))
return;
AsyncImageLoader.LoadImage(new CoverFetcher(null) {
@Override
public Bitmap getImage() {
return HttpImageLoader.downloadBitmap(imageUri.toString());
}
@Override
public void updateImage(Bitmap bitmap, View target) {
updateTargetImage(bitmap, v, binding);
}
}, v);
if (imageUri != null && imageUri.getScheme().equals("http"))
loadImage(new HttpImageLoader(imageUri.toString(), DataBindingUtil.findBinding(v)), v);
}
@BindingAdapter({"media"})
......@@ -108,37 +100,49 @@ public class AsyncImageLoader {
return;
if (isMediaFile && "file".equals(uri.getScheme())) {
mw = sMedialibrary.getMedia(uri);
if (mw != null)
item = mw;
if (mw != null) item = mw;
}
}
AsyncImageLoader.LoadImage(new MLItemCoverFetcher(v, item), v);
loadImage(MLItemCoverFetcher.obtain().init(v, item), v);
}
public static void LoadImage(final Callbacks cbs, final View target){
private static void loadImage(final Callbacks cbs, final View target){
VLCApplication.runBackground(new Runnable() {
@Override
public void run() {
final Bitmap bitmap = cbs.getImage();
cbs.updateImage(bitmap, target);
cbs.updateImage(cbs.getImage(), target);
}
});
}
private static class MLItemCoverFetcher extends AsyncImageLoader.CoverFetcher {
MediaLibraryItem item;
@SuppressWarnings("unchecked")
private static final Pools.SynchronizedPool<MLItemCoverFetcher> sPool = new Pools.SynchronizedPool(20);
private MediaLibraryItem item;
int width;
MLItemCoverFetcher(View v, MediaLibraryItem item) {
super(DataBindingUtil.findBinding(v));
static MLItemCoverFetcher obtain() {
final MLItemCoverFetcher instance = sPool.acquire();
return instance != null ? instance : new MLItemCoverFetcher();
}
MLItemCoverFetcher init(View v, MediaLibraryItem item) {
super.init(DataBindingUtil.findBinding(v));
this.item = item;
width = v.getWidth();
return this;
}
void recycle() {
clear();
item = null;
width = 0;
sPool.release(this);
}
@Override
public Bitmap getImage() {
if (bindChanged)
return null;
if (bindChanged) return null;
if (item instanceof MediaGroup)
return ThumbnailsProvider.getComposedImage((MediaGroup) item);
return AudioUtil.readCoverBitmap(Uri.decode(item.getArtworkMrl()), width);
......@@ -146,14 +150,13 @@ public class AsyncImageLoader {
@Override
public void updateImage(Bitmap bitmap, View target) {
if (!bindChanged)
updateTargetImage(bitmap, target, binding);
if (!bindChanged) updateTargetImage(bitmap, target, binding);
recycle();
}
}
private static void updateTargetImage(final Bitmap bitmap, final View target, final ViewDataBinding vdb) {
if (bitmap == null || bitmap.getWidth() <= 1 || bitmap.getHeight() <= 1)
return;
public static void updateTargetImage(final Bitmap bitmap, final View target, final ViewDataBinding vdb) {
if (bitmap == null || bitmap.getWidth() <= 1 || bitmap.getHeight() <= 1) return;
if (vdb != null) {
vdb.setVariable(BR.scaleType, ImageView.ScaleType.FIT_CENTER);
vdb.setVariable(BR.cover, new BitmapDrawable(target.getResources(), bitmap));
......@@ -170,16 +173,19 @@ public class AsyncImageLoader {
} else if (target instanceof TextView) {
ViewCompat.setBackground(target, new BitmapDrawable(VLCApplication.getAppResources(), bitmap));
((TextView) target).setText(null);
} else if (target instanceof ImageCardView) {
((ImageCardView)target).getMainImageView().setScaleType(ImageView.ScaleType.CENTER_CROP);
((ImageCardView)target).setMainImage(new BitmapDrawable(target.getResources(), bitmap));
}
}
});
}
}
abstract static class CoverFetcher implements AsyncImageLoader.Callbacks {
abstract public static class CoverFetcher implements AsyncImageLoader.Callbacks {
protected ViewDataBinding binding = null;
boolean bindChanged = false;
final OnRebindCallback<ViewDataBinding> rebindCallbacks = new OnRebindCallback<ViewDataBinding>() {
private final OnRebindCallback<ViewDataBinding> rebindCallbacks = new OnRebindCallback<ViewDataBinding>() {
@Override
public boolean onPreBind(ViewDataBinding binding) {
bindChanged = true;
......@@ -197,12 +203,20 @@ public class AsyncImageLoader {
}
};
CoverFetcher(ViewDataBinding binding){
protected void init(ViewDataBinding binding) {
if (binding != null) {
this.binding = binding;
this.binding.executePendingBindings();
this.binding.addOnRebindCallback(rebindCallbacks);
}
}
protected void clear() {
if (binding != null) {
this.binding.removeOnRebindCallback(rebindCallbacks);
binding = null;
bindChanged = false;
}
}
}
}
......@@ -64,7 +64,6 @@ public class BitmapCache {
public synchronized Bitmap getBitmapFromMemCache(String key) {
final Bitmap b = mMemCache.get(key);
if (b == null){
mMemCache.remove(key);
return null;
......
......@@ -29,14 +29,11 @@ import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.preference.PreferenceManager;
import android.support.v17.leanback.widget.ImageCardView;
import android.support.v17.leanback.widget.Presenter;
import android.support.v4.content.ContextCompat;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
......@@ -47,7 +44,6 @@ import org.videolan.vlc.R;
import org.videolan.vlc.VLCApplication;
import org.videolan.vlc.gui.helpers.AsyncImageLoader;
import org.videolan.vlc.gui.helpers.AudioUtil;
import org.videolan.vlc.util.HttpImageLoader;
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public class CardPresenter extends Presenter {
......@@ -59,7 +55,6 @@ public class CardPresenter extends Presenter {
private static final int CARD_WIDTH = VLCApplication.getAppResources().getDimensionPixelSize(R.dimen.tv_grid_card_thumb_width);
private static final int CARD_HEIGHT = VLCApplication.getAppResources().getDimensionPixelSize(R.dimen.tv_grid_card_thumb_height);
private static Drawable sDefaultCardImage;
private static Handler sHandler = new Handler(Looper.getMainLooper());
private boolean mIsSeenMediaMarkerVisible = true;
......@@ -81,11 +76,49 @@ public class CardPresenter extends Presenter {
}
void updateCardViewImage(MediaLibraryItem mediaLibraryItem) {
if (!TextUtils.isEmpty(mediaLibraryItem.getArtworkMrl()) && mediaLibraryItem.getArtworkMrl().startsWith("http")) {
AsyncImageLoader.LoadImage(new HttpImageLoader(mediaLibraryItem.getArtworkMrl()), mCardView);
} else {
AsyncImageLoader.LoadImage(new CoverFetcher(mediaLibraryItem), mCardView);
if (!TextUtils.isEmpty(mediaLibraryItem.getArtworkMrl()))
AsyncImageLoader.loadPicture(mCardView, mediaLibraryItem);
else {
mCardView.getMainImageView().setScaleType(ImageView.ScaleType.FIT_CENTER);
mCardView.setMainImage(new BitmapDrawable(mCardView.getResources(), getDefaultImage(mediaLibraryItem)));
}
}
private Bitmap getDefaultImage(MediaLibraryItem mediaLibraryItem) {
Bitmap picture;
final Resources res = mCardView.getResources();
if (mediaLibraryItem.getItemType() == MediaLibraryItem.TYPE_MEDIA && ((MediaWrapper) mediaLibraryItem).getType() == MediaWrapper.TYPE_DIR) {
MediaWrapper mediaWrapper = (MediaWrapper) mediaLibraryItem;
if (TextUtils.equals(mediaWrapper.getUri().getScheme(), "file"))
picture = BitmapFactory.decodeResource(res, R.drawable.ic_menu_folder_big);
else
picture = BitmapFactory.decodeResource(res, R.drawable.ic_menu_network_big);
} else
picture = AudioUtil.readCoverBitmap(Uri.decode(mediaLibraryItem.getArtworkMrl()), res.getDimensionPixelSize(R.dimen.tv_grid_card_thumb_width));
if (picture == null) {
int resId;
switch (mediaLibraryItem.getItemType()) {
case MediaLibraryItem.TYPE_ALBUM:
resId = R.drawable.ic_album_big;
break;
case MediaLibraryItem.TYPE_ARTIST:
resId = R.drawable.ic_artist_big;
break;
case MediaLibraryItem.TYPE_GENRE:
resId = R.drawable.ic_genre_big;
break;
case MediaLibraryItem.TYPE_MEDIA:
if (((MediaWrapper)mediaLibraryItem).getType() == MediaWrapper.TYPE_VIDEO)
resId = R.drawable.ic_browser_video_big_normal;
else
resId = R.drawable.ic_song_big;
break;
default:
resId = R.drawable.ic_browser_unknown_big_normal;
}
picture = BitmapFactory.decodeResource(res, resId);
}
return picture;
}
void updateCardViewImage(Drawable image) {
......@@ -234,74 +267,4 @@ public class CardPresenter extends Presenter {
this.name = name;
}
}
private static class CoverFetcher implements AsyncImageLoader.Callbacks{
MediaLibraryItem mediaLibraryItem;
private static Resources res;
CoverFetcher(MediaLibraryItem mediaLibraryItem){
this.mediaLibraryItem = mediaLibraryItem;
res = VLCApplication.getAppResources();
}
@Override
public Bitmap getImage() {
Bitmap picture = null;
if (mediaLibraryItem.getItemType() == MediaLibraryItem.TYPE_MEDIA && ((MediaWrapper) mediaLibraryItem).getType() == MediaWrapper.TYPE_DIR) {
MediaWrapper mediaWrapper = (MediaWrapper) mediaLibraryItem;
if (TextUtils.equals(mediaWrapper.getUri().getScheme(), "file"))
picture = BitmapFactory.decodeResource(res, R.drawable.ic_menu_folder_big);
else
picture = BitmapFactory.decodeResource(res, R.drawable.ic_menu_network_big);
} else
picture = AudioUtil.readCoverBitmap(Uri.decode(mediaLibraryItem.getArtworkMrl()), res.getDimensionPixelSize(R.dimen.tv_grid_card_thumb_width));
if (picture == null) {
int resId;
switch (mediaLibraryItem.getItemType()) {
case MediaLibraryItem.TYPE_ALBUM:
resId = R.drawable.ic_album_big;
break;
case MediaLibraryItem.TYPE_ARTIST:
resId = R.drawable.ic_artist_big;
break;
case MediaLibraryItem.TYPE_GENRE:
resId = R.drawable.ic_genre_big;
break;
case MediaLibraryItem.TYPE_MEDIA:
if (((MediaWrapper)mediaLibraryItem).getType() == MediaWrapper.TYPE_VIDEO)
resId = R.drawable.ic_browser_video_big_normal;
else
resId = R.drawable.ic_song_big;
break;
default:
resId = R.drawable.ic_browser_unknown_big_normal;
}
picture = BitmapFactory.decodeResource(res, resId);
}
return picture;
}
@Override
public void updateImage(final Bitmap picture, final View target) {
sHandler.post(
new Runnable() {
@Override
public void run() {
ImageCardView cardView = (ImageCardView) target;
if (picture != null && picture.getByteCount() > 4) {
if (mediaLibraryItem.getArtworkMrl() !=null && !mediaLibraryItem.getArtworkMrl().isEmpty())
cardView.getMainImageView().setScaleType(ImageView.ScaleType.CENTER_CROP);
else
cardView.getMainImageView().setScaleType(ImageView.ScaleType.FIT_CENTER);
cardView.setMainImage(new BitmapDrawable(res, picture));
}
else {
cardView.setMainImage(sDefaultCardImage);
cardView.getMainImageView().setScaleType(ImageView.ScaleType.FIT_CENTER);
}
}
}
);
}
}
}
......@@ -24,23 +24,16 @@
package org.videolan.vlc.util;
import android.databinding.OnRebindCallback;
import android.databinding.ViewDataBinding;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.Nullable;
import android.support.v17.leanback.widget.ImageCardView;
import android.support.v4.util.SimpleArrayMap;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import org.videolan.vlc.BR;
import org.videolan.vlc.VLCApplication;
import org.videolan.vlc.gui.helpers.AsyncImageLoader.Callbacks;
import org.videolan.vlc.gui.helpers.AsyncImageLoader;
import java.io.BufferedInputStream;
import java.io.IOException;
......@@ -49,43 +42,15 @@ import java.lang.ref.SoftReference;
import java.net.HttpURLConnection;
import java.net.URL;
public class HttpImageLoader implements Callbacks {
public class HttpImageLoader extends AsyncImageLoader.CoverFetcher {
private static SimpleArrayMap<String, SoftReference<Bitmap>> iconsMap = new SimpleArrayMap<>();
private String mImageLink;
private ViewDataBinding mBinding;
private boolean bindChanged = false;
final OnRebindCallback<ViewDataBinding> rebindCallbacks;
private static final Handler sHandler = new Handler(Looper.getMainLooper());
public HttpImageLoader(String imageLink) {
mImageLink = imageLink;
rebindCallbacks = null;
}
public HttpImageLoader(String imageLink, ViewDataBinding binding) {
init(binding);
mImageLink = imageLink;
mBinding = binding;
mBinding = binding;
mBinding.executePendingBindings();
rebindCallbacks = new OnRebindCallback<ViewDataBinding>() {
@Override
public boolean onPreBind(ViewDataBinding binding) {
bindChanged = true;
return super.onPreBind(binding);
}
@Override
public void onCanceled(ViewDataBinding binding) {
super.onCanceled(binding);
}
@Override
public void onBound(ViewDataBinding binding) {
super.onBound(binding);
}
};
mBinding.addOnRebindCallback(rebindCallbacks);
}
@Override
......@@ -97,7 +62,7 @@ public class HttpImageLoader implements Callbacks {
public static Bitmap getBitmapFromIconCache(String imageUrl) {
synchronized (iconsMap) {
if (iconsMap.containsKey(imageUrl)) {
Bitmap bd = iconsMap.get(imageUrl).get();
final Bitmap bd = iconsMap.get(imageUrl).get();
if (bd != null) {
return bd;
} else
......@@ -133,27 +98,6 @@ public class HttpImageLoader implements Callbacks {
@Override
public void updateImage(final Bitmap bitmap, final View target) {
if (bitmap == null || bitmap.getWidth() == 1 || bitmap.getHeight() == 1)
return;
if (mBinding != null) {
mBinding.removeOnRebindCallback(rebindCallbacks);
if (bindChanged)
return;
mBinding.setVariable(BR.scaleType, ImageView.ScaleType.FIT_CENTER);
mBinding.setVariable(BR.image, new BitmapDrawable(VLCApplication.getAppResources(), bitmap));
mBinding.setVariable(BR.protocol, null);
} else {
sHandler.post(new Runnable() {
@Override
public void run() {
if (target instanceof ImageCardView)
((ImageCardView) target).setMainImage(new BitmapDrawable(target.getResources(), bitmap));
else if (target instanceof ImageView)
((ImageView) target).setImageBitmap(bitmap);
else if (target instanceof TextView)
target.setBackgroundDrawable(new BitmapDrawable(target.getResources(), bitmap));
}
});
}
AsyncImageLoader.updateTargetImage(bitmap, target, binding);
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment