Android:应用程序可能在其主线程上做了太多的工作

Android:应用程序可能在其主线程上做了太多的工作,android,multithreading,listview,gridview,Android,Multithreading,Listview,Gridview,我正在尝试将视频缩略图从url加载到网格视图中。一切正常,但我收到一条消息“/Choreographer:跳过了46帧!应用程序可能在其主线程上做了太多工作。” 我知道这与主线程中的缩略图加载有关,但我不知道如何解决这个问题 我也在用一个设备来测试 public class ThumbAdapter extends ArrayAdapter<Videos> { Context context; int ressource; ThumbAdapter_Hol

我正在尝试将视频缩略图从url加载到网格视图中。一切正常,但我收到一条消息“/Choreographer:跳过了46帧!应用程序可能在其主线程上做了太多工作。”

我知道这与主线程中的缩略图加载有关,但我不知道如何解决这个问题

我也在用一个设备来测试

public class ThumbAdapter  extends ArrayAdapter<Videos> {

    Context context;
    int ressource;
    ThumbAdapter_Holder holder=new ThumbAdapter_Holder();

    public ThumbAdapter(Context context, int resource, ArrayList<Videos> videoList) {
        super(context, resource, videoList);
        this.context=context;
        this.ressource=resource;

    }


    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        View view=convertView;
        if (view==null){

            LayoutInflater inflater = (LayoutInflater) context.getSystemService(context.LAYOUT_INFLATER_SERVICE);
            view = inflater.inflate(ressource,parent,false);

            holder.video_thum = (ImageView) view.findViewById(R.id.video_thum);

            view.setTag(holder);
        }
        else {
            holder=(ThumbAdapter_Holder) view.getTag();
        }

        try {
            holder.video_thum.setImageBitmap(retriveVideoFrameFromVideo(getItem(position).getURL()));
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }

        return view;
    }


    class ThumbAdapter_Holder{
       ImageView video_thum ;

    }

    public static Bitmap retriveVideoFrameFromVideo(String videoPath) throws Throwable {
        Bitmap bitmap = null;
        MediaMetadataRetriever mediaMetadataRetriever = null;
        try
        {
            mediaMetadataRetriever = new MediaMetadataRetriever();
            if (Build.VERSION.SDK_INT >= 14)
                mediaMetadataRetriever.setDataSource(videoPath, new HashMap<String, String>());
            else
                mediaMetadataRetriever.setDataSource(videoPath);
            //   mediaMetadataRetriever.setDataSource(videoPath);
            bitmap = mediaMetadataRetriever.getFrameAtTime();
        }
        catch (Exception e)
        {
            e.printStackTrace();
            throw new Throwable(
                    "Exception in retriveVideoFrameFromVideo(String videoPath)"
                            + e.getMessage());

        } finally {
            if (mediaMetadataRetriever != null) {
                mediaMetadataRetriever.release();
            }
        }
        return bitmap;
    }
}
公共类ThumbAdapter扩展了ArrayAdapter{
语境;
内部资源;
拇指适配器固定器=新拇指适配器固定器();
公共ThumbAdapter(上下文上下文、int资源、ArrayList视频列表){
超级(上下文、资源、视频列表);
this.context=context;
this.ressource=资源;
}
@凌驾
公共视图getView(int位置、视图转换视图、视图组父视图){
视图=转换视图;
如果(视图==null){
LayoutFlater充气器=(LayoutFlater)context.getSystemService(context.LAYOUT\u充气器\u服务);
视图=充气机。充气(ressource,parent,false);
holder.video\u thum=(ImageView)view.findViewById(R.id.video\u thum);
视图.设置标签(支架);
}
否则{
holder=(ThumbAdapter_holder)视图.getTag();
}
试一试{
holder.video_thum.setImageBitmap(从视频检索视频帧)(getItem(position.getURL());
}捕捉(可抛可抛){
printStackTrace();
}
返回视图;
}
类指形夹持器{
ImageView视频;
}
公共静态位图RetrieveVideoFrameFromVideo(字符串视频路径)抛出可丢弃{
位图=空;
MediaMetadataRetriever MediaMetadataRetriever=null;
尝试
{
mediaMetadataRetriever=新的mediaMetadataRetriever();
如果(Build.VERSION.SDK_INT>=14)
setDataSource(videoPath,newhashmap());
其他的
mediaMetadataRetriever.setDataSource(videoPath);
//mediaMetadataRetriever.setDataSource(videoPath);
位图=mediaMetadataRetriever.getFrameAtTime();
}
捕获(例外e)
{
e、 printStackTrace();
扔新的一次性垃圾(
“RetrieveVideoFrameFromVideo(字符串视频路径)中出现异常”
+e.getMessage());
}最后{
if(mediaMetadataRetriever!=null){
mediaMetadataRetriever.release();
}
}
返回位图;
}
}

问题是,您正在适配器的每个单元中请求和处理数据

try {
        holder.video_thum.setImageBitmap(retriveVideoFrameFromVideo(getItem(position).getURL()));
    } catch (Throwable throwable) {
        throwable.printStackTrace();
    }
这就是罪魁祸首。您正在主线程(管理UI的线程)内执行一项昂贵的非图形化任务。为了优化,您需要将此类操作移动到单独的线程,并将结果通知在主线程内执行的类,以便它可以更新UI。有几种方法可以做到这一点:异步任务、观察者、事件总线。为了简单起见,让我们开始一个异步任务

以此为例:

public class BitMapTask extends AsyncTask<Void, Void, Bitmap> {

public interface OnBitmapLoaded{
    void loadBitmap(Bitmap bitmap);
}

private OnBitmapLoaded bitmapLoaded;
private String url;

public BitMapTask(String url){
    this.url = url;
}

public BitMapTask setBitMapLoaded(OnBitmapLoaded bitMapLoaded){
    this.bitmapLoaded = bitMapLoaded;
    return this;
}

@Override
protected Bitmap doInBackground(Void... params) {
    return retriveVideoFrameFromVideo(url);
}

@Override
protected void onPostExecute(Bitmap result){
    if(bitmapLoaded != null) bitmapLoaded.loadBitmap(result);
}
}

请记住,这种操作将忽略主线程状态;这意味着,即使应用程序处于休眠状态,单独的线程也将继续运行和执行,因此,如果应用程序转到前台,您需要使侦听器/取消订阅接收器无效。愉快的编码。

问题是,您正在适配器的每个单元中请求和处理数据

try {
        holder.video_thum.setImageBitmap(retriveVideoFrameFromVideo(getItem(position).getURL()));
    } catch (Throwable throwable) {
        throwable.printStackTrace();
    }
这就是罪魁祸首。您正在主线程(管理UI的线程)内执行一项昂贵的非图形化任务。为了优化,您需要将此类操作移动到单独的线程,并将结果通知在主线程内执行的类,以便它可以更新UI。有几种方法可以做到这一点:异步任务、观察者、事件总线。为了简单起见,让我们开始一个异步任务

以此为例:

public class BitMapTask extends AsyncTask<Void, Void, Bitmap> {

public interface OnBitmapLoaded{
    void loadBitmap(Bitmap bitmap);
}

private OnBitmapLoaded bitmapLoaded;
private String url;

public BitMapTask(String url){
    this.url = url;
}

public BitMapTask setBitMapLoaded(OnBitmapLoaded bitMapLoaded){
    this.bitmapLoaded = bitMapLoaded;
    return this;
}

@Override
protected Bitmap doInBackground(Void... params) {
    return retriveVideoFrameFromVideo(url);
}

@Override
protected void onPostExecute(Bitmap result){
    if(bitmapLoaded != null) bitmapLoaded.loadBitmap(result);
}
}

请记住,这种操作将忽略主线程状态;这意味着,即使应用程序处于休眠状态,单独的线程也将继续运行和执行,因此,如果应用程序转到前台,您需要使侦听器/取消订阅接收器无效。愉快的编码。

显然对
mediaMetadataRetriever
的一个调用很耗时,请考虑将此操作移动到工作线程。您可以将整个retrieveVideFrameFromVideo包装在“如何实现异步任务”中。显然对
mediaMetadataRetriever
的一个调用很耗时,考虑将此操作移动到工作线程。您可以将整个retrieveVideFrameFromVideo包装在“环顾四周”中,了解如何实现异步任务