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

来源:互联网 发布:如何修改电脑mac地址 编辑:程序博客网 时间:2024/05/21 06:56

今天在做一个运动的小球的安卓项目的时候,我尝试着在子线程中刷新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 0
原创粉丝点击