Android-多线程Handler

http://www.cnblogs.com/plokmju/p/android_Handler.html

 

android不允许在主线程里做耗时操作,如网络操作,以此来避免ANR

 

ANR(Application Not Responding)

http://baike.baidu.com/link?url=rLzKRNkjt79XITQKhRXp32alhsuKEt2FoHPw3vuB2UlEvyKOZwnEh4OYoPy4_fwO6zPPECXWre4ycip4mB0LOq

Activity应该在它的关键生命周期方法(如onCreate()和onResume())里尽可能少的去做创建操作。潜在的耗时操作,例如网络或数据库操作,或者高耗时的计算如改变位图尺寸,应该在子线程里(或者以数据库操作为例,通过异步请求的方式)来完成。

默认情况下,在android中Activity的最长执行时间是5秒,BroadcastReceiver的最长执行时间则是10秒。

 

因此如果想进行上述的操作,应该开启一个子线程。而在子线程中,android不允许进行UI操作。如果想在子线程中进行UI操作,就可以使用Handler开启UI线程。

 

Handler,它直接继承自Object,一个Handler允许发送和处理Message或者Runnable对象,并且会关联到主线程的MessageQueue中。每个Handler具有一个单独的线程,并且关联到一个消息队列的线程,就是说一个Handler有一个固有的消息队列。当实例化一个Handler的时候,它就承载在一个线程和消息队列的线程,这个Handler可以把Message或Runnable压入到消息队列,并且从消息队列中取出Message或Runnable,进而操作它们。

 

由上可知,Handler有两种用法:

  • Post:Post允许把一个Runnable对象入队到消息队列中。它的方法有:post(Runnable)、postAtTime(Runnable,long)、postDelayed(Runnable,long)。
  • sendMessage:sendMessage允许把一个包含消息数据的Message对象压入到消息队列中。它的方法有:sendEmptyMessage(int)、sendMessage(Message)、sendMessageAtTime(Message,long)、sendMessageDelayed(Message,long)。

 

具体用法可以看第一个链接的文章

 

http://blog.csdn.net/gh102/article/details/7191486

这边对post的使用更加清晰一点

 

Post和message区别:

http://blog.csdn.net/u013168615/article/details/47024073

 

从源码中可以看出,post是调用了sendMessageDelayed方法:

public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }

而其中的getPostMessage则是把Runnable r 包装成一个空Message然后返回,并将m的callback设为r

private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
}

在handler源码里,则是调用了dispatchMessage(Message msg)的第一种方法,handleCallback()

public void dispatchMessage(Message msg) {  
    if (msg.callback != null) {  
        handleCallback(msg);  
    } else {  
        if (mCallback != null) {  
            if (mCallback.handleMessage(msg)) {  
                return;  
            }  
        }  
        handleMessage(msg);  
    }  
}  

而handleCallback()源码:

private final void handleCallback(Message message) {  
    message.callback.run();  
}  

就是直接调用了一开始传入的Runnable对象的run()方法

 

所以post方法也可以这样写:

public class MainActivity extends Activity {  
  
    private Handler handler;  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        handler = new Handler();  
        new Thread(new Runnable() {  
            @Override  
            public void run() {  
                handler.post(new Runnable() {  
                    @Override  
                    public void run() {  
                        // 在这里进行UI操作  
                    }  
                });  
            }  
        }).start();  
    }  
} 

我们在Runnable对象的run()方法里更新UI,效果完全等同于在handleMessage()方法中更新UI。

所以post和message没有本质区别,只是用法不同而已

handler.post和handler.sendMessage本质上是没有区别的,都是发送一个消息到消息队列中,而且消息队列和handler都是依赖于同一个线程的。

 

Handler源码解析:

http://blog.csdn.net/guolin_blog/article/details/9991569

 

由源码可知:

1.子线程里创建handler:

  new handler对象时一定要有一个Looper,而每个线程只有一个Looper,主线程的Looper在main函数里已经自动调用prepare方法创建了。如果我们想在子线程new handler,必须先调用Looper.prepare()方法

 

2.Handler到底是把Message发送到哪里去了呢?为什么之后又可以在Handler的handleMessage()方法中重新得到这条Message呢?

  • 首先handler每个发送消息的方法,实际上都是调用到了sendMessageAtTime(Message msg, long uptimeMillis)这个方法
  • sendMessageAtTime(Message msg, long uptimeMillis)方法通过enqueueMessage(Message msg, long when)将消息压入消息队列,并设置发送消息的时间
  • enqueueMessage(Message msg, long when)里定义里入队操作
  • MessageQueue并没有使用一个集合把所有的消息都保存起来,它只使用了一个mMessages对象表示当前待处理的消息。然后观察上面的代码的16~31行我们就可以看出,所谓的入队其实就是将所有的消息按时间来进行排序,这个时间当然就是我们刚才介绍的uptimeMillis参数。具体的操作方法就根据时间的顺序调用msg.next,从而为每一个消息指定它的下一个消息是什么。当然如果你是通过sendMessageAtFrontOfQueue()方法来发送消息的,它也会调用enqueueMessage()来让消息入队,只不过时间为0,这时会把mMessages赋值为新入队的这条消息,然后将这条消息的next指定为刚才的mMessages,这样也就完成了添加消息到队列头部的操作。
  • 出队操作在Looper.loop()方法里完成
  • 如果当前MessageQueue中存在mMessages(即待处理消息),就将这个消息出队,然后让下一条消息成为mMessages,否则就进入一个阻塞状态,一直等到有新的消息入队。继续看loop()方法的第14行,每当有一个消息出队,就将它传递到msg.target的dispatchMessage()方法中,那这里msg.target又是什么呢?其实就是Handler啦
  • dispatchMessage()调用handleMessage()方法


整个异步消息处理流程的示意图如下图所示:

 

 

UI线程和子线程在使用中可以这么封装:

public class ThreadUtils {

    /**
     * 运行在子线程(发送数据)
     * 
     * @param r
     */
    public static void runInSubThread(Runnable r) {
        new Thread(r).start();
    }

    private static Handler handler = new Handler();

    /**
     * 运行在主线程(UI 线程 更新界面)
     * 
     * @param r
     */
    public static void runInUiThread(Runnable r) {
        handler.post(r);// Message-->handler.sendMessage-->handleMessage()
                        // 主线程-->r.run();
    }
}

 

转载于:https://www.cnblogs.com/qlky/p/5657924.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值