handler 订阅
Handler主要用于异步消息的处理:当发出一个消息之后,首先进入一个消息队列,发送消息的函数即刻返回,而另外一个部分在消息队列中逐一将消息取出,然后对消息进行处理,也就是发送消息和接收消息不是同步的处理。 这种机制通常用来处理相对耗时比较长的操作。 展开全文
Handler主要用于异步消息的处理:当发出一个消息之后,首先进入一个消息队列,发送消息的函数即刻返回,而另外一个部分在消息队列中逐一将消息取出,然后对消息进行处理,也就是发送消息和接收消息不是同步的处理。 这种机制通常用来处理相对耗时比较长的操作。
信息
领    域
计算机编程
通常用途
处理相对耗时比较长的操作
应    用
异步消息处理
外文名
handler
handler特点
1. 传递Message。用于接受子线程发送的数据, 并用此数据配合主线程更新UI。在Android中,对于UI的操作通常需要放在主线程中进行操作。如果在子线程中有关于UI的操作,那么就需要把数据消息作为一个Message对象发送到消息队列中,然后,由Handler中的handlerMessage方法处理传过来的数据信息,并操作UI。当然,Handler对象是在主线程中初始化的,因为它需要绑定在主线程的消息队列中。类sendMessage(Message msg)方法实现发送消息的操作。 在初始化Handler对象时重写的handleMessage方法来接收Message并进行相关操作。2. 传递Runnable对象。用于通过Handler绑定的消息队列,安排不同操作的执行顺序。Handler对象在进行初始化的时候,会默认的自动绑定消息队列。利用类post方法,可以将Runnable对象发送到消息队列中,按照队列的机制按顺序执行不同的Runnable对象中的run方法。 [1] 
收起全文
精华内容
下载资源
问答
  • Handler

    千次阅读 2018-07-30 19:24:10
    Handler:作用就是发送与处理信息,如果希望Handle正常工作,在当前线程中要有一个Looper对象 Message:Handle接收与处理的消息对象 MessageQueue:消息队列,先进先出管理Message,在初始化Looper...

    这里写图片描述

    子线程与UI主线程的通信在android中使用了消息机制来完成
    消息处理机制本质:一个线程开启循环模式持续监听并依次处理其他线程给它发的消息

    Handler类的主要作用有两个:

    1.在新启动的线程中发送消息
    2.在主线程中获取,处理消息

    即Handler的作用是把消息加入特定的Looper所管理的MessageQueue中,并处理该MessageQueue中Looper分发的Message。

    一个线程只能有一个Looper,对应一个MessageQueue

    相关名词:
    UI线程:就是我们的主线程,系统在创建UI线程的时候会初始化一个Looper对象,同时也会创建一个与其关联的MessageQueue
    Handler:作用就是发送与处理信息,如果希望Handle正常工作,在当前线程中要有一个Looper对象
    Message:Handle接收与处理的消息对象
    MessageQueue:消息队列,先进先出管理Message,在初始化Looper对象时会创建一个与之关联的MessageQueue
    Looper:每个线程只能够有一个Looper,管理MessageQueue,不断地从中取出Message分发给对应的Handler处理
    这里写图片描述

    在Android应用启动时,会自动创建一个线程,即程序的主线程,主线程负责UI的展示、UI事件消息的派发处理等等,因此主线程也叫做UI线程

    如果有多个线程并发操作UI组件,就会出现线程安全问题,所以Android中制定了一个规则:在Android中只允许主线程(UI线程)修改Activity中的UI组件(子线程不允许操作主线程内的UI组件
    很多时候我们做界面刷新都需要通过Handler来通知UI组件更新
    这里写图片描述

    每个Handler都绑定了一个线程,Handler是Thread的代言人,是多线程之间通信的桥梁,通过Handler,我们可以在一个线程中控制另一个线程去做某事。

    当我们的子线程想修改Activity中的UI组件时,我们可以新建一个Handler对象,通过这个对象向主线程发送信息;而我们发送的信息会先到主线程的MessageQueue进行等待。由Looper按先入先出顺序取出,再根据message对象的what属性分发给对应的Handler进行处理

    这里写图片描述

    展开全文
  • Android Handler消息机制原理最全解读(持续补充中)

    万次阅读 多人点赞 2018-05-13 19:22:57
    Handler  在Android开发的过程中,我们常常会将耗时的一些操作放在子线程(work thread)中去执行,然后将执行的结果告诉 UI线程(main thread),熟悉Android的朋友都知道,UI的更新只能通过Main thread来...

     本文主要详细去解读Android开发中最常使用的Handler,以及使用过程中遇到的各种各样的疑问。

    Handler


     在Android开发的过程中,我们常常会将耗时的一些操作放在子线程(work thread)中去执行,然后将执行的结果告诉UI线程(main thread),熟悉Android的朋友都知道,UI的更新只能通过Main thread来进行。那么这里就涉及到了如何将
    子线程的数据传递给main thread呢?
     Android已经为我们提供了一个消息传递的机制——Handler,来帮助我们将子线程的数据传递给主线程,其实,当熟悉了Handler的原理之后我们知道,Handler不仅仅能将子线程的数据传递给主线程,它能实现任意两个线程的数据传递。
     接下来,我们便详细的了解下Handler的原理及其使用。
     首先看一下Handler最常规的使用方式:

    private Handler mHandler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                    case MESSAGE_WHAT:
                        Log.d(TAG, "main thread receiver message: " + ((String) msg.obj));
                        break;
                }
            }
        };
        
        private void sendMessageToMainThreadByWorkThread() {
            new Thread(){
                @Override
                public void run() {
                    Message message = mHandler.obtainMessage(MESSAGE_WHAT);
                    message.obj = "I am message from work thread";
                    mHandler.sendMessage(message);
                }
            }.start();
        }
        /*
        * 通常我们在主线程中创建一个Handler,
        * 然后重写该Handler的handlerMessage方法,可以看到该方法传入了一个参数Message,
        * 该参数就是我们从其他线程传递过来的信息。
        *
        * 我们在来看下子线程中如何传递的信息,子线程通过Handler的obtainMessage()方法获取到一个Message实例,
        * 我们来看看Message的几个属性:
        * Message.what------------------>用来标识信息的int值,通过该值主线程能判断出来自不同地方的信息来源
        * Message.arg1/Message.arg2----->Message初始定义的用来传递int类型值的两个变量
        * Message.obj------------------->用来传递任何实例化对象
        * 最后通过sendMessage将Message发送出去。
        *
        * Handler所在的线程通过handlerMessage方法就能收到具体的信息了,如何判断信息的来源呢?当然是通过what值啦。
        * 怎么样很简单吧
        */
    

     文章的开头说过,Handler不仅仅是能过将子线程的数据发送给主线程,它适用于任意两个线程之间的通信。
     下面我们来看下两个子线程之间如何进行通信的。
     很简单啊,在一个线程创建Handler,另外一个线程通过持有该Handler的引用调用sendMessage发送消息啊!
     写程序可不能关说不练啊,我们把代码敲出来看一下!

    private Handler handler;
        private void handlerDemoByTwoWorkThread() {
            Thread hanMeiMeiThread = new Thread() {
                @Override
                public void run() {
    //                Looper.prepare();
                    handler = new Handler() {
                        @Override
                        public void handleMessage(Message msg) {
                            Log.d(TAG, "hanMeiMei receiver message: " + ((String) msg.obj));
                            Toast.makeText(MainActivity.this, ((String) msg.obj), Toast.LENGTH_SHORT).show();
                        }
                    };
    //                Looper.loop();
                }
            };
            Thread liLeiThread = new Thread() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    Message message = handler.obtainMessage();
                    message.obj = "Hi MeiMei";
                    handler.sendMessage(message);
                }
            };
            hanMeiMeiThread.setName("韩梅梅 Thread");
            hanMeiMeiThread.start();
            liLeiThread.setName("李雷 Thread");
            liLeiThread.start();
    
            /*
            * 搞定,我们创建了两个Thread,liLeiThread和hanMeiMeiThread两个线程,很熟悉的名字啊!
            * 跟之前的代码没太大区别hanMeiMeiThread创建了Handler,liLeiThread通过Handler发送了消息。
            * 只不过此处我们只发送一个消息,所以没有使用what来进行标记
            * 运行看看,我们的李雷能拨通梅梅吗?
            * 啊哦,出错了
            * 05-13 17:08:17.709 20673-20739/? E/AndroidRuntime: FATAL EXCEPTION: 韩梅梅 Thread
                                                       Process: design.wang.com.designpatterns, PID: 20673
                                                       java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
                                                           at android.os.Handler.<init>(Handler.java:200)
                                                           at android.os.Handler.<init>(Handler.java:114)
            *Can't create handler inside thread that has not called Looper.prepare()
            * -----------》它说我们创建的handler没有调用Looper.prepare();
            * 好的,我们在实例化Handler之前调用下该方法,看一下。加上是不是没有报错了呢。
            * 等等,虽然没有报错,但是hanMeiMeiThread也没有接到消息啊,消息呢?别急。
            * 我们在Handler实例化之后加上Looper.loop();看一看,运行一下,是不是收到消息了呢。
            * 这是为什么呢?
            * 接下来我们就去看看Handler是怎么实现的发消息呢,弄清楚了原理,这里的原因也就明白了。
            */
    
        }
    

     好了,卖了半天的关子,终于要开始真正的主题了。
     首先我们来看下,为什么在子线程里实例化的时候不调用Looper.prepare()就会报错呢?

    //我们先来看看new Handler();时出错的原因。后续讲解源码分析只贴出关键部分。
    //如下是Handler构造函数里抛出上文异常的地方,可以看到,由于mLooper对象为空才抛出的该异常。
    mLooper = Looper.myLooper();
            if (mLooper == null) {
                throw new RuntimeException(
                    "Can't create handler inside thread that has not called Looper.prepare()");
            }
    /*
      异常的原因看到了,接下来我们看看Looper.prepare()方法都干了些什么?
    */
    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));
    }
    /*
     可以看到,该方法在当前thread创建了一个Looper(), ThreadLocal主要用于维护线程的本地变量,  
    */
     private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
    //而Looper的构造函数里面又为我们创建了一个MessageQueue()对象。
    

     了解到此,我们已经成功引出了Handler机制几个关键的对象了,Looper、MessageQueue、Message。
     那么,肯定也有人又产生新的疑问了——为什么在主线程中创建Handler不需要要用Looper.prepare()和Looper.loop()方法呢?
     其实不是这样的,App初始化的时候都会执行ActivityThread的main方法,我们可以看看ActivityThread的main()方法都做了什么?

            Looper.prepareMainLooper();
            ActivityThread thread = new ActivityThread();
            thread.attach(false);
            if (sMainThreadHandler == null) {
                sMainThreadHandler = thread.getHandler();
            }
            if (false) {
                Looper.myLooper().setMessageLogging(new
                        LogPrinter(Log.DEBUG, "ActivityThread"));
            }
            // End of event ActivityThreadMain.
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            Looper.loop();
    /*
     真相只有一个,是的在创建主线程的时候Android已经帮我们调用了Looper.prepareMainLooper()
     和Looper.loop()方法,所以我们在主线程能直接创建Handler使用。
    */
    

     我们接着来看Handler发送消息的过程:

    //调用Handler不同参数方法发送Message最终都会调用到该方法
    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
            MessageQueue queue = mQueue;
            if (queue == null) {
                RuntimeException e = new RuntimeException(
                        this + " sendMessageAtTime() called with no mQueue");
                Log.w("Looper", e.getMessage(), e);
                return false;
            }
            return enqueueMessage(queue, msg, uptimeMillis);
        }
    

     sendMessage的关键在于enqueueMessage(),其内部调用了messageQueue的enqueueMessage方法

    boolean enqueueMessage(Message msg, long when) {
            ...
            synchronized (this) {
                if (mQuitting) {
                    IllegalStateException e = new IllegalStateException(
                            msg.target + " sending message to a Handler on a dead thread");
                    Log.w(TAG, e.getMessage(), e);
                    msg.recycle();
                    return false;
                }
    
                msg.markInUse();
                msg.when = when;
                Message p = mMessages;
                boolean needWake;
                if (p == null || when == 0 || when < p.when) {
                    // New head, wake up the event queue if blocked.
                    msg.next = p;
                    mMessages = msg;
                    needWake = mBlocked;
                } else {
                    needWake = mBlocked && p.target == null && msg.isAsynchronous();
                    Message prev;
                    for (;;) {
                        prev = p;
                        p = p.next;
                        if (p == null || when < p.when) {
                            break;
                        }
                        if (needWake && p.isAsynchronous()) {
                            needWake = false;
                        }
                    }
                    msg.next = p; // invariant: p == prev.next
                    prev.next = msg;
                }
    
                // We can assume mPtr != 0 because mQuitting is false.
                if (needWake) {
                    nativeWake(mPtr);
                }
            }
            return true;
        }
        /*从代码可以看出Message被存入MessageQueue时是将Message存到了上一个Message.next上, 
          形成了一个链式的列表,同时也保证了Message列表的时序性。
        */
    

     Message的发送实际是放入到了Handler对应线程的MessageQueue中,那么,Message又是如何被取出来的呢?
     细心的朋友可能早早就发现了,之前抛出异常的地方讲解了半天的Loop.prepare()方法,一直没有说到Loop.loop()方法。同时,在之前的例子中也看到了,如果不调用Looper.loop()方法,Handler是接受不到消息的,所以我们可以大胆的猜测,消息的获取肯定和它脱不了关系!当然关怀疑还不行,我们还必须找出真相来证明我们的猜想?那还等什么,先看看loop()方法吧。

    public static void loop() {
    //可以看到,在调用Looper.prepare()之前是不能调用该方法的,不然又得抛出异常了
            final Looper me = myLooper();
            if (me == null) {
                throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
            }
            final MessageQueue queue = me.mQueue;
    
            // Make sure the identity of this thread is that of the local process,
            // and keep track of what that identity token actually is.
            Binder.clearCallingIdentity();
            final long ident = Binder.clearCallingIdentity();
    
            for (;;) {
                Message msg = queue.next(); // might block
                if (msg == null) {
                    // No message indicates that the message queue is quitting.
                    return;
                }
    
                // This must be in a local variable, in case a UI event sets the logger
                final Printer logging = me.mLogging;
                if (logging != null) {
                    logging.println(">>>>> Dispatching to " + msg.target + " " +
                            msg.callback + ": " + msg.what);
                }
    
                final long traceTag = me.mTraceTag;
                if (traceTag != 0) {
                    Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
                }
                try {
                    msg.target.dispatchMessage(msg);
                } finally {
                    if (traceTag != 0) {
                        Trace.traceEnd(traceTag);
                    }
                }
    
                if (logging != null) {
                    logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
                }
    
                // Make sure that during the course of dispatching the
                // identity of the thread wasn't corrupted.
                final long newIdent = Binder.clearCallingIdentity();
                if (ident != newIdent) {
                    Log.wtf(TAG, "Thread identity changed from 0x"
                            + Long.toHexString(ident) + " to 0x"
                            + Long.toHexString(newIdent) + " while dispatching to "
                            + msg.target.getClass().getName() + " "
                            + msg.callback + " what=" + msg.what);
                }
    
                msg.recycleUnchecked();
            }
        }
    /*
    这里我们看到,mLooper()方法里我们取出了,当前线程的looper对象,然后从looper对象开启了一个死循环 
    不断地从looper内的MessageQueue中取出Message,只要有Message对象,就会通过Message的target调用
    dispatchMessage去分发消息,通过代码可以看出target就是我们创建的handler。我们在继续往下分析Message的分发
    */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
    /*好了,到这里已经能看清晰了
    可以看到,如果我们设置了callback(Runnable对象)的话,则会直接调用handleCallback方法
    */
    private static void handleCallback(Message message) {
            message.callback.run();
        }
    //即,如果我们在初始化Handler的时候设置了callback(Runnable)对象,则直接调用run方法。比如我们经常写的runOnUiThread方法,由于Handler在主线程创建,所以最终得以在主线程执行:
    runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    
                }
            });
    public final void runOnUiThread(Runnable action) {
          if (Thread.currentThread() != mUiThread) {
              mHandler.post(action);
          } else {
              action.run();
          }
      }
      /*
    而如果msg.callback为空的话,
    存在一种情况,当创建Handler使用了带Callback的构造方法的话,将会执行Callback的handleMessgae方法,并且会根据其方法的返回值判断是否会被callback拦截,  
    是否需要继续执行Handle的handlMessgae方法,如果不存在Callback的拦截则Handler本身的handleMessage方法得意执行。(Handler(Callback)的构造方法使用场景暂时未遇到,欢迎补充)
      */
    

     到这里,想必你应该清楚如何在不同的线程之间来使用Handler了吧。

    最后总结一下:

    1. 在使用handler的时候,在handler所创建的线程需要维护一个唯一的Looper对象, 每个线程对应一个Looper,每个线程的Looper通过ThreadLocal来保证,如需了解ThreadLocal,点击查看详细讲解 ,
      Looper对象的内部又维护有唯一的一个MessageQueue,所以一个线程可以有多个handler,
      但是只能有一个Looper和一个MessageQueue。
    2. Message在MessageQueue不是通过一个列表来存储的,而是将传入的Message存入到了上一个
      Message的next中,在取出的时候通过顶部的Message就能按放入的顺序依次取出Message。
    3. Looper对象通过loop()方法开启了一个死循环,不断地从looper内的MessageQueue中取出Message,
      然后通过handler将消息分发传回handler所在的线程。

    最后附上一张自己理解画出来的流程图:
    这里写图片描述



    Handler补充:

    1. Handler在使用过程中,需要注意的问题之一便是内存泄漏问题。

    为什么会出现内存泄漏问题呢?
    首先Handler使用是用来进行线程间通信的,所以新开启的线程是会持有Handler引用的,
    如果在Activity等中创建Handler,并且是非静态内部类的形式,就有可能造成内存泄漏。

    1. 首先,非静态内部类是会隐式持有外部类的引用,所以当其他线程持有了该Handler,线程没有被销毁,则意味着Activity会一直被Handler持有引用而无法导致回收。
    2. 同时,MessageQueue中如果存在未处理完的Message,Message的target也是对Activity等的持有引用,也会造成内存泄漏。
    解决的办法:

     (1). 使用静态内部类+弱引用的方式:

      静态内部类不会持有外部类的的引用,当需要引用外部类相关操作时,可以通过弱引用还获取到外部类相关操作,弱引用是不会造成对象该回收回收不掉的问题,不清楚的可以查阅JAVA的几种引用方式的详细说明。

    private Handler sHandler = new TestHandler(this);
    
    static class TestHandler extends Handler {
        private WeakReference<Activity> mActivity;
        TestHandler(Activity activity) {
            mActivity = new WeakReference<>(activity);
        }
    
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            Activity activity = mActivity.get();
            if (activity != null) {
                //TODO:
            }
        }
    }
    

     (2). 在外部类对象被销毁时,将MessageQueue中的消息清空。例如,在Activity的onDestroy时将消息清空。

    @Override
    protected void onDestroy() {
        handler.removeCallbacksAndMessages(null);
        super.onDestroy();
    }
    

    2. 在使用Handler时,通常是通过Handler.obtainMessage()来获取Message对象的,而其内部调用的是Message.obtain()方法,那么问题来了,为什么不直接new一个Message,而是通过Message的静态方法obtain()来得到的呢?

    下面就通过代码来一探究竟

    public static Message obtain() {
            synchronized (sPoolSync) {
                if (sPool != null) {
                    Message m = sPool;
                    sPool = m.next;
                    m.next = null;
                    m.flags = 0; // clear in-use flag
                    sPoolSize--;
                    return m;
                }
            }
            return new Message();
        }
    

     其实在在Message中有一个static Message变量sPool,这个变量是用于缓存Message对象的,在obtain中可以看到当需要一个Message对象时,如果sPool不为空则会返回当前sPool(Message),而将sPool指向了之前sPool的next对象,(之前讲MessageQueue时讲过Message的存储是以链式的形式存储的,通过Message的next指向下一个Message,这里就是返回了sPool当前这个Message,然后sPool重新指向了其下一个Message),然后将返回的Message的next指向置为空(断开链表),sPoolSize记录了当前缓存的Message的数量,如果sPool为空,则没有缓存的Message,则需要创建一个新的Message(new Message)。
    这里写图片描述
     接着看下sPool中缓存的Message是哪里来的?

    public void recycle() {
            if (isInUse()) {
                if (gCheckRecycle) {
                    throw new IllegalStateException("This message cannot be recycled because it "
                            + "is still in use.");
                }
                return;
            }
            recycleUnchecked();
        }
    
    void recycleUnchecked() {
            // Mark the message as in use while it remains in the recycled object pool.
            // Clear out all other details.
            flags = FLAG_IN_USE;
            what = 0;
            arg1 = 0;
            arg2 = 0;
            obj = null;
            replyTo = null;
            sendingUid = -1;
            when = 0;
            target = null;
            callback = null;
            data = null;
    
            synchronized (sPoolSync) {
                if (sPoolSize < MAX_POOL_SIZE) {
                    next = sPool;
                    sPool = this;
                    sPoolSize++;
                }
            }
        }
    

     recycle()是回收Message的方法,在Message处理完或者清空Message等时会调用。
    recycleUnchecked()方法中可以看到,将what、arg1、arg2、object等都重置了值,如果当前sPool(Message缓存池)的大小小于允许缓存的Message最大数量时,将要回收的Message的next指向sPool,将sPool指向了回收的Message对象(即将Message放到了sPool缓存池的头部)
    这里写图片描述

    总结:

    由此可见,使用obtain获取Message对象是因为Message内部维护了一个数据缓存池,回收的Message不会被立马销毁,而是放入了缓存池,
    在获取Message时会先从缓存池中去获取,缓存池为null才会去创建新的Message。


    3. Handler sendMessage原理解读。

     引入问题!

    1. sendMessageDelayed是如何实现延时发送消息的?
    2. sendMessageDelayed是通过阻塞来达到了延时发送消息的结果,那么会不会阻塞新添加的Message?

    详细分析请移步下篇文章:Handler进阶之sendMessage原理探索


    欢迎提供其他有关Handler的问题分享讨论

    展开全文
  • Handler 每个初学Android开发的都绕不开Handler这个“坎”,为什么说是个坎呢,首先这是Android架构的精髓之一,其次大部分人都...今天看到Handler.post这个方法之后决定再去翻翻源代码梳理一下Handler的实现机制

    转载请注明出处http://blog.csdn.net/ly502541243/article/details/52062179

    Handler

    每个初学Android开发的都绕不开Handler这个“坎”,为什么说是个坎呢,首先这是Android架构的精髓之一,其次大部分人都是知其然却不知其所以然。今天看到Handler.post这个方法之后决定再去翻翻源代码梳理一下Handler的实现机制。

    异步更新UI

    先来一个必背口诀“主线程不做耗时操作,子线程不更新UI”,这个规定应该是初学必知的,那要怎么来解决口诀里的问题呢,这时候Handler就出现在我们面前了(AsyncTask也行,不过本质上还是对Handler的封装),来一段经典常用代码(这里忽略内存泄露问题,我们后面再说):

    首先在Activity中新建一个handler:

    private Handler mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                    case 0:
                        mTestTV.setText("This is handleMessage");//更新UI
                        break;
                }
            }
        };
    

    然后在子线程里发送消息:

    new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(1000);//在子线程有一段耗时操作,比如请求网络
                        mHandler.sendEmptyMessage(0);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
    

    至此完成了在子线程的耗时操作完成后在主线程异步更新UI,可是并没有用上标题的post,我们再来看post的版本:

    private Handler mHandler;//全局变量
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    	mHandler = new Handler();
    	new Thread(new Runnable() {
    	            @Override
    	            public void run() {
    	                try {
    	                    Thread.sleep(1000);//在子线程有一段耗时操作,比如请求网络
    	                    mHandler.post(new Runnable() {
    	                        @Override
    	                        public void run() {
    	                            mTestTV.setText("This is post");//更新UI
    	                        }
    	                    });
    	                } catch (InterruptedException e) {
    	                    e.printStackTrace();
    	                }
    	            }
    	        }).start();
    }
    

    从表面上来看,给post方法传了个Runnable,像是开了个子线程,可是在子线程里并不能更新UI啊,那么问题来了,这是怎么个情况呢?带着这个疑惑,来翻翻Handler的源码:

    先来看看普通的sendEmptyMessage是什么样子:

    public final boolean sendEmptyMessage(int what)
        {
            return sendEmptyMessageDelayed(what, 0);
        }
    
    public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
            Message msg = Message.obtain();
            msg.what = what;
            return sendMessageDelayed(msg, delayMillis);
        }
    

    将我们传入的参数封装成了一个消息,然后调用sendMessageDelayed:

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

    再调用sendMessageAtTime:

    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
            MessageQueue queue = mQueue;
            if (queue == null) {
                RuntimeException e = new RuntimeException(
                        this + " sendMessageAtTime() called with no mQueue");
                Log.w("Looper", e.getMessage(), e);
                return false;
            }
            return enqueueMessage(queue, msg, uptimeMillis);
        }
    

    好了,我们再来看post():

    public final boolean post(Runnable r)
        {
           return  sendMessageDelayed(getPostMessage(r), 0);//getPostMessage方法是两种发送消息的不同之处
        }
    

    方法只有一句,内部实现和普通的sendMessage是一样的,但是只有一点不同,那就是 getPostMessage® 这个方法:

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

    这个方法我们发现也是将我们传入的参数封装成了一个消息,只是这次是m.callback = r,刚才是msg.what=what,至于Message的这些属性就不看了

    Android消息机制

    看到这里,我们只是知道了post和sendMessage原理都是封装成Message,但是还是不清楚Handler的整个机制是什么样子,继续探究下去。

    刚才看到那两个方法到最终都调用了sendMessageAtTime

    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
            MessageQueue queue = mQueue;
            if (queue == null) {
                RuntimeException e = new RuntimeException(
                        this + " sendMessageAtTime() called with no mQueue");
                Log.w("Looper", e.getMessage(), e);
                return false;
            }
            return enqueueMessage(queue, msg, uptimeMillis);
        }
    

    这个方法又调用了 enqueueMessage,看名字应该是把消息加入队列的意思,点进去看下:

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
            msg.target = this;
            if (mAsynchronous) {
                msg.setAsynchronous(true);
            }
            return queue.enqueueMessage(msg, uptimeMillis);
        }
    

    mAsynchronous这个异步有关的先不管,继续将参数传给了queue的enqueueMessage方法,至于那个msgtarget的赋值我们后面再看,现在继续进入MessageQueue类的enqueueMessage方法,方法较长,我们看看关键的几行:

    Message prev;
    for (;;) {
        prev = p;
        p = p.next;
        if (p == null || when < p.when) {
            break;
        }
        if (needWake && p.isAsynchronous()) {
            needWake = false;
        }
    }
    msg.next = p; // invariant: p == prev.next
    prev.next = msg;
    

    果然像方法名说的一样,一个无限循环将消息加入到消息队列中(链表的形式),但是有放就有拿,这个消息怎样把它取出来呢?

    翻看MessageQueue的方法,我们找到了next(),代码太长,不赘述,我们知道它是用来把消息取出来的就行了。不过这个方法是在什么地方调用的呢,不是在Handler中,我们找到了Looper这个关键人物,我叫他环形使者,专门负责从消息队列中拿消息,关键代码如下:

    for (;;) {
         Message msg = queue.next(); // might block
         ...
         msg.target.dispatchMessage(msg);
         ...
         msg.recycleUnchecked();
    }
    

    简单明了,我们看到了我们刚才说的msg.target,刚才在Handler中赋值了msg.target=this,所以我们来看Handler中的dispatchMessage:

    public void dispatchMessage(Message msg) {
            if (msg.callback != null) {
                handleCallback(msg);
            } else {
                if (mCallback != null) {
                    if (mCallback.handleMessage(msg)) {
                        return;
                    }
                }
                handleMessage(msg);
            }
        }
    
    1. msg的callback不为空,调用handleCallback方法(message.callback.run()
    2. mCallback不为空,调用mCallback.handleMessage(msg)
    3. 最后如果其他都为空,执行Handler自身的 handleMessage(msg) 方法

    msg的callback应该已经想到是什么了,就是我们通过Handler.post(Runnable r)传入的Runnable的run方法,这里就要提提java基础了,直接调用线程的run方法相当于是在一个普通的类调用方法,还是在当前线程执行,并不会开启新的线程。

    所以到了这里,我们解决了开始的疑惑,为什么在post中传了个Runnable还是在主线程中可以更新UI

    继续看如果msg.callback为空的情况下的mCallback,这个要看看构造方法:

    1.
    public Handler() {
            this(null, false);
        }
    2.    
    public Handler(Callback callback) {
            this(callback, false);
        }
    3.
    public Handler(Looper looper) {
            this(looper, null, false);
        }
    4.
    public Handler(Looper looper, Callback callback) {
            this(looper, callback, false);
        }
    5.
    public Handler(boolean async) {
            this(null, async);
        }
    6.
    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;
        }
    7.
    public Handler(Looper looper, Callback callback, boolean async) {
            mLooper = looper;
            mQueue = looper.mQueue;
            mCallback = callback;
            mAsynchronous = async;
        }
    
    

    具体的实现就只有最后两个,已经知道mCallback是怎么来的了,在构造方法中传入就行。

    最后如果这两个回调都为空的话就执行Handler自身的handleMessage(msg)方法,也就是我们熟知的新建Handler重写的那个handleMessage方法。

    Looper

    看到了这里有一个疑惑,那就是我们在新建Handler的时候并没有传入任何参数,也没有哪里显示调用了Looper有关方法,那Looper的创建以及方法调用在哪里呢?其实这些东西Android本身已经帮我们做了,在程序入口ActivityThread的main方法里面我们可以找到:

     public static void main(String[] args) {
        ...
        Looper.prepareMainLooper();
        ...
        Looper.loop();
        ...
    

    总结

    已经大概梳理了一下Handler的消息机制,以及post方法和我们常用的sendMessage方法的区别。来总结一下,主要涉及四个类Handler、Message、MessageQueue、Looper

    新建Handler,通过sendMessage或者post发送消息,Handler调用sendMessageAtTimeMessage交给MessageQueue


    MessageQueue.enqueueMessage方法将Message以链表的形式放入队列中


    Looperloop方法循环调用MessageQueue.next()取出消息,并且调用HandlerdispatchMessage来处理消息


    dispatchMessage中,分别判断msg.callback、mCallback也就是post方法或者构造方法传入的不为空就执行他们的回调,如果都为空就执行我们最常用重写的handleMessage


    最后谈谈handler的内存泄露问题

    再来看看我们的新建Handler的代码:

    private Handler mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                ...
            }
        };
    

    当使用内部类(包括匿名类)来创建Handler的时候,Handler对象会隐式地持有Activity的引用。

    而Handler通常会伴随着一个耗时的后台线程一起出现,这个后台线程在任务执行完毕后发送消息去更新UI。然而,如果用户在网络请求过程中关闭了Activity,正常情况下,Activity不再被使用,它就有可能在GC检查时被回收掉,但由于这时线程尚未执行完,而该线程持有Handler的引用(不然它怎么发消息给Handler?),这个Handler又持有Activity的引用,就导致该Activity无法被回收(即内存泄露),直到网络请求结束。

    另外,如果执行了Handler的postDelayed()方法,那么在设定的delay到达之前,会有一条MessageQueue -> Message -> Handler -> Activity的链,导致你的Activity被持有引用而无法被回收。

    解决方法之一,使用弱引用:

    static class MyHandler extends Handler {
        WeakReference<Activity > mActivityReference;
        MyHandler(Activity activity) {
            mActivityReference= new WeakReference<Activity>(activity);
        }
        @Override
        public void handleMessage(Message msg) {
            final Activity activity = mActivityReference.get();
            if (activity != null) {
                mImageView.setImageBitmap(mBitmap);
            }
        }
    }
    

    聊技术 聊电影 聊人生 什么都聊的公众号
    聊技术 聊电影 聊人生 什么都聊的公众号

    Handler文章关联:

    一个线程可以有几个Looper?几个Handler?从Looper.prepare()来看看关于Looper的一些问题

    Thread、Handler和HandlerThread关系何在?

    AsyncTask你真的用对了吗?

    从Handler.postDelayed来看看Android怎么实现处理延时消息

    尊重劳动成果,转载请注明出处http://blog.csdn.net/ly502541243/article/details/52062179
    展开全文
  • 转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38377229 ,本文出自【张鸿洋的博客】很多人面试肯定都被问到过,请问Android中的Looper , Handler , ...1、 概述Handler 、 Looper 、Mess

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38377229 ,本文出自【张鸿洋的博客】

    很多人面试肯定都被问到过,请问Android中的Looper , Handler , Message有什么关系?本篇博客目的首先为大家从源码角度介绍3者关系,然后给出一个容易记忆的结论。

    1、 概述

    Handler 、 Looper 、Message 这三者都与Android异步消息处理线程相关的概念。那么什么叫异步消息处理线程呢?
    异步消息处理线程启动后会进入一个无限的循环体之中,每循环一次,从其内部的消息队列中取出一个消息,然后回调相应的消息处理函数,执行完成一个消息后则继续循环。若消息队列为空,线程则会阻塞等待。

    说了这一堆,那么和Handler 、 Looper 、Message有啥关系?其实Looper负责的就是创建一个MessageQueue,然后进入一个无限循环体不断从该MessageQueue中读取消息,而消息的创建者就是一个或多个Handler 。

    2、 源码解析

    1、Looper

    对于Looper主要是prepare()和loop()两个方法。
    首先看prepare()方法
    public static final void prepare() {
            if (sThreadLocal.get() != null) {
                throw new RuntimeException("Only one Looper may be created per thread");
            }
            sThreadLocal.set(new Looper(true));
    }
    

    sThreadLocal是一个ThreadLocal对象,可以在一个线程中存储变量。可以看到,在第5行,将一个Looper的实例放入了ThreadLocal,并且2-4行判断了sThreadLocal是否为null,否则抛出异常。这也就说明了Looper.prepare()方法不能被调用两次,同时也保证了一个线程中只有一个Looper实例~相信有些哥们一定遇到这个错误。
    下面看Looper的构造方法:
    private Looper(boolean quitAllowed) {
            mQueue = new MessageQueue(quitAllowed);
            mRun = true;
            mThread = Thread.currentThread();
    }
    
    在构造方法中,创建了一个MessageQueue(消息队列)。
    然后我们看loop()方法:
    public static void loop() {
            final Looper me = myLooper();
            if (me == null) {
                throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
            }
            final MessageQueue queue = me.mQueue;
    
            // Make sure the identity of this thread is that of the local process,
            // and keep track of what that identity token actually is.
            Binder.clearCallingIdentity();
            final long ident = Binder.clearCallingIdentity();
    
            for (;;) {
                Message msg = queue.next(); // might block
                if (msg == null) {
                    // No message indicates that the message queue is quitting.
                    return;
                }
    
                // This must be in a local variable, in case a UI event sets the logger
                Printer logging = me.mLogging;
                if (logging != null) {
                    logging.println(">>>>> Dispatching to " + msg.target + " " +
                            msg.callback + ": " + msg.what);
                }
    
                msg.target.dispatchMessage(msg);
    
                if (logging != null) {
                    logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
                }
    
                // Make sure that during the course of dispatching the
                // identity of the thread wasn't corrupted.
                final long newIdent = Binder.clearCallingIdentity();
                if (ident != newIdent) {
                    Log.wtf(TAG, "Thread identity changed from 0x"
                            + Long.toHexString(ident) + " to 0x"
                            + Long.toHexString(newIdent) + " while dispatching to "
                            + msg.target.getClass().getName() + " "
                            + msg.callback + " what=" + msg.what);
                }
    
                msg.recycle();
            }
    }
    

    第2行:
    public static Looper myLooper() {
    return sThreadLocal.get();
    }
    方法直接返回了sThreadLocal存储的Looper实例,如果me为null则抛出异常,也就是说looper方法必须在prepare方法之后运行。
    第6行:拿到该looper实例中的mQueue(消息队列)
    13到45行:就进入了我们所说的无限循环。
    14行:取出一条消息,如果没有消息则阻塞。
    27行:使用调用 msg.target.dispatchMessage(msg);把消息交给msg的target的dispatchMessage方法去处理。Msg的target是什么呢?其实就是handler对象,下面会进行分析。
    44行:释放消息占据的资源。

    Looper主要作用:
    1、 与当前线程绑定,保证一个线程只会有一个Looper实例,同时一个Looper实例也只有一个MessageQueue。
    2、 loop()方法,不断从MessageQueue中去取消息,交给消息的target属性的dispatchMessage去处理。
    好了,我们的异步消息处理线程已经有了消息队列(MessageQueue),也有了在无限循环体中取出消息的哥们,现在缺的就是发送消息的对象了,于是乎:Handler登场了。

    2、Handler

    使用Handler之前,我们都是初始化一个实例,比如用于更新UI线程,我们会在声明的时候直接初始化,或者在onCreate中初始化Handler实例。所以我们首先看Handler的构造方法,看其如何与MessageQueue联系上的,它在子线程中发送的消息(一般发送消息都在非UI线程)怎么发送到MessageQueue中的。
    public Handler() {
            this(null, false);
    }
    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;
        }
    

    14行:通过Looper.myLooper()获取了当前线程保存的Looper实例,然后在19行又获取了这个Looper实例中保存的MessageQueue(消息队列),这样就保证了handler的实例与我们Looper实例中MessageQueue关联上了。

    然后看我们最常用的sendMessage方法

       public final boolean sendMessage(Message msg)
        {
            return sendMessageDelayed(msg, 0);
        }

       public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
            Message msg = Message.obtain();
            msg.what = what;
            return sendMessageDelayed(msg, delayMillis);
        }

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

     public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
            MessageQueue queue = mQueue;
            if (queue == null) {
                RuntimeException e = new RuntimeException(
                        this + " sendMessageAtTime() called with no mQueue");
                Log.w("Looper", e.getMessage(), e);
                return false;
            }
            return enqueueMessage(queue, msg, uptimeMillis);
        }

    辗转反则最后调用了sendMessageAtTime,在此方法内部有直接获取MessageQueue然后调用了enqueueMessage方法,我们再来看看此方法:

     private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
            msg.target = this;
            if (mAsynchronous) {
                msg.setAsynchronous(true);
            }
            return queue.enqueueMessage(msg, uptimeMillis);
        }

    enqueueMessage中首先为meg.target赋值为this,【如果大家还记得Looper的loop方法会取出每个msg然后交给msg,target.dispatchMessage(msg)去处理消息】,也就是把当前的handler作为msg的target属性。最终会调用queue的enqueueMessage的方法,也就是说handler发出的消息,最终会保存到消息队列中去。


    现在已经很清楚了Looper会调用prepare()和loop()方法,在当前执行的线程中保存一个Looper实例,这个实例会保存一个MessageQueue对象,然后当前线程进入一个无限循环中去,不断从MessageQueue中读取Handler发来的消息。然后再回调创建这个消息的handler中的dispathMessage方法,下面我们赶快去看一看这个方法:

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

    可以看到,第10行,调用了handleMessage方法,下面我们去看这个方法:

      /**
         * Subclasses must implement this to receive messages.
         */
        public void handleMessage(Message msg) {
        }
        
    可以看到这是一个空方法,为什么呢,因为消息的最终回调是由我们控制的,我们在创建handler的时候都是复写handleMessage方法,然后根据msg.what进行消息处理。

    例如:

    private Handler mHandler = new Handler()
    	{
    		public void handleMessage(android.os.Message msg)
    		{
    			switch (msg.what)
    			{
    			case value:
    				
    				break;
    
    			default:
    				break;
    			}
    		};
    	};

    到此,这个流程已经解释完毕,让我们首先总结一下

    1、首先Looper.prepare()在本线程中保存一个Looper实例,然后该实例中保存一个MessageQueue对象;因为Looper.prepare()在一个线程中只能调用一次,所以MessageQueue在一个线程中只会存在一个。

    2、Looper.loop()会让当前线程进入一个无限循环,不端从MessageQueue的实例中读取消息,然后回调msg.target.dispatchMessage(msg)方法。

    3、Handler的构造方法,会首先得到当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue想关联。

    4、Handler的sendMessage方法,会给msg的target赋值为handler自身,然后加入MessageQueue中。

    5、在构造Handler实例时,我们会重写handleMessage方法,也就是msg.target.dispatchMessage(msg)最终调用的方法。

    好了,总结完成,大家可能还会问,那么在Activity中,我们并没有显示的调用Looper.prepare()和Looper.loop()方法,为啥Handler可以成功创建呢,这是因为在Activity的启动代码中,已经在当前UI线程调用了Looper.prepare()和Looper.loop()方法。

    3、Handler post

    今天有人问我,你说Handler的post方法创建的线程和UI线程有什么关系?

    其实这个问题也是出现这篇博客的原因之一;这里需要说明,有时候为了方便,我们会直接写如下代码:

    mHandler.post(new Runnable()
    		{
    			@Override
    			public void run()
    			{
    				Log.e("TAG", Thread.currentThread().getName());
    				mTxt.setText("yoxi");
    			}
    		});

    然后run方法中可以写更新UI的代码,其实这个Runnable并没有创建什么线程,而是发送了一条消息,下面看源码:

     public final boolean post(Runnable r)
        {
           return  sendMessageDelayed(getPostMessage(r), 0);
        }
      private static Message getPostMessage(Runnable r) {
            Message m = Message.obtain();
            m.callback = r;
            return m;
        }

    可以看到,在getPostMessage中,得到了一个Message对象,然后将我们创建的Runable对象作为callback属性,赋值给了此message.

    注:产生一个Message对象,可以new  ,也可以使用Message.obtain()方法;两者都可以,但是更建议使用obtain方法,因为Message内部维护了一个Message池用于Message的复用,避免使用new 重新分配内存。

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

     public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
            MessageQueue queue = mQueue;
            if (queue == null) {
                RuntimeException e = new RuntimeException(
                        this + " sendMessageAtTime() called with no mQueue");
                Log.w("Looper", e.getMessage(), e);
                return false;
            }
            return enqueueMessage(queue, msg, uptimeMillis);
        }
    最终和handler.sendMessage一样,调用了sendMessageAtTime,然后调用了enqueueMessage方法,给msg.target赋值为handler,最终加入MessagQueue.

    可以看到,这里msg的callback和target都有值,那么会执行哪个呢?

    其实上面已经贴过代码,就是dispatchMessage方法:

     public void dispatchMessage(Message msg) {
            if (msg.callback != null) {
                handleCallback(msg);
            } else {
                if (mCallback != null) {
                    if (mCallback.handleMessage(msg)) {
                        return;
                    }
                }
                handleMessage(msg);
            }
        }
    第2行,如果不为null,则执行callback回调,也就是我们的Runnable对象。

    好了,关于Looper , Handler , Message 这三者关系上面已经叙述的非常清楚了。

    最后来张图解:


    希望图片可以更好的帮助大家的记忆~~

    4、后话

    其实Handler不仅可以更新UI,你完全可以在一个子线程中去创建一个Handler,然后使用这个handler实例在任何其他线程中发送消息,最终处理消息的代码都会在你创建Handler实例的线程中运行。

    new Thread()
    		{
    			private Handler handler;
    			public void run()
    			{
    
    				Looper.prepare();
    				
    				handler = new Handler()
    				{
    					public void handleMessage(android.os.Message msg)
    					{
    						Log.e("TAG",Thread.currentThread().getName());
    					};
    				};
                                   Looper.loop();                                                                                                                              }             

    Android不仅给我们提供了异步消息处理机制让我们更好的完成UI的更新,其实也为我们提供了异步消息处理机制代码的参考~~不仅能够知道原理,最好还可以将此设计用到其他的非Android项目中去~~

    最新补充:

    关于后记,有兄弟联系我说,到底可以在哪使用,见博客:Android Handler 异步消息处理机制的妙用 创建强大的图片加载类




    展开全文
  • Handler 源码解析——Handler的创建

    千次阅读 2018-08-18 16:07:15
    Android 提供了Handler和Looper来来满足线程间的通信,而前面我们所说的IPC指的是进程间的通信。这是两个完全不同的概念。 Handler先进先出原则,Looper类用来管理特定线程内消息的交换(MessageExchange); 1...
  • Handler用法及解析

    万次阅读 多人点赞 2018-08-10 17:01:12
    1.handler作用:  1)传递消息Message 2)子线程通知主线程更新ui 2.常用api 3.handler使用避免内存泄露  1)handler怎么使用会产生内存泄露?  2)如何避免handler的内存泄露?  3) 雷区 4.handlerThread...
  • Android Handler异步通信:深入详解Handler机制源码

    千次阅读 多人点赞 2018-05-21 10:08:17
    在Android开发的多线程应用场景中,Handler机制十分常用 今天,我将手把手带你深入分析 Handler机制的源码,希望你们会喜欢 目录 1. Handler 机制简介 定义 一套 Android 消息传递机制 作用 在多...
  • Android handler 取消延时handler消息

    千次阅读 2019-08-31 10:04:55
    Android handler 取消延时handler消息 myHandler.sendEmptyMessageDelayed(TEST, 30000);// 半分钟后发TEST(即msg.what) 如果想在未到半分钟的时候取消发送TEST,可以 myHandler.removeMessages(TEST); 这样...
  • Handler完全解读——Handler的使用

    千次阅读 2018-09-18 15:52:57
    Handler完全解读——Handler的使用 Handler是什么 Handler是Android给我们提供用于更新UI的一套机制,也是一套消息处理机制。我们用它可以发送消息,也可以用它处理消息。在Android开发中有着非常重要的地位。 为...
  • Handler: 更新UI的方法

    万次阅读 多人点赞 2019-07-23 15:35:02
    读这篇文章之前,假设你已经明白线程、Handler 的使用。 在文章的最后,附录一张草图,主要用于说明 Handler、Message、MessageQueue、Looper 之间的关系。 1. 在 onCreate() 方法中开启线程更新 UI public ...
  • 安卓Handler

    2018-03-08 15:26:26
    1.什么是HandlerHandler是安卓SDK中处理异步消息的核心类。 Handler的作用是让子线程通过与主线程通信来更新UI界面。 2.Handler的运行机制 创建一个Handler对象,系统就把Handler对象、UI线程和UI线程的消息...
  • Handler源码分析

    千次阅读 2021-03-01 00:13:41
    Handler Handler机制是子线程和主线程、子线程和子线程通信的一种方法,其中包括Looper、MessageQueue、Message、HandlerHandler将Message发送到MessageQueue中,Looper不停的轮询从MessageQueue中取出Message交给...
  • Handler学习

    千次阅读 2018-07-05 14:53:15
    1 什么是Handler 以下内容摘自Android官方原文: A Handler allows you to send and process {@link Message} and Runnable objects associated with a thread's {@link MessageQueue}. Each Handler ...
  • springmvc拦截器 handler instanceof HandlerMethod false

    万次阅读 热门讨论 2018-11-22 15:14:36
    新建拦截器,获取调用方法中的注解参数,由于handler的对应类型为Controller实例,所以 (handler instanceof HandlerMethod) == false,导致无法将 handler 转换为HandlerMethod类型,解决办法是在xxx-servlet....
  • springBoot项目遇到了“Handler dispatch failed; nested exception is java.lang.StackOverflowError”的错误。总结一哈:StackOverflowError通常情况下是死循环或者是循环依赖了。Caused by: java.lang....
  • 今天声明Handler时,发现出错,alt+回车后出现三个不需要的方法: Handler handler = new Handler() { @Override public void publish(LogRecord record) { } @Override public void flush() { }
  • Handler运行机制

    万次阅读 多人点赞 2016-04-24 22:52:35
    Handler原理分析
  • STM32出现HardFault_Handler故障的原因主要有两个方面: 1、内存溢出或者访问越界。这个需要自己写程序的时候规范代码,遇到了需要慢慢排查。 2、堆栈溢出。增加堆栈的大小。 MemManage_Handler:访问了内存...
  • Android-Handler机制详解并自定义Handler

    千次阅读 2018-06-26 15:12:06
    之前研究过Android的Handler机制,但是一直没有机会自己实现一次。最近又看到这个Handler机制,于是决定自己实现以下这个Handler机制。 首先,简单介绍以下Handler机制。 Handler机制在Android中通常用来更新UI:...
  • 如何使用Handler

    千次阅读 2017-05-18 20:24:17
    什么是HandlerHandler可以发送和处理消息对象或Runnable对象,这些消息对象和Runnable对象与一个线程相关联。每个Handler的实例都关联了一个线程和线程的消息队列。当创建了一个Handler对象时,一个线程或消息队列...
  • Handler基本使用(一) new Handler

    千次阅读 2016-12-13 14:48:08
    通常我们使用如下方式获取一个Handler对象 private Handler mHandler1 = new Handler(){ public void handleMessage(Message msg) { }; }; private Handler mHandler2 = new Handler(new Handler....
  • Handler机制

    千次阅读 2016-03-30 14:29:00
    Handler原理、使用
  • Handler/Handler.post引发内存泄漏

    千次阅读 2019-02-18 20:54:01
    GC ROOT static HandlerCenter.mHandlerList-- Android ... handler.removeCallbacks(null)不起作用;  调用handler.removeCallbacksAndMessages(null);可以清空当前handler的所有回调和所有消息。想当然的...
  • Handler导致内存泄露分析 有关内存泄露请猛戳内存泄露 Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { // do something. } } 当我们这样创建Handler的时候Android ...
  • Handler总结

    千次阅读 2013-08-24 21:33:46
    全面介绍了Handler,post(Runnable runable).
  • Handler详解

    千次阅读 2016-03-11 11:03:13
    Handler、Message、异步消息处理
  • Kotlin 使用Handler

    千次阅读 2020-06-21 12:13:24
    方式 A 网上普遍用法 ... val handler : Handler = object : Handler(){ override fun handleMessage(msg: Message?) { super.handleMessage(msg) when(msg?.what){ 9999 ->{ try { var t = msg.data.get(...
  • Handler翻译

    2016-05-22 00:09:08
    A Handler allows you to send and process Message and Runnable objects associated with a thread'sMessageQueue.  Handler允许你去发送和处理与thread的MessageQueue有关的Message和Runnable对象 E

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 175,260
精华内容 70,104
关键字:

handler