looper

来源:互联网 发布:手机上能设计淘宝店吗 编辑:程序博客网 时间:2024/05/20 14:43
实际上:消息发送和计划任务提交之后,它们都会进入某线程的消息队列中,我们可以把这个线程称之为目标线程。不论是主线程还是子线程都可以成为目标线程。上例中之所以在主线程中处理消息,是因为我们要更新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 
plaincopyprint?

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 
plaincopyprint?

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消息处理机制对于应用程序开发非常重要,也可以让我们对线程同步有更加深刻的认识,希望这篇文章可以对朋友们有所帮助。

//这里的looper还是通过Looper.mylooper得到的单例模式

之所以会向这个线程发送信息

  1. public Looper getLooper() {  
  2.         if (!isAlive()) {  
  3.             return null;  
  4.         }  
  5.   
  6.         // If the thread has been started, wait until the looper has been created.  
  7.         synchronized (this) {  
  8.             while (isAlive() && mLooper == null) {  
  9.                 try {  
  10.                     wait();  
  11.                 } catch (InterruptedException e) {  
  12.                 }  
  13.             }  
  14.         }  
  15.         return mLooper;  
  16.     }  
  17. }  
是因为threadhandler的Looper getLooper()里面有一个锁的原因

0 0
原创粉丝点击