Handler相关说明:
解释:安卓的UI线程(即OnCreate函数创建的线程)是线程非安全的。也就是说,在UI线程中,使用sleep这样的函数会导致整个线程延迟,但是我们在安卓开发中,往往会经常遇到一些延迟比较厉害的操作,(例如通过HTTP获取数据信息)如果放在主线程中,则会影响UI界面的渲染。但是如果另外新开一个线程,则由于UI线程只能在主线程中修改,而导致无法修改主线程的UI界面。这个时候Handler就出来解决这个问题。
handler可以分发Message对象和Runnable对象到主线程中, 每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程), 也就是说Handler对象初始化后,就默认与对它初始化的进程的消息队列绑定,因此可以利用Handler所包含的消息队列,制定一些操作的顺序。
Handler主要两大作用:
1. 提供post操作。post操作主要将Runnable对象放进主线程(UI)线程中的队列中操作。post还支持延迟操作。使用post后,Runnable是按照队列的形式逐个执行的。
2. handlerMessage操作。主要用于新开一个线程与主线程中的通信。新开的线程执行完毕后,可以通过sendMessage给主线程发送消息,并且传递一些参数,然后主线程就可以修改UI界面了。
Handler提供的函数:
post类方法允许你排列一个Runnable对象到主线程队列中:
post(Runnable)
postAtTime(Runnable,long)
postDelayed(Runnable long)
sendMessage类方法, 允许你安排一个带数据的Message对象到队列中:
sendEmptyMessage(int)
sendMessage(Message)
sendMessageAtTime(Message,long)
sendMessageDelayed(Message,long)
应用实例:
1,传递Message。用于接受子线程发送的数据, 并用此数据配合主线程更新UI。
在Android中,对于UI的操作通常需要放在主线程中进行操作。如果在子线程中有关于UI的操作,那么就需要把数据消息作为一个Message对象发送到消息队列中,然后,用Handler中的handlerMessge方法处理传过来的数据信息,并操作UI。类sendMessage(Message msg)方法实现发送消息的操作。 在初始化Handler对象时重写的handleMessage方法来接收Messgae并进行相关操作。
2,传递Runnable对象。用于通过Handler绑定的消息队列,安排不同操作的执行顺序。
Handler对象在进行初始化的时候,会默认的自动绑定消息队列。利用类post方法,可以将Runnable对象发送到消息队列中,按照队列的机制按顺序执行不同的Runnable对象中的run方法。
另外,Android的CPU分配的最小单元是线程,Handler一般是在某个线程里创建的,因而Handler和Thread就是相互绑定的,一一对应。而Runnable是一个接口,Thread是Runnable的子类。所以说,他俩都算一个进程。xml文件:
/>
/>
View Code
packagecom.example.androidexpriment;importandroid.app.Activity;importandroid.os.Bundle;importandroid.os.Handler;importandroid.util.Log;importandroid.view.View;importandroid.view.View.OnClickListener;importandroid.widget.Button;public class MainActivity extendsActivity {private String TAG = "MainActivity";//声明两个按钮控件
private Button startButton = null;private Button endButton = null;
@Overridepublic voidonCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);//根据控件的ID得到代表控件的对象,并为这两个按钮设置相应的监听器
startButton =(Button)findViewById(R.id.startButton);
startButton.setOnClickListener(newStartButtonListener());
endButton=(Button)findViewById(R.id.endButton);
endButton.setOnClickListener(newEndButtonListener());
Log.i(TAG,"Activity-->" +Thread.currentThread().getId());
}class StartButtonListener implementsOnClickListener{
@Overridepublic voidonClick(View v) {//调用Handler的post方法,将要执行的线程对象添加到队列当中
handler.post(updateThread);
}
}class EndButtonListener implementsOnClickListener{
@Overridepublic voidonClick(View v) {
handler.removeCallbacks(updateThread);
}
}//创建一个Handler对象
Handler handler = newHandler();//将要执行的操作写在线程对象的run方法当中
Runnable updateThread = newRunnable(){
@Overridepublic voidrun() {
Log.i(TAG,"UpdateThread");
Log.i(TAG,"Activity-->" +Thread.currentThread().getId());//在run方法内部,执行postDelayed或者是post方法
handler.postDelayed(updateThread, 3000);
}
};
}
点击start后,程序的运行结果就是每隔3秒钟,就会在控制台打印一行UpdateTread。这是因为实现了Runnable接口的updateThread对象进入了空的消息队列即被立即执行run方法,而在run方法的内部,又在3000ms之后将其再次发送进入消息队列中。
注意这种方法创建Handler对象并不需要重写handlerMessage方法。
从输出结果能看出来:
post方法虽然发送的是一个实现了Runnable接口的类对象,但是它并非创建了一个新线程,而是执行了该对象中的run方法。也就是说,整个run中的操作和主线程处于同一个线程。这样对于那些简单的操作,似乎并不会影响。但是对于耗时较长的操作,就会出现“假死”。为了解决这个问题,就需要使得handler绑定到一个新开启线程的消息队列上,在这个处于另外线程的上的消息队列中处理传过来的Runnable对象和消息。Runnable对象只是作为一个封装了操作的对象被传递,并未产生新线程。
下面这种写法也是可以的:
packagecom.example.androidexpriment;importandroid.app.Activity;importandroid.os.Bundle;importandroid.os.Handler;importandroid.util.Log;importandroid.view.View;importandroid.view.View.OnClickListener;importandroid.widget.Button;public class MainActivity extendsActivity {
TestThread t= null;private String TAG = "MainActivity";//声明两个按钮控件
private Button startButton = null;private Button endButton = null;
@Overridepublic voidonCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);//根据控件的ID得到代表控件的对象,并为这两个按钮设置相应的监听器
startButton =(Button)findViewById(R.id.startButton);
startButton.setOnClickListener(newStartButtonListener());
endButton=(Button)findViewById(R.id.endButton);
endButton.setOnClickListener(newEndButtonListener());
Log.i(TAG,"onCreate-->" +Thread.currentThread().getId());
t= new TestThread(1);
}class StartButtonListener implementsOnClickListener{
@Overridepublic voidonClick(View v) {//调用Handler的post方法,将要执行的线程对象添加到队列当中
handler.post(t);
}
}class EndButtonListener implementsOnClickListener{
@Overridepublic voidonClick(View v) {
handler.removeCallbacks(t);
}
}//创建一个Handler对象
Handler handler = newHandler();class TestThread extendsThread{intprime;
TestThread(intprime) {this.prime =prime;
}
@Overridepublic voidrun() {//在run方法内部,执行postDelayed或者是post方法
handler.postDelayed(t, 3000);
Log.i(TAG,"TestThread-->" +Thread.currentThread().getId());
}
}
}
虽然创建了一个Thread,但是并没有执行Thread的start()方法。考虑到Thread和Runnable之间的关系,上面的两种代码并无实质差别,所以logcat中甚至都没出现启动新线程的日志。
然而,如果稍加修改:加上启动方法
class StartButtonListener implementsOnClickListener{
@Overridepublic voidonClick(View v) {//调用Handler的post方法,将要执行的线程对象添加到队列当中
handler.post(t);
t.start();
}
}
可以明显看到,虽然启动了新线程,但post仍然可以把这个线程推到主线程里面去,线程由虚拟机自动结束。
所以,在UI线程(主线程)中:
mHandler=new Handler();
mHandler.post(new Runnable(){
void run(){
//执行代码..
}
});
这个线程其实是在UI线程之内运行的,并没有新建线程。
常见的新建线程的方法是:参考J2SE文档的
1、
class PrimeThread extends Thread {
long minPrime;
PrimeThread(long minPrime) {
this.minPrime = minPrime;
}
public void run() {
// compute primes larger than minPrime
. . .
}
}
The following code would then create a thread and start it running:
PrimeThread p = new PrimeThread(143);
p.start();
2、
class PrimeRun implements Runnable {
long minPrime;
PrimeRun(long minPrime) {
this.minPrime = minPrime;
}
public void run() {
// compute primes larger than minPrime
. . .
}
}
The following code would then create a thread and start it running:
PrimeRun p = new PrimeRun(143);
new Thread(p).start();
尽量按照上面给出的两种方式做,不要受网上影响简单的从Threa创建,那样不能做到传递参数。
static void
Causes the currently executing thread to sleep (temporarily cease execution) for the specified number of milliseconds, subject to the precision and accuracy of system timers and schedulers.
代码验证:
packagecom.example.androidexpriment;importandroid.app.Activity;importandroid.os.Bundle;importandroid.os.Handler;importandroid.os.Message;importandroid.util.Log;importandroid.view.View;importandroid.view.View.OnClickListener;importandroid.widget.Button;public class MainActivity extendsActivity {private String TAG = "MainActivity";//声明两个按钮控件
private Button startButton = null;private Button endButton = null;
TestThread t= null;int flag = 0;
@Overridepublic voidonCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);//根据控件的ID得到代表控件的对象,并为这两个按钮设置相应的监听器
startButton =(Button)findViewById(R.id.startButton);
startButton.setOnClickListener(newStartButtonListener());
endButton=(Button)findViewById(R.id.endButton);
endButton.setOnClickListener(newEndButtonListener());
Log.i(TAG,"onCreate-->" +Thread.currentThread().getId());
t= new TestThread(1);
}class StartButtonListener implementsOnClickListener{
@Overridepublic voidonClick(View v) {//调用Handler的post方法,将要执行的线程对象添加到队列当中
t.start();
}
}class EndButtonListener implementsOnClickListener{
@Overridepublic voidonClick(View v) {
handler.sendEmptyMessage(33);
flag= 5;
}
}class TestThread extendsThread{intprime;
TestThread(intprime) {this.prime =prime;
}
@Overridepublic voidrun() {//在run方法内部,执行postDelayed或者是post方法
try{while(true) {
Log.i(TAG,"TestThread-->" +Thread.currentThread().getId());//handler.sendEmptyMessageDelayed(22,3000);
Thread.sleep(3000);
handler.sendEmptyMessage(22);if(flag == 5) //线程最佳的退出方法,就是自杀,也就是在线程的函数里面自然的return 出来
return;
}
}catch(InterruptedException e) {//TODO Auto-generated catch block
e.printStackTrace();
}
}
}//创建一个Handler对象
Handler handler = newHandler(){
@Overridepublic voidhandleMessage(Message msg) {//TODO Auto-generated method stub
super.handleMessage(msg);switch(msg.what) {case 22:
Log.i(TAG,"StartButton");
Log.i(TAG,"Handler-->" +Thread.currentThread().getId());break;case 33:
Log.i(TAG,"EndButton");
Log.i(TAG,"Handler-->" +Thread.currentThread().getId());break;
}
}
};
}