[英]Android : The application may be doing too much work on its main thread
I'm trying to load a video thumbnail from url into a grid view. 我正在尝试将视频缩略图从url加载到网格视图中。 Everything works fine, but I'm getting this message "/Choreographer: Skipped 46 frames! The application may be doing too much work on its main thread." 一切正常,但我收到此消息:“ /编排:跳过46帧!该应用程序可能在其主线程上做太多工作。”
I know it has something to do with the thumbnail loading in the main thread, but I couldn't find out how to fix this. 我知道这与主线程中的缩略图加载有关,但是我找不到解决方法。
I'm also using a device to test. 我也在使用一种设备进行测试。
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;
}
}
The problem is, you are requesting and processing data in each cell of your adapter. 问题是,您正在请求和处理适配器的每个单元中的数据。
try {
holder.video_thum.setImageBitmap(retriveVideoFrameFromVideo(getItem(position).getURL()));
} catch (Throwable throwable) {
throwable.printStackTrace();
}
that's the culprit. 那是元凶。 You are doing an expensive, non graphical task inside the main thread (the one managing the UI). 您正在主线程(管理UI的任务)内执行一项昂贵的非图形任务。 In order to optimize, you need to move that kind of operation to separate threads, and notify a class executing inside the main thread the results so it can update the UI. 为了进行优化,您需要将这种操作移到单独的线程中,并将结果通知给在主线程中执行的类,以便它可以更新UI。 There are several ways to do this: Asynctasks, Observers, Event buses. 有几种方法可以做到这一点:异步任务,观察者,事件总线。 For the sake of simplicity, let's go with an asynctask. 为了简单起见,让我们使用asynctask。
take this as an example: 以这个为例:
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);
}
}
then, instead of the try-catch, you should do something like this: 然后,您应该执行以下操作,而不是尝试捕获:
BitMapTask task = new BitMapTask(getItem(position).getURL())
.setBitMapLoaded(new OnBitmapLoaded() {
@Override
public void loadBitmap(Bitmap bitmap) {
if(bitmap != null){
setImageBitmap(bitmap);
}
}
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
Keep in mind, this kind of operation will ignore the main thread status; 请记住,这种操作将忽略主线程状态; that means, the separate threads will keep running and executing even if the app is dormant, therefore, you need to void the listeners/unsubscribe receivers if the app goes to the foreground. 这意味着即使应用程序处于休眠状态,单独的线程也将继续运行并执行,因此,如果应用程序进入前台,则需要使侦听器/取消订阅接收器无效。 Happy coding. 快乐的编码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.