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

  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 files
11-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任务交给主线程来处理,就解决了之前的所有问题。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值