Android学习笔记(五) handler
一、基本概念
主要用于"异步消息"的处理.例如:
?在手机使用时,经常碰到这种情况:比如在我们下载的时候,若是将下载方法单独为一个Activity的时候,那么下载时,其他的Activity是没有响应的,那么这个时候整部手机就处于了当机的状态,而Handler就是用来解决这个问题的.
?意思就是说,将下载放在一个单独的线程,那么当这个线程执行的时候,并不会影响该Activity的线程.
二、使用方法?通过调用handler的post方法实现线程的操作.
一个最简单的Handler例子:
XML文件:
?
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:weightSum="1"><Button android:id="@+id/start"android:text="@string/opt_start"android:layout_height="wrap_content"android:layout_weight="0.38" android:layout_width="202dp"/><Button android:layout_height="wrap_content" android:id="@+id/end" android:text="@string/opt_end" android:layout_weight="0.38" android:layout_width="202dp"></Button></LinearLayout>
?
?
Handler文件:
?
package com.hadler;import android.accounts.Account;import android.accounts.OnAccountsUpdateListener;import android.app.Activity;import android.content.Intent;import android.os.Bundle;import android.os.Handler;import android.text.style.UpdateAppearance;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;public class Handlertest extends Activity { /** Called when the activity is first created. */private Button start;private Button end;OnClickListener start_listen = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); start = (Button)findViewById(R.id.start); end = (Button)findViewById(R.id.end); start_listen = (new OnClickListener(){ @Overridepublic void onClick(View v) {// TODO Auto-generated method stub //调用handler的post方法,将要执行的线程对象加到队列当中handler.post(updateThread);} }); start.setOnClickListener(start_listen); OnClickListener end_listen = (new OnClickListener() {@Overridepublic void onClick(View arg0) {// TODO Auto-generated method stubhandler.removeCallbacks(updateThread);}}); end.setOnClickListener(end_listen); } //创建一个Handler对象 Handler handler = new Handler(); //线程类,实现Runnable接口,将要执行的操作写在run方法中 Runnable updateThread = new Runnable(){@Overridepublic void run() {// TODO Auto-generated method stubSystem.out.println("UpdateThread");//在run方法内部,执行postDelayed或者post方法handler.postDelayed(updateThread, 3000);} }; }?
这个例子中可看到LogCat中每隔3秒中就打印一句UpdateThread.
即是,不影响当前Acvtivity,调用新的进程完成的代码段. 也就是异步处理.
?
?
三、使用handler更新ProgressBar进度条?接着看一个例子,更新进度条的
?
package mars.barhandler;import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.ProgressBar;public class TestBarHandler extends Activity { /** Called when the activity is first created. *///声明控件变量ProgressBar bar = null;Button startButton = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //根据控件的ID得到代表控件的对象,并为按钮设置监听器 bar = (ProgressBar)findViewById(R.id.bar); startButton = (Button)findViewById(R.id.startButton); startButton.setOnClickListener(new ButtonListener()); } //当点击startButton按钮时,就会执行ButtonListener的onClick方法 class ButtonListener implements OnClickListener{@Override//匿名内部类public void onClick(View v) {// TODO Auto-generated method stub//进度条设置为可见的bar.setVisibility(View.VISIBLE);//将线程对象updateThread马上加入到消息队列当中,立马执行线程,执行线程就是执行run方法updateBarHandler.post(updateThread);} } //使用匿名内部类来复写Handler当中的handleMessage方法 Handler updateBarHandler = new Handler(){@Overridepublic void handleMessage(Message msg) {//对已经压入消息队列的msg加入到线程队列里面bar.setProgress(msg.arg1)//设置进度条的当前值
Bundle bundle = msg.getData();updateBarHandler.post(updateThread);System.out.println("test---->" + bundle.getString("test"));} }; //线程类,该类使用匿名内部类的方式进行声明 Runnable updateThread = new Runnable(){ int i = 0 ;@Overridepublic void run() {System.out.println("Begin Thread" + i);i = i + 10 ;//得到一个消息对象,Message类是由Android操作系统提供Message msg = updateBarHandler.obtainMessage();//将msg对象的arg1参数的值设置为i,用arg1和arg2这两个成员变量传递消息,优点是系统性能消耗较少msg.arg1 = i ;Bundle bundle = new Bundle();bundle.putString("test", "test bundle");msg.setData(bundle);try {//设置当前线程睡眠1秒Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}//将msg对象加入到消息队列当中if( i > 100){//如果当i的值为100时,就将线程对象从handler当中移除updateBarHandler.removeCallbacks(updateThread);System.out.println(">>>>>>");}else{//将msg压入到消息队列中,压入之后就会去执行上面的handleMessage方法//每次执行完一次压入,上面代码就讲msg加入线程队列,只要i小于100,就一直循环这个操作updateBarHandler.sendMessage(msg);System.out.println("<<<<<<");}} }; class MyThread extends Thread{ public void run(){ } } }?
?原理如下:
?
?
sendMessage执行完之后就返回,继续执行他的方法,不管handlerMessage执行不执行,这就是异步.
?
?
四、Handler与线程当使用handler.post()方法时,并不是调用线程对象的start方法,而是在原本线程上直接调用run()方法。 所以说,Runnable这个线程在实际使用时并不把它当作一个新的线程.
?
只有当实例化了一个Runnable对象,并把该对象当作参数生成Thread对象的时候,才会启用新的进程,看下面两个代码:
?
不启动新的线程:
?
public class HandlerTest extends Activity {private Handler handler = new Handler();public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);/**这里如果先执行Handler的post方法,然后在对控件进行布局,若10秒钟之后才布局完成 * 则说明并没有启动了新的线程,onCreate函数和run函数是运行在同一个线程中的*/handler.post(r);setContentView(R.layout.main)
/**Thread.currentThread()中currentThread()是Thread的一个静态方法 * 返回的是当前的进程对象,为了帮助理解可以写为Thread t = Thread.currentThread() * 也就是说现在变量t就等于Thread.currentThread()。 * 有了上面的简化,现在可以写为t.getId() * 也就是说只是调用了t的一个方法.*/System.out.println("activity--->" + Thread.currentThread().getId());System.out.println("activityname--->" + Thread.currentThread().getName());}Runnable r = new Runnable(){@Overridepublic void run() {System.out.println("handler--->" + Thread.currentThread().getId());System.out.println("handlername--->" + Thread.currentThread().getName());try {Thread.sleep(10000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}};}?
?
启动新的进程:
?
public class HandlerTest extends Activity {private Handler handler = new Handler();public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);/**标准的java启动线程的方法,在下面实例化一个Runnable的对象r,并将r当作参数生成Thread的对象, * 这时候的线程就不一样了*/Thread t = new Thread(r) ;t.start();/**Thread.currentThread()中currentThread()是Thread的一个静态方法 * 返回的是当前的进程对象,为了帮助理解可以写为Thread t = Thread.currentThread() * 也就是说现在变量t就等于Thread.currentThread()。 * 有了上面的简化,现在可以写为t.getId() * 也就是说只是调用了t的一个方法.*/System.out.println("activity--->" + Thread.currentThread().getId());System.out.println("activityname--->" + Thread.currentThread().getName());}Runnable r = new Runnable(){@Overridepublic void run() {System.out.println("handler--->" + Thread.currentThread().getId());System.out.println("handlername--->" + Thread.currentThread().getName());try {Thread.sleep(10000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}};}五、Bundle的使用方法Bundle是一个以string为键,可以有其他数据类型作为值的一个mapping.相当于将所有数据类型打成一个包进行传递.
可以将Bundle看成一个特殊的map,它的key和value都是object类型的,也就是说它的值可以以任意的引用数据类型,但是键永远都是String类型的.
?
?
?
六、在新线程当中处理消息的方法??在新的线程中,使用Bundle来处理消息的例子:
?
package mars.handler;import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.os.HandlerThread;import android.os.Looper;import android.os.Message;public class HandlerTest2 extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.main);//打印了当前线程的IDSystem.out.println("Activity-->" + Thread.currentThread().getId());/**生成一个HandlerThread对象,实现了使用Looper来处理消息队列的功能这个类由Android应用程序框架提供*/HandlerThread handlerThread = new HandlerThread("handler_thread");/**在使用HandlerThread的getLooper()方法之前,必须先调用该类的start(); * 否则调用getLooper取得的Looper对象是为空的(Null)*/handlerThread.start();//使用getLooper()方法,得到线程里面使用的Looper对象,传给MyHandler,然后调用下面的构造函数MyHandler myHandler = new MyHandler(handlerThread.getLooper());/**获取消息对象*/Message msg = myHandler.obtainMessage();//将message发送给目标对象,由哪个Handler生成Message,哪个就是目标对象msg.sendToTarget();//将msg发送到目标对象,所谓的目标对象,就是生成该msg对象的handler对象Bundle b = new Bundle();b.putInt("age", 20);b.putString("name", "Jhon");//b是Bundle类型的对象,将b的参数放在msg中msg.setData(b);//发送messaga到目标MyHandlermsg.sendToTarget();}//构造函数class MyHandler extends Handler{public MyHandler(){}//将线程绑定在looper对象上public MyHandler(Looper looper){super(looper);}@Override/**Message的handlerMessage方法*/public void handleMessage(Message msg) {//取出对象Bundle b = msg.getData();//定义两个变量age和name来接收数据int age = b.getInt("age");String name = b.getString("name");System.out.println("age is " + age + ", name is" + name);System.out.println("Handler--->" + Thread.currentThread().getId());System.out.println("handlerMessage");}}}??
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
