Android 开发中的消息机制 Handler 机制

子线程中更新主线程界面(UI)

一、前言

        最近在多线程的使用过程中遇到一些问题,记录下来以加深印象。当在主线程中要进行某一操作比较耗时时,就需要开启新线程来处理,主线程通常等待时间在 5 秒左右,大于 5 秒的操作会报错,所以需要子线程。


         其一是在子线程中更新主线程界面(UI)  时抛出异常如下:

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


   谷歌翻译:只有创建视图层次才可以触摸其焦点原来的线程。


二、子线程更新主线程界面 (UI)的异常原因及处理

     示例代码:(以下代码是本人的相关文件的部分代码,其中部分类是个人需要写的)

(1)报异常代码

<span style="font-size:14px;">new Thread(new Runnable() {
            @Override
            public void run() {
                GetAllMessageFromWeb getAll = new GetAllMessageFromWeb();
                allList = getAll.getAllMessage();//(1)数据源加载来自数据库(2)创建适配器(3)视图加载适配器
                dataList = new ArrayList<Map<String,Object>>();
                for(int i=0;i<allList.size();i++){
                    MyMessage message = new MyMessage();
                    message = allList.get(i);
                    Map<String,Object> map = new HashMap<String,Object>();
                    map.put("id",message.getId());
                    map.put("content",message.getContent());
                    dataList.add(map);
                }
                    adapter = new MyStyle(MenuActivity.this,dataList,R.layout.listview_layout,new String[] {"id","content"},new int[] {R.id.msg_id,R.id.msg_content});
                    listView.setAdapter(adapter);//出错,报异常,原因在子线程中修改主线程UI会引起错乱,应用Handler机制来处理。
            }
        }).start();</span>

    异常原因是直接在主线程中开一个新线程,该子线程有修改主线程 UI的操作,报异常

Only the original thread that created view hierarchy can touch its views.


(2)Handler 消息机制处理后的代码,不报异常,成功更新主线程界面 (UI)

<span style="font-size:14px;">final Handler handler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                if(msg.what==RIGHT){
                    //(2)创建适配器
                    adapter = new MyStyle(MenuActivity.this,dataList,R.layout.listview_layout,new String[] {"id","content"},new int[] {R.id.msg_id,R.id.msg_content});
                    //(3)视图加载适配器
                    listView.setAdapter(adapter);
                }
            }
        };
new Thread(new Runnable() {
            @Override
            public void run() {
                GetAllMessageFromWeb getAll = new GetAllMessageFromWeb();
                allList = getAll.getAllMessage();
                dataList = new ArrayList<Map<String,Object>>();
                //(1)数据源加载来自数据库
                for(int i=0;i<allList.size();i++){
                    MyMessage message = new MyMessage();
                    message = allList.get(i);
                    Map<String,Object> map = new HashMap<String,Object>();
                    map.put("id",message.getId());
                    map.put("content",message.getContent());
                    dataList.add(map);
                }

                if(dataList!=null){
                    Message m = new Message();
                    m.what = RIGHT;
                    handler.sendMessage(m);
                }else{
                    Message m = new Message();
                    m.what = ERROR;
                    handler.sendMessage(m);
                }
            }
        }).start();</span>


分析:


    
1、对子线程中更新主线程 UI的异常处理,就是使用 Handler消息处理机制。新建 Haldler对象,通过 message 的发送与接收,来处理更新 UI操作。使用 Handler 机制进行子线程更新界面后返回给用户不会报异常。


   2、注意:在子线程中是无法更新主线程的界面(UI)的.Android引入Handler解决这个问题。


   3、原因是如果同时多个子线程更新主线程界面,会导致界面不断变化,并且不易找到原因,Handler机制就是的当子线程中有更新主线程 UI 的操作时,将通过 message 消息的发送接收来告诉主线程,handler 在主线程中运行,对发送接收的message处理,从而实现主线程页面的更新。该机制主要是规范子线程与主线程的操作,从而避免子线程的相关操作引起混乱。


三、 Handler 处理机制的简单使用


      在子线程中修改主线程界面 (UI)中控件 EditText 的内容,代码如下:

其中 _handler1,_handler2 是两个按钮,对其监听,进行修改 UI操作;前者直接在新线程中更新 UI,后者使用Handler message处理。

<span style="font-size:14px;">/**
		 * 监听 handler 机制 (1) 会报异常,因为没用 handler 机制,在子线程修改界面 (UI)会报异常。修改 editText内容失败。
		 */
		_handler1.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				//对文本框内容修改
				editText.setText("调用 handler 之前的内容。");
				new Thread(new Runnable() {
					
					@Override
					public void run() {
						try {
							Thread.sleep(3000);//休息3秒
						} catch (InterruptedException e) {e.printStackTrace();}
						
						editText.setText("调用 handler 机制进行修改内容1。");
					}
				}).start();
			}
		});
		
		/**
		 * 监听 handler 机制,(2)子线程调用handler 处理主线程界面 (UI)成功,将 exitText对应的文本框内容修改
		 */
		_handler2.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				editText.setText("handler 机制,子线程修改 UI之前");
				final Handler handler = new Handler(){
					public void handleMessage(Message m) {
						super.handleMessage(m);
						if(m.what==1){
							editText.setText("调用 handler 机制进行修改内容2。");
						}
					}
				};
				
				new Thread(new Runnable() {
					
					@Override
					public void run() {
						try {
							Thread.sleep(3000);
						} catch (InterruptedException e) {e.printStackTrace();}
						Message message = new Message();//新建消息
						message.what = 1;               //赋给内容
						handler.sendMessage(message);       //发送消息
					}
				}).start();
			}
		});</span>


      在运行的程序中,点击两按钮的结果如下图:

_handler1

     


所报异常:



_handler2


      


正常运行,不报异常。


四、handler + message + looper 对于线程 Thread 详细图示





相关内容跳转:Looper 基础


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

niaonao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值