【Android】UI界面外的线程,控制刷新UI界面

一,问题引入

异常: Only the original thread that created a view hierarchy can touch its views的解决方案

<wbr><wbr><wbr><wbr>为什么会有这种异常产生呢?</wbr></wbr></wbr></wbr>
<wbr><wbr><wbr></wbr></wbr></wbr>
<wbr><wbr><wbr>当每个应用程序apk第一次启动时,Android会同时启动一个对应的<span style="color:#ff0000; line-height:21px; word-wrap:normal; word-break:normal">主线程(Main Thread)</span>,</wbr></wbr></wbr>
<wbr><wbr><wbr>主线程负责处理与UI相关的事件,如:用户的按键事件,用户接触屏幕的事件以及屏幕绘图事件,</wbr></wbr></wbr>
<wbr><wbr><wbr>并把相关的事件分发到对应的组件进行处理,所以主线程通常又被叫做<span style="color:#ff0000; line-height:21px; word-wrap:normal; word-break:normal">UI线程</span>。</wbr></wbr></wbr>

<wbr><wbr><wbr>但是在开发Android应用时必须遵守单线程模型的原则:<wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><span style="color:#ff0000; line-height:21px; word-wrap:normal; word-break:normal">Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行,如果在非UI线程中直接操作UI线程,</span></wbr></wbr></wbr>
<wbr><wbr><wbr>会抛出android.view.ViewRoot$CalledFromWrongThreadExc<wbr>eption: Only the original thread that<wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr>created a view hierarchy can touch its views,这与普通的java程序不同。</wbr></wbr></wbr>

<wbr><wbr><wbr><wbr>由于UI线程负责事件的监听和绘图,因此,必须保证UI线程能够随时响应用户的需求,</wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr>UI线程里的操作应该向中断事件那样短小,费时的操作(如网络连接)需要另开线程,</wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr>否则,如果UI线程超过5s没有响应用户请求,会弹出对话框提醒<span style="color:#ff0000; line-height:21px; word-wrap:normal; word-break:normal">用户终止应用程序(ANP)</span>。</wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><wbr>如果在新开的线程中需要对UI进行设定,就可能违反单线程模型,</wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr>因此android采用一种的Message Queue机制保证<span style="color:#ff0000; line-height:21px; word-wrap:normal; word-break:normal">线程间通信</span>。</wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><wbr>Message Queue是一个消息队列,用来存放通过Handler发送的消息。</wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr>Android在第一启动程序时会默认会为UI thread创建一个关联的消息队列,</wbr></wbr></wbr></wbr>
<wbr><wbr><wbr>可以通过Looper.myQueue()得到当前线程的消息队列,用来管理程序的一些上层组件,</wbr></wbr></wbr>
<wbr><wbr><wbr>activities,broadcast receivers 等,你可以在自己的子线程中创建Handler与UI thread通讯。</wbr></wbr></wbr>

<wbr><wbr><wbr>Handler会向message queue通过两种方法发送消息:send或post。</wbr></wbr></wbr>
<wbr><wbr><wbr>这两种消息都会插在message queue队尾并按先进先出执行,</wbr></wbr></wbr>
<wbr><wbr><wbr>但通过这两种方法发送的消息执行的方式略有不同:</wbr></wbr></wbr>
<wbr><wbr><wbr>1)通过send发送的是一个message对象,<wbr>会被handler的 handleMessage()函数处理;</wbr></wbr></wbr></wbr>
<wbr><wbr><wbr>2)而通过post方法发送的是一个runnable对象,则会自己执行。</wbr></wbr></wbr>

<wbr><wbr><wbr>每个带图形界面的应用启动后,都会创建一个主线程,可称之为UI线程。</wbr></wbr></wbr>
<wbr><wbr><wbr>这个线程自动就会创建一个message queue,来自于系统的消息都会投放到这个message queue里面,</wbr></wbr></wbr>
<wbr><wbr><wbr>并按先进先出的顺序处理。</wbr></wbr></wbr>

<wbr><wbr><wbr>UI线程图形界面中的view可通过post方法向GUI线程的message queue投递一个runnable。</wbr></wbr></wbr>
<wbr><wbr><wbr>对于除UI线程以外的其他线程,创建时缺省并没有message queue,</wbr></wbr></wbr>
<wbr><wbr><wbr>而对于UI线程,则可以直接(比如在onCreate)创建一个handler并重载handleMessage,</wbr></wbr></wbr>
<wbr><wbr><wbr>省去创建message queue的过程。</wbr></wbr></wbr>
二,解决方案一
final Handler handler = new Handler(){   
      
            @Override
        public void handleMessage(Message msg) {   
  
            
            if(msg.what == 0)//成功   
            {
                Log.d(TAG, "**********************start****************************");
                playVideo(strVideoPath);//包含更新界面的方法
                Log.d(TAG, "***********************end*****************************");
            }

              
        } 
           
    };   
 
    new Thread() 
        {
            @Override
		public void run()
		{   
                   // handler.post(runnableUi);   
                        
                    try{
                        
                         Log.d(TAG, "######################start###############################");
                         handler.sendEmptyMessage(0);//UI线程外想更新UI线程
                         Log.d(TAG, "######################end###############################");
                    }
	           catch(Exception e)
                   {
                       Log.d(TAG, "***************************"+e.toString());
                   }
                    
		 }
       }.start();
三,解决方案二
Runnable   runnableUi=new  Runnable(){  
        @Override  
        public void run() {  
            //更新界面  
            textView.setText("the Content is:"+content);  
        }  
          
    };  
  new Thread(){  
                public void run(){    
                    content=df.downLoadFiles();       
                    handler.post(runnableUi);   
                    }                     
            }.start();


四,特别注意,引入函数包得时候,不要引入错误的包
 

import android.os.Handler; //这是正确的包

import java.util.logging.Handler;//不是这个包,而是上一个

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值