Thread,Runnable,Handler,HandlerThread探索总结

本文探讨了Android中Thread, Runnable, Handler以及HandlerThread的使用。解释了为什么在Thread中需要调用Looper.prepare(),并指出在Thread中创建的Handler无法直接修改UI线程,因为它的消息队列由非主线程的Looper处理。HandlerThread则提供了在其他线程中操作UI线程的方法。同时,提到了相关Android官方文档和开发者博客作为参考资料。" 136999833,17165779,AGI自主交互:NLP、语音识别与计算机视觉的融合,"['人工智能', '深度学习', '自然语言处理', '语音识别', '计算机视觉']

Thread,Runnable,Handler,Handler.Callback,Looper,MessageQueue,HandlerThread

新线程的开启:

new Thread(new Runnable() {
    @Override
    public void run(){
        //异步执行
    }
}).start();
②
class MyThread extends Thread {
    @Override
    public void run(){
        //异步执行
    }
}
new MyThread().start();
③
class MyRunnable implements Runnable {
    @Overrid
    public void run(){
        //异步执行
    }
}
new Thread(new MyRunnable()).start();

Runnable:
Runnable

按抠脚的英语理解的是,Runnable接口被实现后,必须要用Thread类开启线程,Runnable的设计理念是提供一个公共的方法执行内容。Runnable不一定要用new Thread()的方法来实例化Runnable,也可以用继承Thread来重写run()方法。

Handler

class MyThread extends Thread {
    private Handler myHandler;
    @Override
    public void run() {
        Looper.prepare();//要在线程中实例化Handler,就必须调用该方法
        myHandler = new Handler();
        //异步执行
        //在最后还要执行Looper.loop();不然消息是不会发送到消息队列中的
        myHandler.post(new Runnbale() {
            @Overrid
            public void run(){
                //属于异步线程
            }
        });
    }
}
②
Handler handler = new Handler(){...};
class MyThread = new Thread(){...}

这时候其实挺疑惑为什么在Thread中一定要调用Looper.prepare();可以先看下构造函数,然后看看源码。
Handler构造函数
Handler.Callback是可以重写Handler类中的handlerMessage()方法。
可知道只要是不传Looper对象的构造参数,
没有参数的Handler构造函数

传Callback的Handler构造函数
最终都是走到以下这个方法:

public Handler(Callback callback, boolean async) {
        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) {
            throw new RuntimeException("Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

在这行中mLooper = Looper.myLooper()中,可以看到看到,当mLooper==null的时候,会报当前线程没有调用Looper.prepare(),而在Looper.prepare,Looper.prepare()中看下面:

public static @Nullable Looper myLooper() {
        return sThreadLocal.get(); // 获取线程Looper
}

public static void prepare() {
        prepare(true);
    }

private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed)); // prepare是会实例化一个新的Looper
    }

从以上就知道为什么要调用Looper.prepare()了。而在Activity中的实例化Handler却不需要的原因的是在ActivityThread中已经调用了Looper.prepareMainLooper();
所以这里要注意的地方就是,在Thread中实例化的Handler是不能修改UI线程了。因为它的消息队列被异步线程的Looper轮询了,而不是MainLooper轮询的。看了Handler.post()和View.post()的代码就知道为什么不行了。

// Handler.post只是调用的sendMessageDelayed.其调用的是异步线程的消息队列
public final boolean post(Runnable r){
    return  sendMessageDelayed(getPostMessage(r), 0);
}
//--- 分割线 ---
public boolean post(Runnable action) {
   final AttachInfo attachInfo = mAttachInfo;
   if (attachInfo != null) {
       return attachInfo.mHandler.post(action);
   }
   // Assume that post will succeed later
   ViewRootImpl.getRunQueue().post(action);
   return true;
}
/**
  * A Handler supplied by a view's {@link android.view.ViewRootImpl}. This
  * handler can be used to pump events in the UI events queue.
  */
final Handler mHandler;

而AttachInfo看源码注释就是A set of information given to a view when it is attached to its parent window.获取的其父类窗口的一些属性。mHandler其实就是父类MainThread的消息队列的Handler。

HandlerThread:

HandlerThread handlerThread = new HandlerThread("myHandlerThread");
handlerThread.start();
Handler asyncHandler = new Handler(handlerThread.getLooper());
Handler uiHandler = new Handler();
asyncHandler.post(new Runnable(){
    @Override
    public void run(){
        // 异步
        uiHandler.post(new Runnbale(){
            // ui线程
        })
    }
});
/*HandlerThread开启的线程后。声明asyncHandler的时候将HandlerThread的Looper赋给asyncHandler,那么asyncHandler post的就是一个异步的的Runnable.
而uiHandler没有的到HandlerLooper,所以是MainActivity的Looper,属于Ui线程。*/
②
Handler uiHandler = new Handler() {
    @Override
    public void handleMessage() {...}
}
asyncHandler.post(new Runnable(){
    @Override
    public void run(){
        // 异步
        uiHandler.sendMessage(...);
    }
});

Android提供的在其它线程操作UI线程的方法:

①Activity.runOnUiThread(Runnable)
②View.post(Runnable)
③View.postDelayed(Runnable, long)

相关查阅资料:
http://blog.youkuaiyun.com/guolin_blog/article/details/9991569
https://developer.android.com/reference/android/os/Handler.html
https://developer.android.com/reference/java/lang/Runnable.html
https://developer.android.com/reference/java/lang/Thread.html
https://developer.android.com/reference/android/os/Looper.html
在其它线程访问UI线程:
https://developer.android.com/guide/components/processes-and-threads.html
https://developer.android.com/training/multiple-threads/communicate-ui.html#Handler

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值