Handler(原理)创建一个与线程相关的Handler

我们通常在Activity中创建的Handler,是与UI线程绑定的,这里说的绑定其实是指,Looper和MessageQueue的绑定,

而这里的线程,也就是Looper和MessageQueue所在的线程,也就是说Handler所持有的Looper和MessageQueue是

哪个线程的,我们就说,此Handler是与哪个线程绑定的。


下面先看一个例子

package com.example.liaoli.handler_demo;

import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

public class MainActivity extends AppCompatActivity {


    private static final String TAG = "Handler_demo";

    private  Handler  UIHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            Log.e(TAG, "UI线程:" + Thread.currentThread());
        }
    };

    class MyThread extends  Thread {
        public  Handler handler ;
        public Looper looper;


        public void run(){
            Looper.prepare();

            looper = Looper.myLooper();
            handler = new Handler(){
                @Override
                public void handleMessage(Message msg) {
                    Log.e(TAG,"当前线程:" + Thread.currentThread());
                }
            };
            Looper.loop();


        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        MyThread mt = new MyThread();
        mt.start();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        mt.handler.sendEmptyMessage(0);

        UIHandler.sendEmptyMessage(0);

    }



}

运行之后打印的结果是:

09-26 18:10:32.072  30495-30507/com.example.liaoli.handler_demo E/Handler_demo﹕ 当前线程:Thread[Thread-170,5,main]
09-26 18:10:32.080  30495-30495/com.example.liaoli.handler_demo E/Handler_demo﹕ UI线程:Thread[main,5,main]


以上结果说明 

 @Override
                public void handleMessage(Message msg) {
                    Log.e(TAG,"当前线程:" + Thread.currentThread());
                }
中的代码是运行在子线程中的,此时我们其实就是创建了一个与子线程绑定的Handler实例。

子线程的run方法中的

     looper = Looper.myLooper();

其实就是在创建一个本子线程的Looper 实例,而在创建Looper的时候又会创建MessageQueue,

然后在handler的构造方法中会拿到这两个实例,从而建立绑定关系。看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;
}


再看Looper的myLooper()方法

/**
 * Return the Looper object associated with the current thread.  Returns
 * null if the calling thread is not associated with a Looper.
 */
public static @Nullable Looper myLooper() {
    return sThreadLocal.get();
}



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));
}

sThreadLocal
是ThreadLocal类的一个实例,Threadlocal类的作用就是,来实现线程的数据共享与分离,

这里的共享指的是同一个线程间的共享,分离指的是不同线程件的分离,我们可以将其理解

成一个Map,这个Map的key是我们的线程实例,value就是我们存的与此线程相关的值,当然

ThreadLocal存取并不需要指定Key,只需要用

public T get()

public void set(T value)
方法来取和存数据,当然必须得先存了在能取到数据。

ThreadLocal会根据线程去取或存这个值。也就是说只有同一个线程中取出来的值才是同一个值,

其实,简单理解成Map就好。


这也就能解释为什么我们在通常我们在Activity中创建用来更新UI的界面为什么会运行在UI线程中的问题。


这就是因为为我们创建的Handler是与ActivityThread的UI线程中Looper绑定的


ActivityThread的main方法中的代码片段:

     Looper.prepareMainLooper();
     ……

   ……
     Looper.loop();

这就在主(UI)线程中,创建了一个Looper,然后我们在Activity(UI线程中)中创建了一个Handler,Handler 在构造函数中

就会和这个主线程中的Looper绑定。所以此时Handler的


private  Handler  UIHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            Log.e(TAG, "UI线程:" + Thread.currentThread());
        }
    };

 public void handleMessage(Message msg)

中的代码是运行在UI线程中的。


再看


public class MainActivity extends AppCompatActivity {


    private static final String TAG = "Handler_demo";

    private  Handler myHandler;

    class MyThread extends  Thread {
        public  Handler handler ;
        public Looper looper;


        public void run(){
            Looper.prepare();

            looper = Looper.myLooper();

            handler = new Handler(){
                @Override
                public void handleMessage(Message msg) {
                    Log.e(TAG,"当前线程:" + Thread.currentThread());
                }
            };
            Looper.loop();


        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        MyThread mt = new MyThread();
        mt.start();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        mt.handler.sendEmptyMessage(0);


        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


        myHandler = new Handler(mt.looper){
            @Override
            public void handleMessage(Message msg) {
                Log.e(TAG, "Run IN 线程:" + Thread.currentThread());
            }
        };

        myHandler.sendEmptyMessage(0);

    }

}

运行结果

09-26 18:18:44.784    1931-1943/com.example.liaoli.handler_demo E/Handler_demo﹕ 当前线程:Thread[Thread-176,5,main]
09-26 18:18:46.784    1931-1943/com.example.liaoli.handler_demo E/Handler_demo﹕ Run IN 线程:Thread[Thread-176,5,main]


发型这两个Handler的Handler的

 public void handleMessage(Message msg)
方法的代码是运行在同一个线程的,

也就是说 Looper是哪个线程的,与之绑定的Handler的

 public void handleMessage(Message msg)
方法就运行与哪个线程。





评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值