【java】Handler,Looper,Message,MessageQueue。【android】HandlerThread+Looper

多线程相关

  • 【java】Handler+Looper+Message+MessageQueue 消息处理系统
  • 【android】HandlerThread+Looper

【java】Handler+Looper+Message+MessageQueue 消息处理系统

  • Handler为什么可以处理UI
  • 各职责
  • Handler、MessageQueue、Looper之间关系,以及是如何协作的
  • Demo例子
  • 4种方式实现其它线程访问UI线程
  • 小结

1.Handler为什么可以处理UI

handler能够处理UI,因为handler在创建的时候会绑定在创建的线程上,如果handler实在在UI线程上创建的,那么他就可以操作UI。

2.各职责

  • Message:消息。包括了消息ID、消息处理对象、处理的数据。由MessageQueue统一列队,最终由Handler进行处理
  • Handler:处理者。负责Message的发送以及接受处理,使用Handler时,需要实现HandleMessage(Message msg)方法来对Message消息进行处理,比如更新UI
  • MessageQueue:消息队列。用来存放Handler发送过来的消息,按照FIFO(先进先出)规则执行。但是,存放的Message并非实际意思的保存,而是将Message以链表的方式串联起来,等待Looper抽取
  • Looper:消息泵。不断从MessageQueue抽取Message执行。因此,一个Looper需要一个MessgaeQueue

3.关系

  • Handler,Looper和MessageQueue就是简单的三角关系。
  • Handler与它们的关系,只是简单的聚集关系,即Handler里会引用当前线程里的特定Looper和MessageQueue。
  • 多个Handler都可以共享同一Looper和MessageQueue。但是,这些Handler也就运行在同一个线程里。
    下面展Handler、MessageQueue、Looper之间是如何协作的:
    这里写图片描述

4.Demo例子(a.主线程发送消息到子线程。b.子线程发送消息到主线程)

  • a.主线程发送消息到子线程
  • b.子线程发送消息到主线程
    (a)主线程发送消息到子线程例子:
public class MainActivity extends AppCompatActivity {

    TextView tv;
    private Handler handler;
    private int i = 0;

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

        tv = (TextView) findViewById(R.id.tv);
        new LooperThread().start();
        tv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                i += 1;
                //注意这个handler在New LooperThread().start()时候初始化了;
                Message message = handler.obtainMessage(1, 1, 1, "主线程发送的消息" + i);
                handler.sendMessage(message);
            }
        });
    }

    class LooperThread extends Thread {
        @Override
        public void run() {
            super.run();
            // 将当前线程初始化为Looper线程
            Looper.prepare();

            // 其他处理,如实例化handler
            /**
             * 注意了:
             * ---这里的handler是定义在主线程中的
             *Looper.myLooper()获得的就是该线程的Looper对象了
             */
            handler = new ThreadHandlers(Looper.myLooper());

            // 开始循环处理消息队列
            Looper.loop();
        }

        class ThreadHandlers extends Handler {
            public ThreadHandlers(Looper looper) {
                super(looper);
            }

            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                //这里对该线程中的MessageQueue中的Message进行处理
                handler = new Handler(Looper.myLooper()) {
                    @Override
                    public void handleMessage(Message msg) {
                        super.handleMessage(msg);
                        Log.e("aaaaa", "子线程收到" + msg.obj);
                    }
                };
            }
        }
    }
}
多次点击结果为:

E/aaaaa: 子线程收到主线程发送的消息1
E/aaaaa: 子线程收到主线程发送的消息2
E/aaaaa: 子线程收到主线程发送的消息3
E/aaaaa: 子线程收到主线程发送的消息4
E/aaaaa: 子线程收到主线程发送的消息5
E/aaaaa: 子线程收到主线程发送的消息6
E/aaaaa: 子线程收到主线程发送的消息7

(b)子线程发送消息到主线程

public class MainActivity extends AppCompatActivity {

    TextView tv;
    private Handler handler;
    private int i = 0;//记数,记录点击的次数

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

        tv = (TextView) findViewById(R.id.tv);
        tv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new LooperThread(i++).start();
            }
        });
    }

    class LooperThread extends Thread {
        int i = 0;

        public LooperThread(int i) {
            this.i = i;
        }

        @Override
        public void run() {
            super.run();
            //主线程的Looper对象
            Looper looper = Looper.getMainLooper();
            //使用主线程的Looper对象来创建Handler,因此这个Handler发送的Message会传递给主线程的MessageQueue
            handler = new UIHandlers(looper);

            Message message = handler.obtainMessage(1, 1, 1, "子线程发送消息" + i);
            handler.sendMessage(message);
        }
    }

    class UIHandlers extends Handler {
        public UIHandlers(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            //更新UI
            tv.setText(msg.obj + "");
            Log.e("aaa", msg.obj + "");
        }
    }
}
多次点击结果为:

