Handler与Looper引起的故事

先看看一段代码:

new Thread(new Runnable() {  

            public void run() {  

                Handler handler = new Handler(){  

                    @Override  

                    public void handleMessage(Message msg) {  

                        Toast.makeText(getApplicationContext(), "handler msg", Toast.LENGTH_LONG).show();  

                    }  

                };  

                handler.sendEmptyMessage(1);  

            };  

        }).start();  

很遗憾,上面的代码会报错:
AndroidRuntime(2545): java.lang.RuntimeException: Can’t create handler inside thread that has not called Looper.prepare()
在看看这Log是在源码的什么地方打印的

/**
     * Default constructor associates this handler with the queue for the
     * current thread.
     *
     * If there isn't one, this handler won't be able to receive messages.
     */
    public Handler() {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

        mLooper = Looper.myLooper();
        if (mLooper == null) { //当mLooper为null时就会报这个异常
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = null;
    }

这下我们知道了,在mLooper == null时就会报错,所以需要looper.prepare().
正确的代码写法:

new Thread(new Runnable() {  

            public void run() {  

                Looper.prepare();  

                Handler handler = new Handler(){  

                    @Override  

                    public void handleMessage(Message msg) {  

                        Toast.makeText(getApplicationContext(), "handler msg", Toast.LENGTH_LONG).show();  

                    }  

                };  

                handler.sendEmptyMessage(1);  

                Looper.loop();  

            };  

        }).start();  

可能你会有一个疑问,问什么在UI线程中就不需要Looper.prepare(); Looper.loop();
其实UI线程也是一个线程,在主线程–>prepareMainLooper()(内部调用prepare() ,去实例化Looper,Looper实例化同时创建了messagequeue,一一对应关系)–>主线程中的handler获取当前线程的Looper–>三者关联
所以在UI线程中我们不需要调用Looper.prepare(); Looper.loop();

如果还是不想写Looper.prepare(); Looper.loop(); 那么推荐一个类HandlerThread,查看源码会发现内部已经实现了Looper.prepare(); Looper.loop();

常用api

 //消息
    Message message = Message.obtain();
    //发送消息
        new Handler().sendMessage(message);
    //延时1s发送消息
        new Handler().sendMessageDelayed(message, 1000);
    //发送带标记的消息(内部创建了message,并设置msg.what = 0x1)
        new Handler().sendEmptyMessage(0x1);
    //延时1s发送带标记的消息
        new Handler().sendEmptyMessageDelayed(0x1, 1000);
    //延时1秒发送消息(第二个参数为:相对系统开机时间的绝对时间,而SystemClock.uptimeMillis()是当前开机时间)
        new Handler().sendMessageAtTime(message, SystemClock.uptimeMillis() + 1000);
 
    //避免内存泄露的方法:
    //移除标记为0x1的消息
        new Handler().removeMessages(0x1);
    //移除回调的消息
        new Handler().removeCallbacks(Runnable);
    //移除回调和所有message
        new Handler().removeCallbacksAndMessages(null);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值