Android中在主线程与在子线程中更新UI的探索

今天在做一个运动的小球的安卓项目的时候,我尝试着在子线程中刷新ui。众所周知,子线程是线程中不安全的,这个不安全不是说不能在子线程里面更新UI,这个很复杂,取决于你的主线程处理的时间,子线程就是子线程,主线程就是主线程,不必太纠结,碰到一个问题,要善于去寻找他有价值的地方。在子线程中也可以用handler,不过这需要开启一个循环队列looper,并且用looperloop()方法,这主要是为了能够在子线程中创建handler,但是问题来了,loop()里面是一个循环,但是为了刷新,线程里面又是一个循环,两者不可同时进行,所以这样的方法handleMessage不会被执行,逻辑上不是很好。逻辑上出现了问题。  

package wust.edu.ball;  
  
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.Looper;  
import android.os.Message;  
import android.view.View;  
  
public class MoveActivity extends Activity {  
    Handler handler=null;  
    Thread t;//放在外面。这样比较好。  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        MyView mv=new MyView(MoveActivity.this);  
        setContentView(mv);       
    }  
      
    @Override  
    protected void onStop() {  
        // TODO Auto-generated method stu     
        super.onStop();  
        System.out.println("OnDestroy有没有被执行");  
        t.stop();  
        t.interrupt();  
        t=null;  
    }  
  
  
    class MyView extends View implements Runnable{  
        private int x=20,y=20;  
          
        public MyView(Context context) {//应用的上下文。  
            super(context);  
            setFocusable(true);  
            t=new Thread(this);  
            t.start();  
            // TODO Auto-generated constructor stub  
        }  
        @Override  
        public void run() {  
            System.out.println("线程有没有被执行");  
            Looper.prepare();  
            handler=new Handler(){  
                @Override  
                public void handleMessage(Message msg) {  
                    // TODO Auto-generated method stub  
                    System.out.println("handler方法有没有执行");  
                    if(msg.what==0x11){  
                        MyView.this.update();//不要局限于这个,你可以取得他的引用的  
                        MyView.this.invalidate();  
                    }  
                      
                    super.handleMessage(msg);  
                }  
            };  
              
              
            while(!Thread.currentThread().isInterrupted()){  
                System.out.println("线程里面的方法有没有被执行");  
                Message m=Message.obtain();  
                m.what=0x11;  
                handler.sendMessage(m);  
                try {  
                    Thread.sleep(100);  
                } catch (InterruptedException e) {  
                    // TODO Auto-generated catch block  
                    e.printStackTrace();  
                }//已经进入循环  
            }  
              
            Looper.loop();//监视循环队列。这里又是一个循环  
              
              
        }  
          
        protected void update() {  
            // TODO Auto-generated method stub  
            System.out.println("update方法被执行了");  
            int h=MyView.this.getHeight();  
            y+=5;  
            if(y>=h){  
                y=20;  
            }  
              
        }  
        @Override  
        protected void onDraw(Canvas canvas) {  
            // TODO Auto-generated method stub  
              
            super.onDraw(canvas);  
            Paint p=new Paint();  
            p.setColor(Color.RED);  
            canvas.drawCircle(x,y,15,p);  
        }  
          
    }  
}  
接下来。在一个网友的帮助下寻找到了正确的方法,就是最常规的方法,在主线程中更新ui,接下来看代码。  


 Handler mHandler = new Handler() {//主线程里面  
        @Override  
        public void handleMessage(Message msg) {  
            // TODO Auto-generated method stub  
            super.handleMessage(msg);  
            if (msg.what == 0x11) {  
                mv.update();//交给主线程去处理。  
                mv.invalidate();  
            }  
        }  
  
  
    };  
      
    private MyView mv;//持有类的(也可以是内部类的一个)对象。我老是不知道invalidate在那里面执行  
  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        mv = new MyView(MoveActivity.this);  
        setContentView(mv);  
        new Thread() {//就是子线程,不要去纠结。  
            public void run() {  
                while (!Thread.currentThread().isInterrupted()) {  
                    Message m = new Message();  
                    m.what = 0x11;  
                    mHandler.sendMessage(m);  
                    try {  
                        Thread.sleep(100);  
                    } catch (InterruptedException e) {  
                        // TODO Auto-generated catch block  
                        e.printStackTrace();  
                    }  
                      
                }  
  
  
            };  
        }.start();  
  
  
    }  
  
  
    class MyView extends View {  
        private int x = 20, y = 20;  
        public MyView(Context context) {// 应用的上下文。  
            super(context);  
            setFocusable(true);  
            // TODO Auto-generated constructor stub  
        }  
        protected void update() {  
            // TODO Auto-generated method stub  
            int h = MyView.this.getHeight();  
            int w = MyView.this.getWidth();  
            y += 5;  
            x += 5;  
            if (y >= h||x>=w) {  
                y = 20;  
                x = 20;  
            }  
  
  
        }  
        @Override  
        protected void onDraw(Canvas canvas) {  
            // TODO Auto-generated method stub  
            System.out.println("这个方法被执行了几次");  
            super.onDraw(canvas);  
            Paint p = new Paint();  
            p.setColor(Color.RED);  
            canvas.drawCircle(x, y, 15, p);  
        }  
  
  
    }  
}
这里要注意它的一个方法,也是在面向对象中比较常见的一个方法,持有类的引用,这里最关键的是,他吧内部类Myview的引用申明为了全局变量,这样的话就可以访问它的update和invalidate方法了,这个思路比较好的,面向对象的核心。

总之还是那句话,在安卓里面,主线程是线程中不安全的,一般来说不允许在子线程中更新ui。但是还是要灵活解决。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值