Android中更新UI的几种方式

一、 runOnUiThread

先判断当前线程是否是UI线程,在默认情况下activity有个自己的handler,通过handler会发送一个runnable。

public class five extends AppCompatActivity {
    private TextView textView;

    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {

        };
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_five);
        textView = (TextView) findViewById(R.id.textview);
        //一般情况下都在子线程中更新UI
        new Thread(){

            @Override
            public void run() {
                textView.setText("OK");
                try {
                    Thread.sleep(2000);
                    //在Runnable中更新UI
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            textView.setText("ok");
                        }
                    });
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }
}

二、 handler post

通过post发送一个runnable的象,在内部封装成一个message,先调用一个getPostMessage方法。与本质发送message没有什么区别。

public class five extends AppCompatActivity {
    private TextView textView;

    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            textView.setText("ok2");
        };
    };

    //直接在一个子线程中给handler发送信息
    private void handler2(){
        handler.sendEmptyMessage(1);
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_five);
        textView = (TextView) findViewById(R.id.textview);
        //一般情况下都在子线程中更新UI
        new Thread(){
            @Override
            public void run() {
                textView.setText("OK");
                try {
                    Thread.sleep(5000);
                    //在Runnable中更新UI
                    handler2();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }
}

三、 handler sendMessage

public class five extends AppCompatActivity {
    private TextView textView;

    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
        };
    };
    //直接在子线程中更新UI
    private void updataUI(){
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                textView.setText("ok3");
            }
        });
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_five);
        textView = (TextView) findViewById(R.id.textview);
        //一般情况下都在子线程中更新UI
        new Thread(){
            @Override
            public void run() {
                textView.setText("OK");
                try {
                    Thread.sleep(5000);
                    //在Runnable中更新UI
                    updataUI();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }
}

四、 view post

先判断一个AttachInfo,若不为空,通过AttachInfo得到一个handler去发送一个runnable,若为空则通过ViewRootImpl去更新UI。

public class five extends AppCompatActivity {
    private TextView textView;

    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            textView.setText("ok2");
        };
    };

    //通过view自己发送Runnable
    private void viewUI(){
        textView.post(new Runnable() {
            @Override
            public void run() {
                textView.setText("OK4");
            }
        });
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_five);
        textView = (TextView) findViewById(R.id.textview);
        //一般情况下都在子线程中更新UI
        new Thread(){
            @Override
            public void run() {
                textView.setText("OK");
                try {
                    Thread.sleep(5000);
                    //在Runnable中更新UI
                    viewUI();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }
}

总结:本质都是通过handler去更新UI,只是在内部有一些代码上的差异。

五、非UI线程真的不能更新UI么

1)如下程序可以执行

new Thread(){
   @Override
   public void run(){
          textView.setText("OK");
  }
}.start();           

2)如下程序会报错

new Thread(){
    @Override
    public void run() {
        try {
            Thread.sleep(5000);
            textView.setText("OK");
        } catch (InterruptedException e) {
           e.printStackTrace();
        }
    }
}.start();

原因:
所有更新UI的操作都会调用View的invalidate()方法,在我们调用textView.setText()方法后,内部会调用invalidate()方法。其内部,主要用于判断当前线程是否在UI线程更新的操作在ViewParent类中(有一个checkThread()//用于检查当前更新操作是都在主线程中,当前线程是否和UI线程相等)。
然而(1)中因为onResume方法在onCreate方法之前,所以还未能检查。但是不建议以这种方式更新UI。

六、使用handler时所遇到的问题

1、两个异常
1)错误:Only the original thread that created a view hierarchy can touch its views
原因:mThread是在UI线程(activityThread)中创建,若更新UI操作在子线程中,则会抛出异常。

2)错误:Can’t create handler inside thread that has not called Looper.prepare()
原因:在用到handler时必须指定一个looper对象 相关

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值