利用Handler回更新android的UI

利用Handler来更新android的UI

刚刚开始接触android线程编程的时候,习惯好像java一样,试图用下面的代码解决问题

 new Thread( new Runnable() {   
    public void run() {   
         myView.invalidate();  
     }          
}).start();   

 

然而发现这样是不行的,因为它违背了单线程模型:Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行。查阅了文档和apidemo后,发觉常用的方法是利用Handler来实现UI线程的更新的。

 

下面代码的功能很简单:画一个圆出来,每隔0.1秒,圆向10移动10个像素。但可以清楚展示利用Handler更新UI的流程。

 

利用Handler回更新android的UI

 

首先创建简单的View,代码如下:

package com.ray.handler;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.view.View;

public class BounceView extends View {
    float x = 40;
    
    public BounceView(Context context) { 
         super(context); 
    } 

    @Override 
    protected void onDraw(Canvas canvas) { 
    	x+=10;
    	Paint mPaint = new Paint();
    	mPaint.setAntiAlias(true);
    	mPaint.setColor(Color.GREEN);
    	canvas.drawCircle(x, 40, 40, mPaint);
    }
}

 

创建Activity,代码如下:

package com.ray.handler;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.Window;

public class TestHandler extends Activity {
     protected static final int GUIUPDATEIDENTIFIER = 0x101; 
	 
     Thread myRefreshThread = null; 
     BounceView myBounceView = null; 
 
     Handler myHandler = new Handler() {
          public void handleMessage(Message msg) { 
               switch (msg.what) { 
                    case TestHandler.GUIUPDATEIDENTIFIER: 
                         myBounceView.invalidate();
                         break; 
               } 
               super.handleMessage(msg); 
          } 
     };
     public void onCreate(Bundle savedInstanceState) { 
          super.onCreate(savedInstanceState); 
          this.requestWindowFeature(Window.FEATURE_NO_TITLE); 
 
          this.myBounceView = new BounceView(this);
          this.setContentView(this.myBounceView); 
          new Thread(new myThread()).start();
     } 
 
     class myThread implements Runnable { 
          public void run() {
               while (!Thread.currentThread().isInterrupted()) {  
                     
                    Message message = new Message(); 
                    message.what = TestHandler.GUIUPDATEIDENTIFIER; 
                    
                    TestHandler.this.myHandler.sendMessage(message); 
                    try { 
                         Thread.sleep(100);  
                    } catch (InterruptedException e) { 
                         Thread.currentThread().interrupt(); 
                    } 
               } 
          } 
     } 
}
1 楼 neverland 2009-09-11  
兄弟写的文章很清晰,~~感谢利用Handler回更新android的UI
2 楼 raymondlueng 2009-09-11  
呵呵,其实我只是初学者,只能写简单的东西!
3 楼 chenweiguo66 2009-10-15  
利用Handler回更新android的UI 不用Handler行吗?在你的另一篇文章中http://www.iteye.com/topic/435147,
回帖的那个人贴的代码就没有用Handler。用Handler比不用Handler有什么特别的优势吗?
4 楼 raymondlueng 2009-10-15  
chenweiguo66 写道
利用Handler回更新android的UI 不用Handler行吗?在你的另一篇文章中http://www.iteye.com/topic/435147,
回帖的那个人贴的代码就没有用Handler。用Handler比不用Handler有什么特别的优势吗?
用handler可以更好地使用消息
驱动的程序设计!类似mfc[color=red][/color]
5 楼 crazier9527 2009-12-30  
TestHandler.this.myHandler利用Handler回更新android的UI
6 楼 happyljt 2010-01-25  
学习ing...利用Handler回更新android的UI
7 楼 kevin2562 2010-03-09  
class myThread implements Runnable {   
          public void run() {  
               while (!Thread.currentThread().isInterrupted()) {    
                       
                    Message message = new Message();   
                    message.what = TestHandler.GUIUPDATEIDENTIFIER;   
                      
                    TestHandler.this.myHandler.sendMessage(message);   
                    try {   
                         Thread.sleep(100);    
                    } catch (InterruptedException e) {   
                         Thread.currentThread().interrupt();   
                    }   
               }   
          }   


这段有点不理解,楼主能解释一下么?
尤其是:
   while (!Thread.currentThread().isInterrupted()) { 

   message.what = TestHandler.GUIUPDATEIDENTIFIER;
   
   TestHandler.this.myHandler.sendMessage(message);

  Thread.currentThread().interrupt();

作用是什么?

我很喜欢楼主的学习风格,在此表示感谢,你的帖子对我很有帮助。
8 楼 leon_ch 2012-04-12  
楼主既然用到BounceView来继承View,为什么不考虑用子空间的方式来实现呢?
另外,如果用handler来实现的话,那么利用activity内的内部类就可以循环实现,我自己做了一下,楼主看一下是不是可以?
第一种:
package edu.cslg.leon.ballinvalidate;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.util.AttributeSet;
import android.view.View;

public class BallView extends View
{
private Paint paint;
private int BallX=10;
private int BallY=10;
private int WindowWidth=200;
private int WindowHeight=200;
static final int radius=20;

public BallView(Context context, AttributeSet attrs)
{
super(context, attrs);
paint=new Paint();
}

@Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
BallX++;
BallY++;
paint.setColor(Color.BLUE);
paint.setStyle(Style.FILL);
canvas.drawCircle(BallX, BallY, radius, paint);
if(BallX<WindowWidth&&BallY<WindowHeight)
{
invalidate();
}
}
}

配置文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
    <edu.cslg.leon.ballinvalidate.BallView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />
</LinearLayout>

第二种:
package edu.cslg.leon.ballinvalidate;

import android.app.Activity;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;

public class BallInvalidate extends Activity
{
private int BallX;
private int BallY;
private Paint paint;
private Canvas canvas;
static final int radius=20;
class MyHandler extends Handler
{
public MyHandler(Looper looper)
{
super(looper);
}
@Override
public void handleMessage(Message msg)
{
super.handleMessage(msg);
paint.setColor(Color.BLUE);
paint.setStyle(Style.FILL);
canvas.drawCircle(msg.arg1,msg.arg2, radius, paint);
}
};
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
paint=new Paint();
canvas=new Canvas();
new MyThread().start();
}
class MyThread extends Thread
{
@Override
public void run()
{
super.run();
while (BallX<200&&BallY<200)
{
Looper looper=Looper.getMainLooper();
Handler handler=new MyHandler(looper);
Message msg=handler.obtainMessage(1, BallX,BallY);
handler.sendMessage(msg);
}
}
}
}
9 楼 yacobe 2012-04-24  
条理很清楚,很受用。感谢利用Handler回更新android的UI
10 楼 yacobe 2012-04-24  
条理很清晰,很受用。感谢利用Handler回更新android的UI
11 楼 KwokWing 2012-07-19  
最近学习Android游戏开发, 感谢楼主