美文网首页Android开发经验谈Android技术知识
关于Runnable是否会新开线程的问题

关于Runnable是否会新开线程的问题

作者: _Justin | 来源:发表于2018-08-07 16:54 被阅读2次

首先,我们这里先给出一个结论.

extends Thread一定新开一个线程,但Runnable不一定新开线程(所谓新开线程,指非UI线程)

  • 如果是implements Runnable,像extends Thread一样,是新开了线程。

  • 如果是匿名Runnable对象new Runnable() {...},是把Runnable对象以Message形式post到UI线程的Looper里执行。

1、Runnable 并不一定是新开一个线程,比如下面的调用方法就是运行在UI主线程中的:

Handler mHandler = new Handler();
mHandler.post(new Runnable(){
    @Override
    public void run() {
        // TODO Auto-generated method stub
    }
});

官方对这个方法的解释如下,注意其中的:“The runnable will be run on the user interface thread. ”

我们可以通过调用handler的post方法,把Runnable对象(一般是Runnable的子类)传过去;handler会在looper中调用这个Runnable的Run方法执行。

mHandler.post(new Runnable(){......}) 好像是new 了一个 interface, 其实是new的一个实现Runnable的匿名内部类(Inner Anonymous Class),这是很简练的写法!

上面的代码可以看成是: new anonymousClass() implement Runnable{......}

Runnable是一个接口,不是一个线程,一般要开线程的类会implements Runnable。

所以:

如果我们使用匿名内部类,则是运行在UI主线程的;

如果我们使用implements这个Runnable接口的线程类,则是运行在另一个新线程的。

2、View也可以post一个Runnable对象到UI线程你去执行:

View.post(Runnable)

boolean android.view.View.post(Runnable action)

Causes the Runnable to be added to the message queue. The runnable will be run on the user interface thread.

Parameters:
action The Runnable that will be executed.
Returns:
Returns true if the Runnable was successfully placed in to the message queue. Returns false on failure, usually because the looper processing the message queue is exiting.

这里我们可以看下源码:
View的Post方法:

public boolean post(Runnable action) {
        final AttachInfo attachInfo = mAttachInfo;
        if (attachInfo != null) {
            //获得当前线程的Handler
            return attachInfo.mHandler.post(action);
        }

        // Postpone the runnable until we know on which thread it needs to run.
        // Assume that the runnable will be successfully placed after attach.
        getRunQueue().post(action);
        return true;
    }

接下来转到Handler的post方法中:

public final boolean post(Runnable r){
    //getPostMessage(r)将runnable封装进message中
    return  sendMessageDelayed(getPostMessage(r), 0);
}
    
private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

public final boolean sendMessageDelayed(Message msg, long delayMillis){
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

具体来说,View.post(Runnable)这个函数的工作原理如下:

在post(Runnable action)方法里,View获得当前线程(即UI线程)的Handler,然后将action对象post到Handler里。在Handler里,它将传递过来的action对象包装成一个Message(Message的callback为action,即通过Message可以回调action),然后将其投入UI线程的消息循环中。

在Handler再次处理该Message时,当msg.callback != null时,会调用handleCallback(msg),从而调用到runnable的run方法。而此时,已经路由到UI线程里,因此,我们可以在这个Runnable action里毫无顾虑的来更新UI,比如调用findViewById或者TextView.setText等。

如下图,前面看到的代码,我们这里Message的callback为一个Runnable的匿名内部类


image

这种情况下,由于不是在新的线程中使用,而是在UI线程,所以千万别做复杂的计算逻辑。

相关文章

网友评论

    本文标题:关于Runnable是否会新开线程的问题

    本文链接:https://www.haomeiwen.com/subject/zkyavftx.html