Android -- Looper.prepare()和Looper.loop() —深度版
Android中的Looper类,是用来封装消息循环和消息队列的一个类,用于在android线程中进行消息处理。handler事实上能够看做是一个工具类。用来向消息队列中插入消息的。
(1) Looper类用来为一个线程开启一个消息循环。
默认情况下android中新诞生的线程是没有开启消息循环的。(主线程除外,主线程系统会自己主动为其创建Looper对象,开启消息循环。) Looper对象通过MessageQueue来存放消息和事件。
一个线程仅仅能有一个Looper。相应一个MessageQueue。
(2) 一般是通过Handler对象来与Looper进行交互的。
Handler可看做是Looper的一个接口。用来向指定的Looper发送消息及定义处理方法。 默认情况下Handler会与其被定义时所在线程的Looper绑定,比方,Handler在主线程中定义。那么它是与主线程的Looper绑定。
mainHandler = new Handler() 等价于new Handler(Looper.myLooper()). Looper.myLooper():获取当前进程的looper对象,类似的 Looper.getMainLooper() 用于获取主线程的Looper对象。
(3) 在非主线程中直接new Handler() 会报例如以下的错误: E/AndroidRuntime( 6173): Uncaught handler: thread Thread-8 exiting due to uncaught exception E/AndroidRuntime(
6173): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() 原因是非主线程中默认没有创建Looper对象,须要先调用Looper.prepare()启用Looper。
(4) Looper.loop(); 让Looper開始工作,从消息队列里取消息,处理消息。
注意:写在Looper.loop()之后的代码不会被执行,这个函数内部应该是一个循环,当调用mHandler.getLooper().quit()后。loop才会中止,其后的代码才干得以执行。
(5) 基于以上知识,可实现主线程给子线程(非主线程)发送消息。
把以下样例中的mHandler声明成类成员,在主线程通过mHandler发送消息就可以。
Android官方文档中Looper的介绍: Class used to run a message loop for a thread. Threads by default do not have a message loop
associated with them; to create one, call prepare() in the thread that is to run the loop, and then loop() to have it process messages until the loop is stopped.
Most interaction with a message loop is through the Handler class.
This is a typical example of the implementation of a Looper thread, using the separation of prepare() and loop() to create an initial Handler
to communicate with the Looper.
class LooperThread extends Thread
{
public Handler mHandler;
public void run()
{
Looper.prepare();
mHandler = new Handler()
{
public void handleMessage(Message msg)
{
// process incoming messages here
}
};
Looper.loop();
}
假设线程中使用Looper.prepare()和Looper.loop()创建了消息队列就能够让消息处理在该线程中完毕。
android HandlerThread使用小例
之前研究过handler 和 looper 消息队列。只是android里的handler不是另外开启线程来运行的。还是在主UI线程中,假设想另启线程的话须要用到HandlerThread来实现。在使用HandlerThread的时候须要实现CallBack接口以重写handlerMessage方法。在handlerMessage方法中来处理自己的逻辑。
下来给出一个小样例程序。
layout文件非常easy,就一个button来启动HanlderTread线程
<?xml version="1.0" encoding="utf-8"? >
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" > <TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" /> <Button
android:id="@+id/handlerThreadBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="startHandlerThread" /> </LinearLayout>
Activity代码例如以下:
package com.tayue; import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Handler.Callback;
import android.os.HandlerThread;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
/**
*
* @author xionglei
*
*/
public class TestHandlerActivity extends Activity implements OnClickListener{ public Button handlerThreadBTN;
MyHandlerThread handlerThread;
Handler handler; /** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//打印UI线程的名称
System.out.println("onCreate CurrentThread = " + Thread.currentThread().getName()); setContentView(R.layout.main); handlerThreadBTN = (Button) findViewById(R.id.handlerThreadBtn);
handlerThreadBTN.setOnClickListener(this); handlerThread = new MyHandlerThread("myHanler");
handlerThread.start();
//注意: 这里必须用到handler的这个构造器,由于须要把callback传进去,从而使自己的HandlerThread的handlerMessage来替换掉Handler原生的handlerThread
handler = new Handler(handlerThread.getLooper(), handlerThread);
} @Override
public void onClick(View v) {
//点击button后来开启线程
handler.sendEmptyMessage(1);
} private class MyHandlerThread extends HandlerThread implements Callback { public MyHandlerThread(String name) {
super(name);
} @Override
public boolean handleMessage(Message msg) {
//打印线程的名称
System.out.println(" handleMessage CurrentThread = " + Thread.currentThread().getName());
return true;
}
}
}
点击button。打印的日志例如以下(这里点击了3次) 07-06 09:32:48.776: I/System.out(780): onCreate CurrentThread = main 07-06 09:32:55.076: I/System.out(780): handleMessage CurrentThread = myHanler 07-06 09:32:58.669: I/System.out(780): handleMessage CurrentThread = myHanler 07-06 09:33:03.476:
I/System.out(780): handleMessage CurrentThread = myHanler
HandlerThread就这么简单。
当然 android自己也有异步线程的handler,就是AsyncTask。这个类就是封装了HandlerThread 和handler来实现异步多线程的操作的。
相同能够这样使用:
private boolean iscancel = false; //用户手动取消登录的标志位
handlerThread = new HandlerThread("myHandlerThread");
handlerThread.start();
handler = new MyHandler(handlerThread.getLooper());
// 将要运行的线程对象加入到线程队列中
handler.post(new Runnable() {
@Override
public void run() {
Message message = handler.obtainMessage();
UserBean user = Bbs.getInstance().Login(username, password);//耗时任务
Bundle b = new Bundle();
b.putSerializable("user", user);
message.setData(b);
message.sendToTarget(); //或使用 handler.sendMessage(message);
}
});
class MyHandler extends Handler {
public MyHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
if(iscancel == false){
// 操作UI线程的代码
Bundle b = msg.getData();
UserBean user = (UserBean)b.get("user");
......
}
}
}
Android -- Looper.prepare()和Looper.loop() —深度版的更多相关文章
- Android -- Looper.prepare()和Looper.loop() —深入版
Android中的Looper类,是用来封装消息循环和消息队列的一个类,用于在android线程中进行消息处理.handler其实可以看做是一个工具类,用来向消息队列中插入消息的. (1) Loope ...
- 【转】Android -- Looper.prepare()和Looper.loop()
Looper.prepare()和Looper.loop() 原文地址:http://blog.csdn.net/heng615975867/article/details/9194219 Andro ...
- Looper.prepare()和Looper.loop()
什么时候需要 Looper Looper用于封装了android线程中的消息循环,默认情况下一个线程是不存在消息循环(message loop)的,需要调用Looper.prepare()来给线程创建 ...
- Android 线程 Looper.prepare()、Looper.loop() 使用
优化项目过程中发现了一个非常Low的问题,整理一下.备忘: 说问题之前先看下HandlerThread的定义 一个封装了looper的线程: Looper用于封装了android线程中的消息循环. ...
- Android handler 报错处理Can't create handler inside thread that has not called Looper.prepare()
问题: 写了一个sdk给其他人用,提供一个回调函数,函数使用了handler处理消息 // handler监听网络请求,完成后操作回调函数 final Handler trigerGfHandler ...
- Android进阶(十六)子线程调用Toast报Can't create handler inside thread that has not called Looper.prepare() 错误
原子线程调用Toast报Can't create handler inside thread that has not called Looper.prepare() 错误 今天用子线程调Toast报 ...
- ThreadLocal ——android消息机制handler在非主线程创建not called Looper.prepare() 错误的原因
引用自:https://www.jianshu.com/p/a8fa72e708d3 引出: 使用Handler的时候,其必须要跟一个Looper绑定.在UI线程可直接初始化Handler来使用.但是 ...
- android 37 线程通信Looper
安卓程序的主线程也叫UI线程. 工作线程和主线程的差别:安卓主线程已经调用了Looper.prepare()方法了,已经有一个MessageQueue对象了,所以才可以在工作线程用Handler发消息 ...
- 「Android」消息驱动Looper和Handler类分析
Android系统中的消息驱动工作原理: 1.有一个消息队列,可以往这个消息队列中投递消息; 2.有一个消息循环,不断的从消息队列中取得消息,然后处理. 工作流程: 1.事件源将待处理的消息加入到消息 ...
随机推荐
- 如何搭建NTP服务(转)
最近,在搭建Oracle RAC过程中,需要用到DNS和NTP,其中,DNS用于域名.IP管理,NTP用于时间同步.其实,很久以前搭建过这两种服务,但技术,本质上,符合“用进废退”的客观规律.用得越频 ...
- 给一个非常长的字符串str 另一个字符集比方{a,b,c} 找出str 里包括{a,b,c}的最短子串。要求O(n)
给一个非常长的字符串str 另一个字符集比方{a,b,c} 找出str 里包括{a,b,c}的最短子串.要求O(n). 比方,字符集是a,b,c,字符串是abdcaabcx,则最短子串为abc. 设置 ...
- 在VM已安装Android4.4 连接小米手环 网络设置
1.打开一个终端 2.输入su,选择同意 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGl5dW4xMjNneA==/font/5a6L5L2T/fon ...
- IE8,IE9,IE10,FireFox 的CSS HACK
#employeesView { top: 732px; //所有浏览器 top: 730px\9;//所有IE浏览器 } @media all and (min-width:0) { #employ ...
- poj1679(最小生成树)
传送门:The Unique MST 题意:判断最小生成树是否唯一. 分析:先求出原图的最小生成树,然后枚举删掉最小生成树的边,重做kruskal,看新的值和原值是否一样,一样的话最小生成树不唯一. ...
- Android_多媒体_SoundPool声音池使用
1.SoundPool概述 SoundPool就相当于一个简单的集合,可以将apk中的资源或者系统中的文件加载至内存中,使用了MediaPlayer服务区解码音频文件,用SoundPool可以播一些短 ...
- 已知直线上的两点 A(x1, y1), B(x2, y2) 和另外一点 C(x0, y0),求C点到直线的距离。
数学知识太差,一点点积累,高手勿喷. 1. 先求出AB向量 a = ( x2-x1, y2-y1 ) 2. 求AB向量的单位方向向量 b = √((x2-x1)^2 + (y2-y1)^2)) a1 ...
- follow through
follow through是什么意思_follow through的翻译_音标_读音_用法_例句 - 必应 Bing Dictionary Web Images Videos Maps News D ...
- Jndi使用好处,与简单实例【Tomcat】
JNDI学习总结(一)——JNDI数据源的配置 一.数据源的由来 在Java开发中,使用JDBC操作数据库的四个步骤如下: ①加载数据库驱动程序(Class.forName("数据库驱动 ...
- 如何用C#使用java
如何使用C#调用Java 今天需要使用C#调用Java的包,研究了一下,大体是以下几种解决方案: 把Java包转换为DLL或者EXE后注册为com组件,之后调用. 使用web service 比如:H ...