安卓looper怎么工作的
Ⅰ android中looper的实现原理,为什么调用looper.prepare就在当前线程关联了一个lo
实际上:消息发送和计划任务提交之后,它们都会进入某线程的消息队列中,我们可以把这个线程称之为目标线程。不论是主线程还是子线程都可以成为目标线程。上例中之所以在主线程中处理消息,是因为我们要更新UI,按照android中的规定我们必须由主线程更新UI。所以我们让主线程成为了目标线程。
那么如何控制让某个线程成为目标线程呢?
这就引出了Looper的概念。Android系统中实现了消息循环机制,Android的消息循环是针对线程的,每个线程都可以有自己的消息队列和消息循环。Android系统中的通过Looper帮助线程维护着一个消息队列和消息循环。通过Looper.myLooper()得到当前线程的Looper对象,通过Looper.getMainLooper()得到当前进程的主线程的Looper对象。
前面提到每个线程都可以有自己的消息队列和消息循环,然而我们自己创建的线程默认是没有消息队列和消息循环的(及Looper),要想让一个线程具有消息处理机制我们应该在线程中先调用Looper.prepare()来创建一个Looper对象,然后调用Looper.loop()进入消息循环。如上面的源码所示。
当我们用Handler的构造方法创建Handler对象时,指定handler对象与哪个具有消息处理机制的线程(具有Looper的线程)相关联,这个线程就成了目标线程,可以接受消息和计划任务了。Handler中的构造方法如下:
[java] view
plainprint?
public Handler() {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = null;
}
public Handler(Looper looper) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = null;
}
public Handler() {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = null;
}
public Handler(Looper looper) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = null;
}
在上述的计时器的例子中,之所以可以在主线程中处理消息而我们自己并没有调用Looper.prepare()等方法,是因为Android系统在Activity启动时为其创建一个消息队列和消息循环,当我们用无参的Handler构造方法创建对象时又用了当前线程的Looper对象,及将handler与主线程中的Looper对象进行了关联。
android中是使用Looper机制来完成消息循环的,但每次创建线程时都先初始化Looper比较麻烦,因此Android为我们提供了一个HandlerThread类,他封装了Looper对象,是我们不用关心Looper的开启和释放问题。
不管是主线程还是其他线程只要有Looper的线程,别的线程就可以向这个线程的消息队列中发送消息和任务。
我们使用HandlerThread类代替上一篇文章中的子线程,并用HandlerThread类中的Looper对象构造Handler,则接受消息的目标线程就不是主线程了,而是HandlerThread线程。代码如下:
[java] view
plainprint?
public class clockActivity extends Activity {
/** Called when the activity is first created. */
private String TAG="clockActivity";
private Button endButton;
private TextView textView;
private int timer=0;
private boolean isRunning=true;
private Handler handler;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
endButton=(Button)findViewById(R.id.endBtn);
textView=(TextView)findViewById(R.id.textview);
endButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
isRunning=false;
}
});
HandlerThread thread=new HandlerThread("myThread");
handler=new Handler(thread.getLooper());//与HandlerThread中的Looper对象关联
thread.start();
Runnable r=new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub
if(isRunning){
textView.setText("走了"+timer+"秒");
timer++;
handler.postDelayed(this, 1000);//提交任务r,延时1秒执行
}
}
};
handler.postDelayed(r, 1000);
}
}
public class clockActivity extends Activity {
/** Called when the activity is first created. */
private String TAG="clockActivity";
private Button endButton;
private TextView textView;
private int timer=0;
private boolean isRunning=true;
private Handler handler;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
endButton=(Button)findViewById(R.id.endBtn);
textView=(TextView)findViewById(R.id.textview);
endButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
isRunning=false;
}
});
HandlerThread thread=new HandlerThread("myThread");
handler=new Handler(thread.getLooper());//与HandlerThread中的Looper对象关联
thread.start();
Runnable r=new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub
if(isRunning){
textView.setText("走了"+timer+"秒");
timer++;
handler.postDelayed(this, 1000);//提交任务r,延时1秒执行
}
}
};
handler.postDelayed(r, 1000);
}
}
此时处理任务会在handlerThread线程中完成。当然这个例子会出线异常:依然是因为在非主线程中更新了UI。这样做只是为了大家能够理解这种机制。
深入理解Android消息处理机制对于应用程序开发非常重要,也可以让我们对线程同步有更加深刻的认识,希望这篇文章可以对朋友们有所帮助。
Ⅱ android looper 怎么理解
Android
中
Looper
和
handler
的联系及处理
最近一直在看
Android
内核的代码。把
Looper
及
Handler
这一节先分享一下:
Handle
主要起一个代理中介的作用,具体对象要向底层发请求,得通过
Handler
,
Handler
把这个请求放进对应的
MessageQueue
(消息队列)中,而
MessageQueue
是由
Looper
来维护的。
Looper
中有一个循环,循环读取
MessageQueue
中的请求,发给相应的底层处理(这个过程有点复杂)。当底层
有信息返回时,
也会先放进
MessageQueue
中,
然后对应的
Looper
遍历,
交给对
应的
Handler
处理。
Handler
找出对应的回调函数或其他已注册的相关方法,让
其进行处理,最终在界面有一个反应。
以下是我写的一个
demo
,
主要是如何关联
Looper
、
Handler
、
以及对应的线程
(
MessageQueue
是
Looper
的一个成员)。
1.
测试方法入口:
testLooper1.java
package com.linquan.test.loop1;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
public class testLooper1 extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.d(MyConstant.TAG, "main start...");
new MyThread().start();
Message msg = new Message();
msg.what = MyConstant.CONSTANT3;
while(MyThread.h == null){
Log.d(MyConstant.TAG, "handler is not init ! please wait a
monment....");
try {
Thread.sleep(300);//
由于这里是测试,
所以加上此行代码,
避免出错。
实
际中多为用户触发事件,此时
handle
应该已经初始化了。
} catch (InterruptedException e) {
e.printStackTrace();
Ⅲ android里面所说的looper是什么意思啊
Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。
Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message
msg)方法来对特定的Message进行处理,例如更新UI等。
MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO规则执行。当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。
Looper:消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper。
Thread:线程,负责调度整个消息循环,即消息循环的执行场所
Ⅳ looper的作用 android 为什么要循环
给你举个例子:
用handler传递消息时候。你先sendmessage。这时候消息到looper然后你再looper当中更具msg.what获取相应的消息。looper相当于一个消息收取中介。所以要有循环。我自己的理解。
Ⅳ Android的handler机制的原理
Android的handler机制的原理分为异步通信准备,消息发送,消息循环,消息处理。
1、异步通信准备
在主线程中创建处理器对象(Looper)、消息队列对象(Message Queue)和Handler对象。
2、消息入队
工作线程通过Handler发送消息(Message) 到消息队列(Message Queue)中。
3、消息循环
消息出队: Looper循环取出消息队列(Message Queue) 中的的消息(Message)。
消息分发: Looper将取出的消息 (Message) 发送给创建该消息的处理者(Handler)。
4、消息处理
处理者(Handler) 接收处理器(Looper) 发送过来的消息(Message),根据消息(Message) 进行U操作。
handler的作用
handler是android线程之间的消息机制,主要的作用是将一个任务切换到指定的线程中去执行,(准确的说是切换到构成handler的looper所在的线程中去出处理)android系统中的一个例子就是主线程中的所有操作都是通过主线程中的handler去处理的。
Handler的运行需要底层的 messagequeue和 looper做支撑。
Ⅵ [Android源码分析] - 异步通信Handler机制
一、问题:在Android启动后会在新进程里创建一个主线程,也叫UI线程( 非线程安全 )这个线程主要负责监听屏幕点击事件与界面绘制。当Application需要进行耗时操作如网络请求等,如直接在主线程进行容易发生ANR错误。所以会创建子线程来执行耗时任务,当子线程执行完毕需要通知UI线程并修改界面时,不可以直接在子线程修改UI,怎么办?
解决方法:Message Queue机制可以实现子线程与UI线程的通信。
该机制包括Handler、Message Queue、Looper。Handler可以把消息/ Runnable对象 发给Looper,由它把消息放入所属线程的消息队列中,然后Looper又会自动把消息队列里的消息/Runnable对象 广播 到所属线程里的Handler,由Handler处理接收到的消息或Runnable对象。
1、Handler
每次创建Handler对象时,它会自动绑定到创建它的线程上。如果是主线程则默认包含一个Message Queue,否则需要自己创建一个消息队列来存储。
Handler是多个线程通信的信使。比如在线程A中创建AHandler,给它绑定一个ALooper,同时创建属于A的消息队列AMessageQueue。然后在线程B中使用AHandler发送消息给ALooper,ALooper会把消息存入到AMessageQueue,然后再把AMessageQueue广播给A线程里的AHandler,它接收到消息会进行处理。从而实现通信。
2、Message Queue
在主线程里默认包含了一个消息队列不需要手动创建。在子线程里,使用Looper.prepare()方法后,会先检查子线程是否已有一个looper对象,如果有则无法创建,因为每个线程只能拥有一个消息队列。没有的话就为子线程创建一个消息队列。
Handler类包含Looper指针和MessageQueue指针,而Looper里包含实际MessageQueue与当前线程指针。
下面分别就UI线程和worker线程讲解handler创建过程:
首先,创建handler时,会自动检查当前线程是否包含looper对象,如果包含,则将handler内的消息队列指向looper内部的消息队列,否则,抛出异常请求执行looper.prepare()方法。
- 在 UI线程 中,系统自动创建了Looper 对象,所以,直接new一个handler即可使用该机制;
- 在 worker线程 中,如果直接创建handler会抛出运行时异常-即通过查‘线程-value’映射表发现当前线程无looper对象。所以需要先调用Looper.prepare()方法。在prepare方法里,利用ThreadLocal<Looper>对象为当前线程创建一个Looper(利用了一个Values类,即一个Map映射表,专为thread存储value,此处为当前thread存储一个looper对象)。然后继续创建handler, 让handler内部的消息队列指向该looper的消息队列(这个很重要,让handler指向looper里的消息队列,即二者共享同一个消息队列,然后handler向这个消息队列发送消息,looper从这个消息队列获取消息) 。然后looper循环消息队列即可。当获取到message消息,会找出message对象里的target,即原始发送handler,从而回调handler的handleMessage() 方法进行处理。
- handler与looper共享消息队列 ,所以handler发送消息只要入列,looper直接取消息即可。
- 线程与looper映射表 :一个线程最多可以映射一个looper对象。通过查表可知当前线程是否包含looper,如果已经包含则不再创建新looper。
5、基于这样的机制是怎样实现线程隔离的,即在线程中通信呢。
核心在于 每一个线程拥有自己的handler、message queue、looper体系 。而 每个线程的Handler是公开 的。B线程可以调用A线程的handler发送消息到A的共享消息队列去,然后A的looper会自动从共享消息队列取出消息进行处理。反之一样。
二、上面是基于子线程中利用主线程提供的Handler发送消息出去,然后主线程的Looper从消息队列中获取并处理。那么还有另外两种情况:
1、主线程发送消息到子线程中;
采用的方法和前面类似。要在子线程中实例化AHandler并设定处理消息的方法,同时由于子线程没有消息队列和Looper的轮询,所以要加上Looper.prepare(),Looper.loop()分别创建消息队列和开启轮询。然后在主线程中使用该AHandler去发送消息即可。
2、子线程A与子线程B之间的通信。
1、 Handler为什么能够实现不同线程的通信?核心点在哪?
不同线程之间,每个线程拥有自己的Handler、消息队列和Looper。Handler是公共的,线程可以通过使用目标线程的Handler对象来发送消息,这个消息会自动发送到所属线程的消息队列中去,线程自带的Looper对象会不断循环从里面取出消息并把消息发送给Handler,回调自身Handler的handlerMessage方法,从而实现了消息的线程间传递。
2、 Handler的核心是一种事件激活式(类似传递一个中断)的还是主要是用于传递大量数据的?重点在Message的内容,偏向于数据传输还是事件传输。
目前的理解,它所依赖的是消息队列,发送的自然是消息,即类似事件中断。
0、 Android消息处理机制(Handler、Looper、MessageQueue与Message)
1、 Handler、Looper源码阅读
2、 Android异步消息处理机制完全解析,带你从源码的角度彻底理解
谢谢!
wingjay

Ⅶ android里面所说的looper是什么意思啊
Looper即:有消息循环的线程。
在Android里线程分为有消息循环的线程和没有消息循环的线程,有消息循环的线程一般都会有一个Looper,这个事android的新概念。主线程(UI线程)就是一个消息循环的线程。针对这种消息循环的机制,引入一个新的机制Handle,有消息循环,就要往消息循环里 面发送相应的消息,自定义消息一般都会有对应的处理,消息的发送和清除,消息的处理,把这些都封装在Handle里面,注意Handle只是针对那些有Looper的线程,不管是UI线程还是子线程,只要有Looper,就可以往消息队列里面添加东西,并做相应的处理。
Ⅷ Handler的工作原理。为什么在子线程中使用Handler会抛出异常
Handler了它在安卓中常见的工作就是子线程与主线程的通信,其实可以直接归类为线程和线程间的通信
谈到Handler会涉及到以下几个类
Handler、Message、Looper、MessageQueue
我们一个一个来说,首先设置场景在一个线程中通知另一个线程
1,创建Looper和创建MessageQueue
首先在一个线程里要用Handler,那么需要准备Looper,调用Looper.prepare(),我们在主线程里面不用准备Looper,那么是因为在我们的主线程中已经给我们初始化好了Looper,
在准备Looper的时候会去校验这个线程中是否存在Looper,如果有Looper那么抛出异常(注意:有一些面试官会问如何判断一个线程中是否存在一个Looper的,它用的是ThreadLocal,它的作用是在线程范围内保证变量的唯一性,Thread中会维护一个类似HashMap的东西,然后用ThreadLocal对象作为key,value就是要存储的变量值,这样就保证了存储数据的唯一性)
如果没有Looper那么new一个Looper,new Looper的同时会new 一个MessageQueue(注意:一个线程中只有一个Looper一个MessageQueue)
然后Looper.loop()就可以启动轮训来轮训消息队列了
2,创建Handler
这个我们在熟悉不过了,继承一个Handler然后复写handlerMessage方法,这里其实面试官也可以问一些比较细致的问题,如下
注意:有面试官会问可以创建几个Handler,我负责任的说是多个,哪个Handler发送的消息哪个Handler处理(吐槽一下有的面试官,你自己把自己要问的问题搞清楚了在去问别人,非要跟我犟只能创建一个)
3,创建Message
Message一般都是使用Message.obtain(),它这里面是有一个spool指向一个Message对象,还有一个next指向下一个Message,它里面维护了一个链表,obtain的时候在表头头取Message,在Message回收的时候在表头添加一个Message,类似栈,默认大小是50
4,消息的处理
Handler对象sendMessage发送消息放入的MessageQueue队列中,Looper轮训到它,然后就开始处理Message,Message会有一个target去记录是哪个Handler发送的它,会调用这个Handler中的dispatchMessage()方法,如果说Message中实现了CallBack那么调用Message中的CallBack,如果Handler中实现了Callback调用Handler中CallBack,否则就都调动Handler中的handleMessage方法
根据上面的原理分析,那就是因为你子线程中没有Looper,给他一个Looper就好了
Ⅸ Android-Looper
Looper.loop是一个死循环,拿不到需要处理的Message就会阻塞,那在UI线程中为什么不会导致ANR?
首先我们来看造成ANR的原因:
1.当前的事件没有机会得到处理(即主线程正在处理前一个事件,没有及时的完成或者looper被某种原因阻塞住了)
2.当前的事件正在处理,但没有及时完成
我们再来看一下APP的入口ActivityThread的main方法:
显而易见的,如果main方法中没有looper进行死循环,那么主线程一运行完毕就会退出,会导致直接崩溃,还玩什么!
现在我们知道了消息循环的必要性,那为什么这个死循环不会造成ANR异常呢?
我们知道Android 的是由事件驱动的,looper.loop() 不断地接收事件、处理事件,每一个点击触摸或者说Activity的生命周期都是运行在 Looper的控制之下,如果它停止了,应用也就停止了。只能是某一个消息或者说对消息的处理阻塞了 Looper.loop(),而不是 Looper.loop() 阻塞它,这也就是我们为什么不能在UI线程中处理耗时操作的原因。
主线程Looper从消息队列读取消息,当读完所有消息时,主线程阻塞。子线程往消息队列发送消息,唤醒主线程,主线程被唤醒只是为了读取消息,当消息读取完毕,再次睡眠。因此loop的循环并不会对CPU性能有过多的消耗。
初始化当前线程和Looper,这样可以在实际开始启动循环(loop())之前创建一个Handler并且关联一个looper。确保在先调用这个方法,然后调用loop()方法,并且通过调用quit()结束。
这里面的入参boolean表示Looper是否允许退出,true就表示允许退出,对于false则表示Looper不允许退出。
初始化当前当前线程的looper。并且标记为一个程序的主Looper。由Android环境来创建应用程序的主Looper。因此这个方法不能由咱们来调用。另请参阅prepare()
这里的sThreadLocal.get()是和prepare(boolean)方法里面的sThreadLocal.set(new Looper(quitAllowed));一一对应的。而在prepareMainLooper()方法里面。
退出循环
将终止(loop()方法)而不处理消息队列中的任何更多消息。在调用quit()后,任何尝试去发送消息都是失败的。例如Handler.sendMessage(Message)方法将返回false。因为循环终止之后一些message可能会被无法传递,所以这个方法是不安全的。可以考虑使用quitSafely()方法来确保所有的工作有序地完成。
安全退出循环
调用quitSafely()方法会使循环结束,只要消息队列中已经被传递的所有消息都将被处理。然而,在循环结束之前,将来不会提交处理延迟消息。
调用退出后,所有尝试去发送消息都将失败。就像调用Handler.sendMessage(Message)将返回false。