Android 学习 笔记_02. handler的使用
![](http://images0.cnblogs.com/blog/433994/201302/08193419-56a354085aba4989add778a645bc8220.png)
1 package zzl.handleactivity; 2 3 import android.app.Activity; 4 import android.os.Bundle; 5 import android.os.Handler; 6 import android.os.Message; 7 import android.view.Gravity; 8 import android.view.View; 9 import android.view.View.OnClickListener; 10 import android.widget.Button; 11 import android.widget.ProgressBar; 12 import android.widget.Toast; 13 14 public class Handler_01 extends Activity { 15 16 //声明变量 17 private Button startButton=null; 18 private Button endButton=null; 19 private ProgressBar firstBar=null; 20 private Toast toast=null; 21 @Override 22 protected void onCreate(Bundle savedInstanceState) { 23 super.onCreate(savedInstanceState); 24 setContentView(R.layout.main); 25 26 //根据ID获取对象 27 startButton =(Button)findViewById(R.id.startButton); 28 endButton=(Button)findViewById(R.id.endButton); 29 firstBar=(ProgressBar)findViewById(R.id.firstBar); 30 //给对象设置动作监听器 31 startButton.setOnClickListener(new StartButtonListener()); 32 endButton.setOnClickListener(new EndButtonListener()); 33 } 34 35 class StartButtonListener implements OnClickListener{ 36 37 @Override 38 public void onClick(View v) { 39 // TODO Auto-generated method stub 40 //一开始执行,加入到消息队列,不延迟, 41 //然后马上执行run方法 42 firstBar.setVisibility(View.VISIBLE); 43 firstBar.setMax(100); 44 handler.post(upRunnable); 45 toast=Toast.makeText(Handler_01.this, "运行开始", Toast.LENGTH_SHORT); 46 toast.setGravity(Gravity.CENTER, 0, 0); 47 toast.show(); 48 } 49 } 50 class EndButtonListener implements OnClickListener{ 51 52 @Override 53 public void onClick(View v) { 54 // TODO Auto-generated method stub 55 //停止 56 handler.removeCallbacks(upRunnable); 57 System.out.println("It's time to stop..."); 58 } 59 } 60 61 //创建handler对象,在调用post方法 62 //异步消息处理:将下载或者处理大数据等等单独放到另一个线程 63 //更好的用户体验 64 Handler handler=new Handler(){ 65 66 @Override 67 public void handleMessage(Message msg){ 68 firstBar.setProgress(msg.arg1); 69 firstBar.setSecondaryProgress(msg.arg1+10); 70 //handler.post(upRunnable); 71 if(msg.arg1<=100) { 72 handler.post(upRunnable); //将要执行的线程放入到队列当中 73 }else { 74 handler.removeCallbacks(upRunnable); 75 } 76 } 77 }; 78 79 //声明线程类:实现Runnable的接口 80 Runnable upRunnable=new Runnable() { 81 82 int i=0; 83 @Override 84 public void run() {//程序的运行状态 85 // TODO Auto-generated method stub 86 //postDelayed方法:把线程对象加入到消息队列中 87 // 隔2000ms(延迟) 88 System.out.println("It's time to start..."); 89 i=i+10; 90 //获取Message消息对象 91 Message msg=handler.obtainMessage(); 92 //将msg对象的arg1(还有arg2)对象的值设置 93 //使用这两个变量传递消息优点:系统消耗性能较少 94 msg.arg1=i; 95 try{ 96 //设置当前显示睡眠1秒 97 Thread.sleep(1000); 98 }catch(InterruptedException e){ 99 e.printStackTrace(); 100 } 101 //将msg对象加入到消息队列当中 102 handler.sendMessage(msg); 103 if(i==100){//当值满足时,将线程对象从handle中剔除 104 handler.removeCallbacks(upRunnable); 105 firstBar.setVisibility(View.GONE); 106 //临时弹出 107 108 toast=Toast.makeText(Handler_01.this, "运行结束", Toast.LENGTH_SHORT); 109 toast.setGravity(Gravity.CENTER, 0, 0); 110 toast.show(); 111 } 112 } 113 }; 114 }
main.xml
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:orientation="vertical" 4 android:layout_width="match_parent" 5 android:layout_height="match_parent" 6 tools:context=".Handler_01" > 7 8 <ProgressBar 9 android:id="@+id/firstBar" 10 style="?android:attr/progressBarStyleHorizontal" 11 android:layout_width="200dp" 12 android:layout_height="wrap_content" 13 android:visibility="gone"/> 14 15 <Button 16 android:id="@+id/startButton" 17 android:layout_width="wrap_content" 18 android:layout_height="wrap_content" 19 android:text="@string/start" /> 20 21 <Button 22 android:id="@+id/endButton" 23 android:layout_width="wrap_content" 24 android:layout_height="wrap_content" 25 android:text="@string/end" /> 26 27 </LinearLayout>
总结:
1)当点击开始或者运行结束的时候,都会通过调用Toas弹出临时窗口,Toast.makeText(Handler_01.this, "运行结束", Toast.LENGTH_SHORT),这一句一开始总是执行出错,原因在于必须调用它的show方法才可以显示出来,还可以通过设置它的位置来显示;
2)在xml中 android:text="@string/end",则需要在layout下的string文件中敲写相应的代码
3)原本代码有一些瑕疵,就是没有下面这一段代码:
1 if(msg.arg1<=100) { 2 handler.post(upRunnable); //将要执行的线程放入到队列当中 3 }else { 4 handler.removeCallbacks(upRunnable); 5 }
这样就导致了upRunnable的run方法出现了死循环,这样,虽然程序UI本身没有问题,但是内部却又很大的缺陷
这是因为
1 if(i==100){//当值满足时,将线程对象从handle中剔除 2 handler.removeCallbacks(upRunnable); 3 firstBar.setVisibility(View.GONE); 4 toast=Toast.makeText(Handler_01.this, "运行结束", Toast.LENGTH_SHORT); 5 toast.setGravity(Gravity.CENTER, 0, 0); 6 toast.show(); 7 }
这一段代码看似是把upRunnable线程从线程对象队列中移除,但是再次之前又前执行了handler.sendMessage(msg);这句代码
从而导致下面的代码又被执行到
1 public void handleMessage(Message msg){ 2 firstBar.setProgress(msg.arg1); 3 firstBar.setSecondaryProgress(msg.arg1+10); 4 5 }
这样肯定会使upRunnable线程重新加入到线程对象队列中,updateThread的run方法重复执行,这就导致了死循环。所以必须加上之前的那段代码,通过判断来控制循环终止。并且run方法中的if(i==100)的那段代码也是可以不用的,不过我是写了一些其他代码就懒得优化了,这是后话了。
4) 刚刚大家看到我们可以通过敲写System.out.println在logcat中显示,一开始eclipse编译器中是没有,这是如何显示出来的?
大家可以再window的show view中找到logCat(deprecated)通过下图中绿色的“+”添加出来
然后显示内容的时候,选择右上角“V D I W E ”的I就可以比较清晰的显示出来了,当然你也可以选择另外一个logCat来显示,方法类似。
5)实际上,Handler在默认情况下,和调用它的Activity是处于同一个线程的。 上述Handler的使用示例中,虽然声明了线程对象,但是在实际调用当中它并没有调用线程的start()方法,而是直接调用当前线程的run()方法。
如果要实现调用另一个新的线程,只要注释post方法,然后加上这样两段代码即可: Thread t = new Thread(r); t.start();