06-03 00:24:38.983 15698-15698/com.example.administrator.demo E/aaa: 子线程发送消息0
06-03 00:24:40.023 15698-15698/com.example.administrator.demo E/aaa: 子线程发送消息1
06-03 00:24:40.523 15698-15698/com.example.administrator.demo E/aaa: 子线程发送消息2
06-03 00:24:40.753 15698-15698/com.example.administrator.demo E/aaa: 子线程发送消息3
06-03 00:24:40.953 15698-15698/com.example.administrator.demo E/aaa: 子线程发送消息4
06-03 00:24:41.163 15698-15698/com.example.administrator.demo E/aaa: 子线程发送消息5

5.6种方式实现其他线程访问UI线程

  • Handler与Message机制:通过显示的抛出、捕获消息与UI进行交互
  • Activity.runOnUiThread(Runnable):如果当前线程为ui线程,则立即执行;否则,将参数中的线程操作放入到ui线程的事件队列中,等待执行。
  • View.post(Runnable):在线程里面发送消息。然后在handler的dispatchMessage()方法里面进行处理
  • View.postDelayed(Runnable,long):跟上面一样,只是多了个带有延迟的
  • 使用AsyncTask直接更新UI
  • 2~6条其实底层实现都是Handler的通信机制(注意:为什么handelr在子线程创建不调用Looper.prepare()不行),详细介绍可以参考郭神的博文:http://blog.csdn.net/guolin_blog/article/details/9991569

6.小结

  • Handler的处理过程,运行在创建的Handler的线程里
  • 一个Looper对应一个MessageQueue
  • 一个线程对应一个Looper
  • 一个Looper可以对应多个Handler
  • 不确定当前线程时,更新UI尽量调用post方法

【android】HandlerThread+Looper

  • 使用步骤
  • HandlerThread优势
  • 测试Demo

1.使用步骤

    //1.创建一个HandlerThread,即创建了一个包含Looper的线程。
    HandlerThread handlerThread = new HandlerThread("MyHandlerThread");
    handlerThread.start();

    //2.获取HandlerThread的Looper
    Looper looper = handlerThread.getLooper();

    //3.创建Handler,通过Looper初始化
    Handler handler = new Handler(looper);

//注意:
//a.通过以上三步我们就成功创建HandlerThread。通过handler发送消息,就会在子线程中执行。
//b.如果想让HandlerThread退出,则需要调用handlerThread.quit();。

2.HandlerThread的优势

Android使用Looper机制才能接收消息和处理计划任务,上面的代码编写起来实在是麻烦,所以Android提供了一个线程类HanderThread类,HanderThread类继承了Thread类,它封装了Looper对象,使我们不用关心Looper的开启和释放的细节问题。HandlerThread对象中可以通过getLooper方法获取一个Looper对象引用。

3.测试Demo

public class MainActivity extends AppCompatActivity {

    TextView tv;
    private Handler handler;
    private boolean isRunning;

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

        tv = (TextView) findViewById(R.id.tv);
        tv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
//                handler.postDelayed(runnable, 1000);
                Message message = handler.obtainMessage(1, 1, 1, "发送消息");
                handler.sendMessage(message);
            }
        });

        HandlerThread handlerThread = new HandlerThread("MyHandlerThread");
        handlerThread.start();
        Looper looper = handlerThread.getLooper();
        handler = new UIHandlers(looper);
    }

    class UIHandlers extends Handler {
        public UIHandlers(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            //子线程
            Log.e("aaa", msg.obj + "");
        }
    }

//    private Runnable runnable = new Runnable() {
//        @Override
//        public void run() {
//            Log.e("aaa", "HandlerThread.");
//            try {
//                Thread.sleep(200);
//            } catch (Exception e) {
//                e.printStackTrace();
//            }
//        }
//    };

    @Override
    protected void onResume() {
        super.onResume();
        isRunning = true;
    }

    @Override
    protected void onStop() {
        super.onStop();
        isRunning = false;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        isRunning = false;
//        handler.removeCallbacks(runnable);
    }
}
//多次点击执行结果为:
06-03 00:54:28.693 18284-18346/com.example.administrator.demo E/aaa: 发送消息
06-03 00:54:29.503 18284-18346/com.example.administrator.demo E/aaa: 发送消息
06-03 00:54:30.073 18284-18346/com.example.administrator.demo E/aaa: 发送消息
06-03 00:54:31.143 18284-18346/com.example.administrator.demo E/aaa: 发送消息
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值