22.通过Handler实现线程间通信

2017-05-20  本文已影响76人  Jsonzhang

前言

主线程可以向子线程发送消息吗?如果可以怎样实现?
子线程可以向子线程发送消息吗?
面试时被面试官问过两次这样的问题都没有回答上来,所以今天查阅了一些资料来补充一下这里的知识。

参考资料:http://www.mamicode.com/info-detail-517314.html

子线程向主线程发送消息

由于android不允许在主线程做耗时的操作,子线程又不能更新UI,所以我们工作中大多用的都是在子线程中请求处理数据,然后将数据发送到主线程,来更新UI,所以我们经常用到的都是子线程向主线程发送消息,大家都不陌生就不多说了。

主线程向子线程发送消息

我们首先要确定一个事情:哪个线程要处理消息,Handler就必须绑定到哪个线程

其实简单的逻辑就是创建一个Handler,然后在一个线程中发送消息,另一个线程中处理消息。Handler将消息发送到消息队列MessageQueue中,消息队列是由Looper来负责管理的,所以我们首先要得到一个Looper。但是有的同学就有疑问了,为啥我们平时写代码时没有管什么looper啊,那是因为我们在主线程创建的Handler,而主线程默认帮我们完成了Looper的操作,所以如果我们从主线程向子线程发送消息,Handler是子线程的的,我们必须在子线程中自己完成Looper的操作。

我们再来具体的说下这个Looper是什么。
它就像一个消息队列(MessageQueue)的管家(Looper),一个消息队列只有一个管家,并且管理者整个消息队列,而一个消息队列内可以容纳多个消息(Message),而工人(Handler)也可以有多个,管家派遣他们向消息队列中存储或取出消息后执行任务;

所以它们的个数如下:
管家(Looper): 1 个;
消息队列(MessageQueue):1 个;
消息(Message):可以多个;
工人(Handler):可以多个;

Looper的部分源码:

//ThreadLocal可以理解为一个存储Looper的列表;
ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

//Looper的构造器
private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }


1.Looper.prepare()完成了如下操作:
sThreadLocal.set(new Looper(quitAllowed));


2.Looper.loop()完成了如下操作:
Looper me = sThreadLocal.get();

MessageQueue queue = me.mQueue;
……
//不断循环分发消息
for (;;) {
    Message msg = queue.next(); 
    ……
    msg.target.dispatchMessage(msg);

        //dispatchMessage(msg)方法执行如下内容:
        handler.handleMessage(msg);//handler执行handleMessage(msg)中的代码;
    ……
};

简单实例

public class MainActivity extends AppCompatActivity {


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

        final MyThread thread = new MyThread();
        thread.start();

        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Message message = Message.obtain();
                message.what = 2;
                thread.handler.sendMessage(message);
            }
        });


    }

    class MyThread extends Thread{
        private Handler handler;

        @Override
        public void run() {
            super.run();
            Looper.prepare();
            handler = new Handler(){   //handler必须在在线程的run方法中创建
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    Toast.makeText(MainActivity.this,"MyThread handler 收到消息 :"+msg.what,Toast.LENGTH_LONG).show();
                }
            };
            Looper.loop();
        }
    }
}

Looper.prepare() 和Looper.loop() 就是所说的我们要在子线程中要自己完成的Looper操作。

子线程向子线程发送消息

 class MyThread extends Thread{
        public Handler handler;

        @Override
        public void run() {
            super.run();
            Looper.prepare();
            handler = new Handler(){   //handler必须在在线程的run方法中创建
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    Toast.makeText(MainActivity.this,"MyThread handler 收到消息 :"+msg.what,Toast.LENGTH_LONG).show();
                }
            };
            Looper.loop();
        }
    }

其实只要我们知道了上面的和代码,建立一个线程类,先获取Looper对象,然后在run方法中绑定一个Handler,然后启动消息循环,我们就可以在任何时间地点通过创建线程类对象,从而获取他的handler成员变量来发送消息。所以子线程也可以向子线程发送消息。

public class MainActivity extends AppCompatActivity {
    YourThread yourThread;
    MyThread myThread;

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

        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                yourThread = new YourThread();
                yourThread.start();
            }
        });

        myThread = new MyThread();
        myThread.start();
    }

    class MyThread extends Thread{
        private Handler handler;

        @Override
        public void run() {
            super.run();
            Looper.prepare();
            handler = new Handler(){   //handler必须在在线程的run方法中创建
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    Toast.makeText(MainActivity.this,"MyThread handler 收到消息 :"+msg.what,Toast.LENGTH_LONG).show();
                }
            };

            Looper.loop();
        }
    }

    class YourThread extends Thread{
        @Override
        public void run() {
            super.run();
            Message message = Message.obtain();
            message.what = 3;
            myThread.handler.sendMessage(message);
        }
    }
}
上一篇 下一篇

猜你喜欢

热点阅读