前言

  上一篇博客讲解了Handler实现线程间通信,这篇博客讲解一下Handler运行的原理,其中涉及到MessageQueue、Looper。简要来讲,Handler会把一个线程消息发送给当前线程的消息队列,从最后Handler会处理消息队列中的消息,这里的消息队列就是MessageQueue,而管理消息队列的,就是Looper。

  Handler、MessageQueue、Looper三者间的关系如图:

  从上图可以看出,Handler发送线程消息到当前线程的MessageQueue中,而Looper用来管理MessageQueue,它从MessageQueue中取到消息交给Handler处理。

Looper

  Looper,通常运行在一个消息的循环队列当中,线程在默认的情况下,不会给我们提供一个消息循环去管理消息队列的。如果想管理消息队列,需要在线程当中调用Looper.prepare()方法使消息循环初始化,并且调用Looper.loop()使消息循环一直处于运行状态,直到停止循环。所以Looper主要就是完成MessageQueue与Handler进行交互的功能。

  在Activity中的UI主线程中,无需使用显式的方式进行Looper的初始化以及开始循环,是因为Activity内部包含一个Looper对象,它会自动管理Looper,处理子线程中发送过来的消息。而初始化Handler的时候,在Handler的构造函数中,会把当前线程的Looper与Handler关联,所以在Activity中,无需显式使用Looper。下面通过一个例子讲解一下Activity中,工作线程给主线程发送消息的例子。

  实现代码:

 package com.example.handlerlooperdemo;

 import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.TextView; public class MainThreadActivity extends Activity {
private Button btnSendToUI1, btnSendToUI2;
private TextView tvSendMes1;
private static MyHandler handler; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.looper_activity);
tvSendMes1 = (TextView) findViewById(R.id.tvSendMes1);
btnSendToUI1 = (Button) findViewById(R.id.btnSendToUI1);
btnSendToUI2 = (Button) findViewById(R.id.btnSendToUI2); btnSendToUI1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 使用Activity内部的Looper对象
handler=new MyHandler();
Message msg=Message.obtain();
msg.what=1;
msg.obj="默认Looper";
handler.sendMessage(msg);
}
});
btnSendToUI2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 获取当前线程的Looper
Looper looper=Looper.myLooper();
handler=new MyHandler(looper); Message msg=Message.obtain();
msg.what=2;
msg.obj="使用当前线程的Looper";
handler.sendMessage(msg);
}
});
} public class MyHandler extends Handler { public MyHandler() {
} public MyHandler(Looper looper) {
super(looper);
} @Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
tvSendMes1.setText("what=" + msg.what + "," + msg.obj);
}
}
}

  实现效果:

  通过上面的Demo可以看到,虽然Handler有两个构造函数,一个需要传递一个Looper对象,一个不需要,但是对于UI线程而言,使用哪个其实效果是一样的,因为Activity会帮我们维护Looper对象。

  而对于子线程而言,没有任何对象帮助我们维护Looper对象,所以需要我们自己手动维护。这时候就需要使用prepare()和loop()方法了。下面通过一个Demo来演示一下在UI线程中给子线程发送消息的实现。注意,因为这个Handler是在子线程中声明的,所以在Handler中处理消息的实现,也必须符合子线程的限制,一些无法在子线程中做的事情,也无法这里实现,比如访问网络、操作UI组件。

  实现代码:

 package com.example.handlerlooperdemo;

 import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast; public class WorkThreadActivity extends Activity {
private Button btnSendToWorkUI;
private Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.looper_activity2); // 在UI线程中开启一个子线程
new Thread(new Runnable() {
@Override
public void run() {
// 在子线程中初始化一个Looper对象
Looper.prepare();
handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
// 把UI线程发送来的消息显示到屏幕上。
Log.i("main", "what="+msg.what+","+msg.obj);
Toast.makeText(WorkThreadActivity.this, "what="+msg.what+","+msg.obj, Toast.LENGTH_SHORT).show();
}
};
// 把刚才初始化的Looper对象运行起来,循环消息队列的消息
Looper.loop();
}
}).start(); btnSendToWorkUI=(Button)findViewById(R.id.btnSendToWorkUI); btnSendToWorkUI.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// onClick方法是运行在UI线程上的
Message msg=Message.obtain();
msg.what=1;
msg.obj="向子线程中发送消息!";
// 向子线程中发送消息
handler.sendMessage(msg);
}
});
} }

  效果展示:

  源码下载

