• 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();
        }
    }
  • 相关阅读:
    CentOS8下升级Python3.6到3.9
    web service基础知识
    mysql+centos7+主从复制
    saltstack高效运维
    Docker
    python如何配置virtualenv
    Python操作 RabbitMQ、Redis、Memcache、SQLAlchemy
    nginx+uWSGI+django+virtualenv+supervisor发布web服务器
    RabbitMQ消息队列-Centos7下安装RabbitMQ3.6.1
    flask-wtforms
  • 原文地址:https://www.cnblogs.com/qlky/p/5657924.html
Copyright © 2020-2023  润新知