Android--多线程之Looper
前言
上一篇博客讲解了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的更多相关文章
- Android 多线程之IntentService 完全详解
关联文章: Android 多线程之HandlerThread 完全详解 Android 多线程之IntentService 完全详解 android多线程-AsyncTask之工作原理深入解析(上) ...
- Android 多线程之HandlerThread 完全详解
关联文章: Android 多线程之HandlerThread 完全详解 Android 多线程之IntentService 完全详解 android多线程-AsyncTask之工作原理深入解析(上) ...
- Android线程之Looper
之前已经为大家奉献了关于Handler和Message的使用,本篇我们来了解一下Handler内部的具体使用,本篇主要探讨Looper的在处理Handler的消息机制中起的重要作用,我们知道我们在子线 ...
- Android——多线程之Handler
Why? 因为在Android系统中UI操作并不是线程安全的,如果多个线程并发的去操作同一个组件,可能导致线程安全问题.为了解决这一个问题, android制定了一条规则:只允许UI线程来修改UI组件 ...
- Android-——多线程之Handler(转)
Android--多线程之Handler 原文地址:http://www.cnblogs.com/shirley-1019/p/3557800.html 前言 Android的消息传递机制是另外一种形 ...
- iOS多线程之8.NSOPeration的其他用法
本文主要对NSOPeration的一些重点属性和方法做出介绍,以便大家可以更好的使用NSOPeration. 1.添加依赖 - (void)addDependency:(NSOperation * ...
- python 线程之 threading(四)
python 线程之 threading(三) http://www.cnblogs.com/someoneHan/p/6213100.html中对Event做了简单的介绍. 但是如果线程打算一遍一遍 ...
- python 线程之 threading(三)
python 线程之 threading(一)http://www.cnblogs.com/someoneHan/p/6204640.html python 线程之 threading(二)http: ...
- python 线程之_thread
python 线程之_thread _thread module: 基本用法: def child(tid): print("hello from child",tid) _thr ...
随机推荐
- 得到一个文件夹中所有文件的名称的几个方法(命令指示符, C++, python)
因为最近一直需要获得一个文件下的所有图片的名称,自己又总是跨平台使用,所以把自己在不同环境之下使用的方法总结如下 1.cmd 模式下 优点:简单 例如,我想将一个文件夹下的所有".jpg&q ...
- JavaScript基础视频教程总结(121-130章)
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...
- fiddler抓包工具总结
Fiddler 抓包工具总结 Fiddler是一个蛮好用的抓包工具,可以将网络传输发送与接受的数据包进行截获.重发.编辑.转存等操作.也可以用来检测网络安全.反正好处多多,举之不尽呀!当年学习的时候也 ...
- [swarthmore cs75] Lab 1 — OCaml Tree Programming
课程回顾 Swarthmore学院16年开的编译系统课,总共10次大作业.本随笔记录了相关的课堂笔记以及第2大次作业. 比较两个lists的逻辑: let rec cmp l ll = match ( ...
- scrapy的入门使用(一)
1. scrapy项目实现流程 创建一个scrapy项目:scrapy startproject mySpider 生成一个爬虫:scrapy genspider 提取数据:完善spider,使用x ...
- UE4动画及相关物理的更新顺序图
- docker 私有 repository
为什么需要私有仓库? 首先假如公司内部有两台以上的服务器,使用docker管理应用程序,我在A服务器上创建了一个.net core 的镜像,需要在B服务器上共享这个镜像,怎么办?当然不能拷贝一份代码在 ...
- python中字典的操作
----------字典操作------------ --查字典1. 字典名["元素名称"]2. 字典名.get("元素名称")-获取不存在得元素名称,.get ...
- Linux更新源汇总-18.9.7更新
企业站 阿里云:https://opsx.alibaba.com/mirror 网易:http://mirrors.163.com/ 教育站 北京理工大学:http://mirror.bit.edu. ...
- 基本数据类型的包装类(Interger)
基本数据类型 vs包装类 byte Byte short Short char Character int Integer long Long float Float double Double bo ...