总结

  本篇博客讲解了Handler在发送消息的原理,并且也说明了如何在UI线程和子线程中互相通信的方式,虽然在实际开发过程中,很少会用到UI线程向子线程发送消息的实现,但是通过这个例子也更好的说明了Looper的原理。

Android--多线程之Looper的更多相关文章

  1. Android 多线程之IntentService 完全详解

    关联文章: Android 多线程之HandlerThread 完全详解 Android 多线程之IntentService 完全详解 android多线程-AsyncTask之工作原理深入解析(上) ...

  2. Android 多线程之HandlerThread 完全详解

    关联文章: Android 多线程之HandlerThread 完全详解 Android 多线程之IntentService 完全详解 android多线程-AsyncTask之工作原理深入解析(上) ...

  3. Android线程之Looper

    之前已经为大家奉献了关于Handler和Message的使用,本篇我们来了解一下Handler内部的具体使用,本篇主要探讨Looper的在处理Handler的消息机制中起的重要作用,我们知道我们在子线 ...

  4. Android——多线程之Handler

    Why? 因为在Android系统中UI操作并不是线程安全的,如果多个线程并发的去操作同一个组件,可能导致线程安全问题.为了解决这一个问题, android制定了一条规则:只允许UI线程来修改UI组件 ...

  5. Android-——多线程之Handler(转)

    Android--多线程之Handler 原文地址:http://www.cnblogs.com/shirley-1019/p/3557800.html 前言 Android的消息传递机制是另外一种形 ...

  6. iOS多线程之8.NSOPeration的其他用法

      本文主要对NSOPeration的一些重点属性和方法做出介绍,以便大家可以更好的使用NSOPeration. 1.添加依赖 - (void)addDependency:(NSOperation * ...

  7. python 线程之 threading(四)

    python 线程之 threading(三) http://www.cnblogs.com/someoneHan/p/6213100.html中对Event做了简单的介绍. 但是如果线程打算一遍一遍 ...

  8. python 线程之 threading(三)

    python 线程之 threading(一)http://www.cnblogs.com/someoneHan/p/6204640.html python 线程之 threading(二)http: ...

  9. python 线程之_thread

    python 线程之_thread _thread module: 基本用法: def child(tid): print("hello from child",tid) _thr ...

随机推荐

  1. linux下安装srilm

    1.安装相关依赖库 a.c/c++ compiler:编译器gcc 3.4.3及以上版本   b.GNU make:构建和管理工程的工具,解释Makefile里的指令,描述了整个工程所有文件的编译顺序 ...

  2. JSP:getOutputStream() has already been called for this response

    JSP页面,用小脚本显示一张图片 <%@page import="java.io.OutputStream"%> <%@page import="jav ...

  3. Python Day 12

    阅读目录: 内容回顾 函数默认值的细节 三元表达式 列表与字典推导式 函数对象 名称空间 函数嵌套的定义 作用域 ##内容回顾 # 字符串的比较 -- 按照从左往右比较每一个字符,通过字符对应的asc ...

  4. select下拉框左右变换

    效果图: 使用jQuery插件---multiselect2side做法: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 ...

  5. Visual Studio Code 学习记录

    Visual Studio Code的官方文档可以学到很多知识,不只是vs code的用法,包括一些语言的入门 和一些概念等等.很好的文档. ※,user.settings.json中的一些配置说明: ...

  6. 关于Idea里设置Terminal为Git/bin/bash.exe中文乱码的问题的终极解决方案

    1.这里如果设置为Git/git-bash.exe确实不会乱码,但是每次点Idea里的Terminal都会弹出一个单独的terminal窗口而非在idea子窗口里出现: 2.因此需要设置为Git/bi ...

  7. Paper | 学习多任务中的最佳分/ 合结构(十字绣结构)

    目录 1. 问题 2. 十字绣结构(Cross-stitch architecture) 3. 实验设计 论文:Cross-stitch Networks for Multi-task Learnin ...

  8. pointer-events: none 的两个应用场景

    简介 pointer-events: none 真是个神奇的属性. 该属性有什么用?借用 CSS3 pointer-events:none 应用举例及扩展 的总结来说: pointer-events: ...

  9. 【原创】IO流:读写操作研究(输入流)

    默写代码(以下问题要求能默写,不翻书不百度) 输入 问题一:从文件abc.txt中读取数据到字节数组并打印出来. 分析:如果读取数据,首先第一个问题,数据有多少?如果数据量不确定,如果确定字节数组大小 ...

  10. JAVA:简单添加菜单界面(swing)

    package com.le.menu; import java.awt.Color; import java.awt.Container; import java.awt.FlowLayout; i ...