I am developing a module in which I need to show all the video from phone in form of video thumbnails. I have taken BaseAdapter to show all video thumbnails into GridView. The only problem is that I had to write the code extract thumbnail from video file to bitmap in getView() of BaseAdapter.
((Activity) context).runOnUiThread(new Runnable() {
@Override
public void run() {
Bitmap bmThumbnail = ThumbnailUtils.createVideoThumbnail(
videoValues.get(position).getFile()
.getAbsolutePath(), Thumbnails.MINI_KIND);
imageThumbnail.setImageBitmap(bmThumbnail);
bmThumbnail = null;
}
});
I want to load this Asynchronously with some image loader. I have already tried Aquery, Universal Image Loader, Picasso etc but none of them gives asynchronous image loading with memory caching, file caching, failure callback mechanism etc.
Can anyone suggest how can I achieve this efficiently? TIA.
To resolve this issue, I have made a class VideoThumbLoader
. It asynchronously generated Bitmap and passes it to adapter. So that main benefit is that the whole process is being handled in background thread.
The code for class is as below:
import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.media.ThumbnailUtils;
import android.os.AsyncTask;
import android.provider.MediaStore;
import android.support.v4.util.LruCache;
import android.widget.ImageView;
public class VideoThumbLoader {
private LruCache<String, Bitmap> lruCache;
@SuppressLint("NewApi")
public VideoThumbLoader() {
int maxMemory = (int) Runtime.getRuntime().maxMemory();// obtain maximum
// memory to run
int maxSize = maxMemory / 4;// get cache memory size 35
lruCache = new LruCache<String, Bitmap>(maxSize) {
@Override
protected int sizeOf(String key, Bitmap value) {
// this will be called when the cache deposited in each
return value.getByteCount();
}
};
}
public void addVideoThumbToCache(String path, Bitmap bitmap) {
if (getVideoThumbToCache(path) == null && bitmap != null) {
lruCache.put(path, bitmap);
}
}
public Bitmap getVideoThumbToCache(String path) {
return lruCache.get(path);
}
public void showThumbByAsynctack(String path, ImageView imgview) {
if (getVideoThumbToCache(path) == null) {
// asynchronous loading
new MyBobAsynctack(imgview, path).execute(path);
} else {
imgview.setImageBitmap(getVideoThumbToCache(path));
}
}
class MyBobAsynctack extends AsyncTask<String, Void, Bitmap> {
private ImageView imgView;
private String path;
public MyBobAsynctack(ImageView imageView, String path) {
this.imgView = imageView;
this.path = path;
}
@Override
protected Bitmap doInBackground(String... params) {
Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(params[0],
MediaStore.Video.Thumbnails.MINI_KIND);
// provide
if (getVideoThumbToCache(params[0]) == null) {
addVideoThumbToCache(path, bitmap);
}
return bitmap;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
if (imgView.getTag().equals(path)) {// through Tag can be bound
// pictures address and
// imageView, this address
// Listview loading the image
// dislocation solution
imgView.setImageBitmap(bitmap);
}
}
}
}
And from adapter side, simply call:
private VideoThumbLoader mVideoThumbLoader = new VideoThumbLoader();
imageThumbnail.setTag(videoValues.get(position).getFile()
.getAbsolutePath());// binding imageview
imageThumbnail.setImageResource(R.drawable.videothumb); //default image
mVideoThumbLoader.showThumbByAsynctack(videoValues.get(position)
.getFile().getAbsolutePath(), imageThumbnail);
P.S: One important thing I had taken a note of was, due to asynchronous downloading of bitmap, there were few cases where thumbnails tend to mix up. So I have tagged the imageview with file path. This way I will have the exact thumbnail for the image.