Monitor项目开发走过的路~子线程Toast全解析

来源:互联网 发布:重庆专业u盘数据恢复 编辑:程序博客网 时间:2024/06/07 07:33

  Toast在Android开发中是很常用的,可以很便捷清楚的反映给用户一些重要的实时信息。在Monitor项目开发中在Toast的使用上也是遇到了一些问题。平时最经常用的方法就是在Activity中调用Toast.makeText().show()方法,我们需要传入当前的上下文环境,通常传入当前的Activity.this即可。可是项目中与服务器端交互的代码是我们后端开发人员写的,他让我将里面的日志都用Toast显示出来。因为是在一个非Activity的类里面,也就没有办法传入Context变量。最后想到了看书的时候获取全局context的方法。新建一个MyApplication类

public class MyApplication extends Application{    private static Context context;    @Override    public void onCreate() {        super.onCreate();        context=getApplicationContext();    }    public static Context getContext(){        return context;    }}

  这样你就可以轻易地在项目中的任何一个地方调用MyApplication.getContext()静态方法获取全局Context

Toast.makeText(MyApplication.getContext(),"这是Toast",Toast.LENGTH_SHORT).show();

  运行程序之后抛出了下面这样的异常
这里写图片描述

  网上一番搜寻之后找到了问题所在,因为我的Toast是在一个自己创建的子线程中运行的,子线程在默认情况下并没有一个消息循环loop与它们相关联。looper是用来给线程处理消息用的,线程默认情况下没有looper对象,也就是线程中的消息不会被处理,自然将消息直接丢在线程中的时候是不会被处理的。必须在线程中创建一个Looper实例。主线程在创建的时候就直接绑定初始化了一个looper对象,所以我们平时在主线程使用Toast是没有问题的。所以子线程中使用Toast要加入下面两行代码创建Looper并使它运行起来处理子线程的消息循环。

Looper.prepare();Toast.makeText(MyApplication.getContext(),"下载成功",Toast.LENGTH_SHORT).show();Looper.loop();

  这样一来就可以在子线程中正常使用Toast了,但是千万别以为这样就万事东风了,我在Monitor项目中有非常多的地方要使用Toast,于是乎就把所有使用的地方都创建一个Looper。果不其然Bug就出现了,这个问题很难发现,在多次运行应用后偶尔会出现闪退的情况。思前想后也是没有找的问题的根源。于是手机USB调试一直放在那里等待Bug的出现。真的是等到花儿也谢了,终于看到了打印出两句日志

11-24 15:13:26.188 23853-2029/com.qinlong275.android.monitor A/    Looper: Could not create epoll instance: Too many open files11-24 15:13:26.188 23853-23853/com.qinlong275.android.monitor E/    art: ashmem_create_region failed for 'indirect ref table': Too many              open files

  网上查了一下说这个应该是创建了太多Looper的原因,果然是由于我每个Toast都新创建了一个Toast造成的。于是想到可以将每个子线程的Toast操作交给主线程来运行,主线程有默认的Looper 循环消息,以及对应的Handler来处理消息任务。

public class ConnectActivity extends SingleFragmentActivity {    //在一些类中的子线程中使用Toast,可以发到这个主线程的Handler解决,防止子线程Loop太多带来的各种问题    public static Handler mHandler=new Handler(){        @Override        public void handleMessage(Message msg) {            String str=(String)msg.obj;            Toast.makeText(MyApplication.getContext(),str,Toast.LENGTH_SHORT).show();        }    };    @Override    protected Fragment createFragment() {        return ConnectFragment.newInstance();    }}

  我在项目的第一个Activity中创建了一个Handler来处理主线程的消息,在public void handleMessage(Message msg){}方法中来处理子线程Toast.并将这个Handler设置为静态成员,这样便可以在任何一个地方来使用。好了处理消息机制搭建好了,就可以在应用端向主线程发消息了。

Message msg=new Message();msg.obj="升级出现错误";ConnectActivity.mHandler.sendMessage(msg);msg=null;

  这样就可以将子线程Toast任务交给主线程来处理,就解决了之前的所有问题。

原创粉丝点击