Android更新UI的2种方法

1、引言

在Android开发过程中,我们常常需要对UI进行更新。而对UI的更新,我们主要是在主线程进行的。常常我们会遇到这样的异常信息:

android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

这是什么意思呢?翻译过来其实就是说“只有原始创建这个视图层次(view hierachy)的线程才能修改它的视图(view)”,简单的说就是我们在主线程以外的线程进行了UI更新的操作才导致了这个异常。
既然知道了产生的原因,那有什么办法来进行UI更新呢?


2、更新UI两种方法

2.1、方法简介

目前更新UI的方法主要有2种,主要用到的是Handle类和runOnUiThread方法。

2.2 Handler

该方法通常实在Activity的ovnCreate()中创建一个Handler实例,而后在其实例中使用Message类在handleMessage回调函数中对界面UI进行更新。但这样容易引起内存溢出,因而比较好的做法是自定义一个静态私有的Handler类,配合弱引用来避免内存溢出。
示例代码如下:

/**
 * 初始化控件
 */
private void initView() {
    // TODO Auto-generated method stub
    Button btn = (Button) findViewById(R.id.main_btn);
    btn.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            Message msg = Message.obtain();//不要使用new
            msg.what = 1;
            msg.obj = getData();
            handler.sendMessage(msg);
        }
    });
    Button btnHide = (Button) findViewById(R.id.main_btn_hide);
    btnHide.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            Message msg = handler.obtainMessage();//减少内存开销,直接从Message池获取
            // msg.what=2;
            handler.sendEmptyMessage(2);

        }
    });
    lv = (ListView) findViewById(R.id.main_lv);

}
/**
 * 自定义Handler类进行优化
 */
private static class MyHandler extends Handler {//静态、私有
    private WeakReference<MainActivity> mActivity;//弱引用

    public MyHandler(MainActivity pActivity) {
        mActivity = new WeakReference<MainActivity>(pActivity);
    }

    @SuppressWarnings("unchecked")
    @Override
    public void handleMessage(Message msg) {
        // TODO Auto-generated method stub
        MainActivity activity = mActivity.get();
        if (null != activity && 1 == msg.what) {//activity是否为空
            List<String> list = (List<String>) (msg.obj);
            lv.setAdapter(new ArrayAdapter<String>(MainActivity.this,
                    android.R.layout.simple_list_item_1, list));
        } else if (null != activity && 2 == msg.what) {
            lv.setAdapter(null);
        }
        lv.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> parent, View view,
                    int position, long id) {
                // TODO Auto-generated method stub
                Toast.makeText(MainActivity.this,
                        "Click the item:" + (position + 1), 2).show();
                showDialog();
            }
        });
    }
}
private MyHandler handler = new MyHandler(this);//实例化  

2.3 runOnUiThread

该方法是Activity类的方法,实现的原理其实就是把更新界面UI的过程写在Runnable中,而在需要更新的时候将该Runnable对象传给Activity.runOnUiThread(Runnable)。如果当前线程是UI线程,那么行动是立即执行。如果当前线程不是UI线程,操作是发布到事件队列的UI线程。(该方法用的较少,还不知道有什么可以优化的,若可优化,希望大家留言)
先看下源码:

  public final void runOnUiThread(Runnable action) {  
       if (Thread.currentThread() != mUiThread) {  
           mHandler.post(action);//将Runnable Post到消息队列,由内部的mHandler来处理,实际上也是Handler的处理方式  
       } else {  
           action.run();//已经在UI线程,直接运行。  
       }  
   }  

示例代码如下:

void test(){
    runOnUiThread(new MyRunnable());
}
class MyRunnable implements Runnable{

    @Override
    public void run() {
        // TODO Auto-generated method stub
        Toast t=Toast.makeText(LoginActivity.this, "Just A Test", Toast.LENGTH_SHORT);
        t.show();
    }
}  

2.4 Handler和runOnUiThread的区别

个人的理解就是前者是一个新的子线程,而后者是UI线程(仅仅一个,故而界面是同步)。
具体可以参阅下面的博客。
http://http://blog.csdn.net/id19870510/article/details/6680900

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值