1.从媒体库中查询
2. android 2.2以后使用ThumbnailUtils类获取
3.调用jni文件,实现MediaMetadataRetriever类
三种方法各有利弊:
第一种方法,新视频增加后需要SDCard重新扫描才能给新增加的文件添加缩略图,灵活性差,而且不是很稳定,适合简单应用
第二种方法,实现简单,但2.2以前的版本不支持
第三种方法,实现复杂,但比较灵活
package cn.lsj.mypalyer.adapter;
import android.content.Context;
import android.database.Cursor;
import android.support.v4.widget.CursorAdapter;
import android.text.format.Formatter;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import cn.lsj.mypalyer.R;
import cn.lsj.mypalyer.bean.VideoBean;
import cn.lsj.mypalyer.utils.MyUtils;
import cn.lsj.mypalyer.utils.MyVideoThumbLoader;
import cn.lsj.mypalyer.view.MyImageView;
public class MyVideoCursorAdapter extends CursorAdapter {
private MyVideoThumbLoader mVideoThumbLoader;
public MyVideoCursorAdapter(Context context, Cursor c) {
super(context, c);
mVideoThumbLoader = new MyVideoThumbLoader();// 初始化缩略图载入方法
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
final VideoBean vb = VideoBean.getInstance(cursor);
View view = View.inflate(mContext, R.layout.video_list_item, null);
ViewHolder vh = new ViewHolder();
vh.title = (TextView) view.findViewById(R.id.video_list_item_tv_title);
vh.duration = (TextView) view
.findViewById(R.id.video_list_item_tv_duration);
vh.size = (TextView) view.findViewById(R.id.video_list_item_tv_size);
vh.iv = (MyImageView) view.findViewById(R.id.iv);
view.setTag(vh);
vh.iv.setTag(vb.path);
return view;
}
@Override
public void bindView(View view, final Context context, Cursor cursor) {
final ViewHolder vh = (ViewHolder) view.getTag();
final VideoBean vb = VideoBean.getInstance(cursor);
vh.title.setText(vb.title);
vh.duration.setText(MyUtils.DurationByMs(vb.duration));
vh.size.setText(Formatter.formatFileSize(context, vb.size));
if (vb.duration == 0) {
vh.iv.setImageResource(R.drawable.btn_audio_play);
} else {
mVideoThumbLoader.showThumbByAsynctack(vb.path, vh.iv);
}
}
private class ViewHolder {
private TextView title;
private TextView duration;
private TextView size;
private MyImageView iv;
}
}
java.lang.IllegalArgumentException: Cannot draw recycled bitmapsat
Android.view.GLES20Canvas.drawBitmap(GLES20Canvas.java:778)at
android.view.GLES20RecordingCanvas.drawBitmap
(GLES20RecordingCanvas.java:117)at
android.graphics.drawable.BitmapDrawable.draw(BitmapDrawable.java:393)at
android.widget.ImageView.onDraw(ImageView.java:979)at
android.view.View.draw(View.java:13458)at
android.view.View.getDisplayList(View.java:12409)at
android.view.View.getDisplayList(View.java:12453)at
android.view.View.draw(View.java:13182)at
android.view.ViewGroup.drawChild(ViewGroup.java:2929)at
android.view.ViewGroup.dispatchDraw(ViewGroup.java:2799)at
android.view.View.draw(View.java:13461)at
android.view.View.getDisplayList(View.java:12409)at
android.view.View.getDisplayList(View.java:12453)at
android.view.View.draw(View.java:13182)at
android.view.ViewGroup.drawChild(ViewGroup.java:2929)at
android.widget.ListView.drawChild(ListView.java:3226)at
android.view.ViewGroup.dispatchDraw(ViewGroup.java:2799)at
android.widget.AbsListView.dispatchDraw(AbsListView.java:2433)at
android.widget.ListView.dispatchDraw(ListView.java:3221)at
android.view.View.draw(View.java:13461)at android.widget.AbsListView.draw
(AbsListView.java:3759)
package cn.lsj.mypalyer.view;
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.widget.ImageView;
public class MyImageView extends ImageView {
public MyImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public MyImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyImageView(Context context) {
super(context);
}
@Override
protected void onDraw(Canvas canvas) {
try {
super.onDraw(canvas);
} catch (Exception e) {
System.out.println("trying to use a recycled bitmap");
}
}
}
MyVideoCursorAdapter adapter = new MyVideoCursorAdapter(mContext, null);
lv.setAdapter(adapter);
MyQueryHandler myQueryHandler = new MyQueryHandler(
mContext.getContentResolver());
myQueryHandler.startQuery(100, adapter, Media.EXTERNAL_CONTENT_URI,
new String[] { Media._ID, Media.TITLE, Media.DATA,
Media.DURATION, Media.SIZE }, null, null, null);
package cn.lsj.mypalyer.utils;
import android.content.AsyncQueryHandler;
import android.content.ContentResolver;
import android.database.Cursor;
import android.support.v4.widget.CursorAdapter;
public class MyQueryHandler extends AsyncQueryHandler {
public MyQueryHandler(ContentResolver cr) {
super(cr);
}
@Override
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
super.onQueryComplete(token, cookie, cursor);
if (token == 100 && cookie instanceof CursorAdapter) {
CursorAdapter adapter = (CursorAdapter) cookie;
adapter.swapCursor(cursor);
}
}
}
vh.iv.setTag(vb.path);
mVideoThumbLoader = new MyVideoThumbLoader();
mVideoThumbLoader.showThumbByAsynctack(vb.path, vh.iv);
package cn.lsj.mypalyer.utils;
import android.graphics.Bitmap;
import android.media.ThumbnailUtils;
import android.os.AsyncTask;
import android.provider.MediaStore.Video.Thumbnails;
import android.support.v4.util.LruCache;
import cn.lsj.mypalyer.R;
import cn.lsj.mypalyer.activity.MainActivity;
import cn.lsj.mypalyer.view.MyImageView;
public class MyVideoThumbLoader {
// 创建cache
private LruCache lruCache;
public MyVideoThumbLoader() {
int maxMemory = (int) Runtime.getRuntime().maxMemory();// 获取最大的运行内存
int maxSize = maxMemory / 4;
// 拿到缓存的内存大小
lruCache = new LruCache(maxSize) {
@Override
protected int sizeOf(String key, Bitmap value) {
// 这个方法会在每次存入缓存的时候调用
return value.getByteCount();
}
};
}
public void addVideoThumbToCache(String path, Bitmap bitmap) {
if (getVideoThumbToCache(path) == null) {
// 当前地址没有缓存时,就添加
lruCache.put(path, bitmap);
}
}
public Bitmap getVideoThumbToCache(String path) {
return lruCache.get(path);
}
public void showThumbByAsynctack(String path, MyImageView imgview) {
if (getVideoThumbToCache(path) == null) {
// 异步加载
new MyBobAsynctack(imgview, path).execute(path);
} else {
imgview.setImageBitmap(getVideoThumbToCache(path));
}
}
class MyBobAsynctack extends AsyncTask {
private MyImageView imgView;
private String path;
public MyBobAsynctack(MyImageView imageView, String path) {
this.imgView = imageView;
this.path = path;
}
@Override
protected Bitmap doInBackground(String... params) {
Bitmap bitmap = null;
try {
ThumbnailUtils tu = new ThumbnailUtils();
bitmap = tu.createVideoThumbnail(params[0],
Thumbnails.MICRO_KIND);
System.out.println("111111path: " + path + " bitmap: "
+ bitmap);
if (bitmap == null) {
bitmap = android.graphics.BitmapFactory.decodeResource(
MainActivity.mainActivity.getResources(),
R.drawable.btn_audio_play);
System.out.println("5555555path: " + path + " bitmap: "
+ bitmap);
}
// //直接对Bitmap进行缩略操作,最后一个参数定义为OPTIONS_RECYCLE_INPUT ,来回收资源
Bitmap bitmap2 = tu.extractThumbnail(bitmap, 50, 50,
ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
System.out.println("path: " + path + "bitmap2: " + bitmap2);
// 加入缓存中
if (getVideoThumbToCache(params[0]) == null) {
addVideoThumbToCache(path, bitmap2);
}
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
if (imgView.getTag().equals(path)) {// 通过 Tag可以绑定 图片地址和
// imageView,这是解决Listview加载图片错位的解决办法之一
imgView.setImageBitmap(bitmap);
}
}
}
}
bitmap = tu.createVideoThumbnail(params[0],Thumbnails.MICRO_KIND);
if (bitmap == null) {
bitmap = android.graphics.BitmapFactory.decodeResource(
MainActivity.mainActivity.getResources(),
R.drawable.btn_audio_play);
System.out.println("5555555path: " + path + " bitmap: "
+ bitmap);
}
至此,视频缩略图可以完美的展示于ListView中,不卡顿,不重复,不乱跳,并加入异步加载 和 缓存机制, 在加上一个绑定TAG机制。