前言:
在我刚刚完成的一个版本开发中,有这样的一个需求,我们选择了多个视频,进入到下面几个层级的时候,需要把视频文件的第一帧图片展示在imageview上,对视频做处理,在这个地方,怎样把视频第一帧图像很快的取出来,就有了这篇文章,以记录开发中的点点滴滴,下面开始介绍。
1.场景设置为读取手机的视频文件,gridview显示视频第一帧,显示的速率不能太慢了,选择多个视频,进入到第二层界面,界面要非常快显示出视频的封面。
2.now let's do it,首先第一步在项目的AndroidManifest清单文件中添加上读取权限
3.第二步先获出来的所有的视频文件,所以先定义视频文件bean对象MediaModeVideo,一个视频文件的name,文件fileUrl,视频文件时长,现在定义单个的文件夹对象VideoPhotoFloder,这个对象我包含了视频和图片的集合对象,但是这里我们只需要视频集合。
3.第三步获取手机里面的视频文件,有了对象了,那还会单身吗,哈哈😄,写一个util工具类获取全部的视频文件分文件夹都取出来,别忘了在界面打开的时候申请权限,不然就尴尬了,说什么都不如代码实在。
获取视频的方法是调用Android 内容解析器ContentResolver,查询的5个参数uri,projection,selection,selectionArgs,sortOrder,具体5个参数的用处就自行学习吧。现在方法已经有了,可以拿到数据了,界面上的绘画就比较简单了,一个简单的gridview,调用我们的util的获取方法设置适配器就完事
为了让其他界面能快速的拿到视频对象的第一帧,在这个适配器的里面就是我们要重点说的地方。在adapter里面对视频文件根据地址异步获取第一帧做缓存,就是为了在后面的操作中可以快速的获取到视频的封面。
还是不说废话上代码,继承AsyncTask,定义一次执行线程数量最多10个个线程,
因为我们定义了视频和图片两种类型或者加了type类型作为BLGalleryCache读取的条件之一
我在异步处理中分配给自己做的缓存BLGalleryCache大小是进程内存的1/8,BLGalleryRetainCache一个单例类保证BLGalleryCache单例,好了现在就介绍BLGalleryCache的作用,
缓存主要用的是LruCache,LruCache是android提供的一个缓存工具类,其算法是最近最少使用算法。它把最近使用的对象用“强引用”存储在LinkedHashMap中,并且把最近最少使用的对象在缓存值达到预设定值之前就从内存中移除,就是酱紫😯,在adapter中单个new 出来的时候,从单例中获取到mBitmapCache根据key取对应的bitmap.在LruCache清理掉的时候,开个AsyncTask再去取。
可以看到我设置了一个条件当不是在滑动的时候才去加载,在Scrolling的时候是没有执行task的,这样也只是为了不损耗资源吧。好了,最后一步了,在mBitmapCache里面没有或者被清理的时候,去AsyncTask地址Url获取bitmap
private classBLBitmapLoaderTaskextendsAsyncTask {
privateBaseAdaptermAdapter;
privateStringmImageKey;
publicBLBitmapLoaderTask(String imageKey,BaseAdapter adapter) {
mAdapter= adapter;
mImageKey= imageKey;
}
@Override
protected voidonPreExecute() {
mCurrentTasks.add(mImageKey);
}
@Override
protectedBitmapdoInBackground(Void... params) {
Bitmap bitmap =null;
try{
bitmap = ThumbnailUtils.createVideoThumbnail(mImageKey,
Thumbnails.FULL_SCREEN_KIND);
if(bitmap !=null) {
bitmap = Bitmap.createScaledBitmap(bitmap,mMaxWidth,
mMaxWidth, false);
addBitmapToCache(mImageKey,bitmap);
returnbitmap;
}
return null;
}catch(Exception e) {
if(e !=null) {
e.printStackTrace();
}
return null;
}
}
@Override
protected voidonPostExecute(Bitmap param) {
mCurrentTasks.remove(mImageKey);
if(param !=null) {
if(mAdapter!=null)
mAdapter.notifyDataSetChanged();
}
}
}
直接上代码了,传递adapter过来是为了让界面刷新,imageview是adapter里面调用的时候传递的holder .image.到此为止,我们的缓存就搞出来了,核心就是利用LruCache其特性做这件事。好处就是什么呢,好处就是在我很深层级的地方,只要一个视频的地址就可以轻松拿到bitmap。渲染速率,自然非常快,也完美的完成了项目的需求。需要调用的地方就是简单的一行代码搞定
代码链接后面会附上。现在看下场景运行的效果
因为限制10M,所以压缩的挺厉害的,有些失真了,感谢大家的阅读,希望对大家有一点点的促进,代码会托管到git上,链接随后附上。