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

来源:互联网 发布:参与网络博客是否违法 编辑:程序博客网 时间:2024/05/22 16:51

我们通常在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)
方法就运行与哪个线程。





0 0
原创粉丝点击