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