I have a slight problem. Need a nudge in the right direction. I am doing a video editor like Vine and/or instagram. Where they show a timeline with screencaps from the video
It just adds more pictures depending on the videos duration. What i did for my app is that i added a recyclerView. This recyclerview has an adapter that calls the following function every time onBindViewHolder
public Bitmap getFrameFromCurrentVideo(int seconds) {
Bitmap bitmap = null;
if(mMediaMetadataRetriever != null) {
bitmap = mMediaMetadataRetriever.getFrameAtTime(seconds * 1000000, MediaMetadataRetriever.OPTION_CLOSEST);
}
return bitmap;
}
This works and it adds the proper amount of images that i want. But the problem is that it is too heavy on the UI thread. Since the recyclerView is recycling everything. It then lags up every time it has to get a frame.
So i thought that i have to do some async task and then cache the images. But what i read is that AsyncTask is not recommended for recycler views since it recycles.
So what should i do to enchance the performance? Any good idea?
This is what i did to solve my problem. I created async task and memory cache my result.
My adapter checks if the image already exist. If it does. Then we skip doing the background work. Otherwise i do the async task and try to load the image. We also tag the view just in case the user scrolls while the task is not finished.
This helps us check if the Tag is different from what the task have. If it is the same. Then we can safely put the right image in the imageview.
Snippet from my adapter
@Override
public void onBindViewHolder(PostVideoRecyclerViewHolder holder, int position) {
holder.mImageView.getLayoutParams().width = mScreenWidth / mMaxItemsOnScreen;
holder.mImageView.setImageDrawable(null);
int second = position * 3 - 3;
String TAG = String.valueOf(second);
holder.mImageView.setTag(TAG);
Bitmap bitmap = mFragment.getBitmapFromMemCache(TAG);
if(bitmap == null) {
PostVideoBitmapWorkerTask task = new PostVideoBitmapWorkerTask(holder.mImageView, TAG, mFragment);
task.execute(second);
}
else {
holder.mImageView.setImageBitmap(bitmap);
}
}
My AsyncTask class
public class PostVideoBitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
private ImageView mImageView;
private String TAG;
private PostVideoFeedFragment mFragment;
public PostVideoBitmapWorkerTask(ImageView imageView, String TAG, PostVideoFeedFragment fragment) {
mImageView = imageView;
this.TAG = TAG;
mFragment = fragment;
}
@Override
protected Bitmap doInBackground(Integer... params) {
Bitmap bitmap = mFragment.getFrameFromCurrentVideo(params[0]);
mFragment.addBitmapToCache(TAG,bitmap);
return bitmap;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
if(mImageView.getTag().toString().equals(TAG)) {
mImageView.setImageBitmap(bitmap);
}
}
}
Snippet from my fragment class
public void addBitmapToCache(String key, Bitmap bitmap) {
if (getBitmapFromMemCache(key) == null) {
mMemoryCache.put(key, bitmap);
}
}
public Bitmap getBitmapFromMemCache(String key) {
return mMemoryCache.get(key);
}
I can recommend https://developer.android.com/training/displaying-bitmaps/cache-bitmap.html if you want to read up on caching
And also https://developer.android.com/reference/android/os/AsyncTask.html for reading up on asyncTask's