简述Androiod UI线程阻塞及其优化

先说什么叫做UI线程吧。。。

当一个应用程序启动的时候,系统就开始一个新线程,我们称之为main 主线程,它负责分发事件给构件,包括绘制事件。我们在这里才能与Android UI工具包中的组件进行交互。

android里面的设置是把UI的交互放在单线程模型下面的,所以我们只能在主线程里面处理更改UI信息,所以,我们也将UI线程,称为主线程。

而一个View里面包含这很多的控件,如果一个控件里面需要某些耗时操作的话,就会影响UI的更新,也就是我们经常说的UI线程的阻塞。。。而对于这些情况,Android提供了多种方法来处理

子线程中更新数据,UI线程中更新控件,子线程将获取的信息发送到有关消息队列中,UI线程从消息队列中获得信息,从而实现线程间的交互

1· Activity.runOnUiThread(Runnable)

利用Activity.runOnUiThread(Runnable)把更新ui的代码创建在Runnable中,然后在需要更新ui时,把这个Runnable对象传给Activity.runOnUiThread(Runnable)。 这样Runnable对像就能在ui程序中被调用。如果当前线程是UI线程,那么行动是立即执行。如果当前线程不是UI线程,操作是发布到事件队列的UI线程

2· View.post(Runnable)

iew.post(Runnable)方法。在post(Runnable action)方法里,View获得当前线程(即UI线程)的Handler,然后将action对象post到Handler里。在Handler里,它将传递过来的action对象包装成一个Message(Message的callback为action),然后将其投入UI线程的消息循环中。在Handler再次处理该Message时,有一条分支(未解释的那条)就是为它所设,直接调用runnable的run方法。

3· View.postDelayed(Runnable, long)

与第二个差不多,long参数用于制定多少时间后运行后台进程
4· Handler 

创建一个Handler类的实例, 在这个Handler实例的handleMessage回调函数中调用更新界面显示的函数。

private class UIHandler extends Handler{  
        @Override  
        public void handleMessage(Message msg) {  
            // TODO Auto-generated method stub  
            super.handleMessage(msg);  
            Bundle bundle = msg.getData();  
            String color = bundle.getString("color");  
            UITxt.setText(color);  
        }  
    }  
    private class UIThread extends Thread{  
        @Override  
        public void run() {  
            try {  
                Thread.sleep(3000);  
            } catch (InterruptedException e) {  
                // TODO Auto-generated catch block  
                e.printStackTrace();  
            }  
            Message msg = new Message();  
            Bundle bundle = new Bundle();  
            bundle.putString("color", "黄色");  
            msg.setData(bundle);  
            MainActivity.this.UIhandler.sendMessage(msg);  
              
        }  
    } 

5· AsyncTask

AsyncTask是一个专门用来处理后台进程与UI线程的工具。通过AsyncTask,我们可以非常方便的进行后台线程和UI线程之间的交流。
那么AsyncTask是如何工作的哪。
AsyncTask拥有3个重要参数
1、Params
2、Progress
3、Result
Params是后台线程所需的参数。在后台线程进行作业的时候,他需要外界为其提供必要的参数,就好像是一个用于下载图片的后台进程,他需要的参数就是图片的下载地址。
Progress是后台线程处理作业的进度。依旧上面的例子说,就是下载图片这个任务完成了多少,是20%还是60%。这个数字是由Progress提供。
Result是后台线程运行的结果,也就是需要提交给UI线程的信息。按照上面的例子来说,就是下载完成的图片。
AsyncTask还拥有4个重要的回调方法。
1、onPreExecute
2、doInBackground
3、onProgressUpdate
4、onPostExecute
onPreExecute运行在UI线程,主要目的是为后台线程的运行做准备。当他运行完成后,他会调用doInBackground方法。
doInBackground运行在后台线程,他用来负责运行任务。他拥有参数Params,并且返回Result。在后台线程的运行当中,为了能够更新作业完成的进度,需要在doInbackground方法中调用PublishProgress方法。该方法拥有参数Progress。通过该方法可以更新Progress的数据。然后当调用完PublishProgress方法,他会调用onProgressUpdate方法用于更新进度。
onProgressUpdate运行在UI线程,主要目的是用来更新UI线程中显示进度的UI控件。他拥有Progress参数。在doInBackground中调用PublishProgress之后,就会自动调onProgressUpdate方法
onPostExecute运行在UI线程,当doInBackground方法运行完后,他会调用onPostExecute方法,并传入Result。在onPostExecute方法中,就可以将Result更新到UI控件上。
明白了上面的3个参数和4个方法,你要做的就是
1、编写一个继承AsyncTask的类,并声明3个参数的类型,编写4个回调方法的内容。
2、然后在UI线程中创建该类(必须在UI线程中创建)。
3、最后调用AsyncTask的execute方法,传入Parmas参数(同样必须在UI线程中调用)。
这样就大功告成了。
另外值得注意的2点就是,千万不要直接调用那四个回调方法。还有就是一个AsyncTask实例只能执行一次,否则就出错哦。
以上是AsyncTask的基本用法,更加详细的内容请参考android官方文档。最后附上一段代码,供大家参考。

private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> 
 //在这里声明了Params、Progress、Result参数的类型
 {
     //因为这里不需要使用onPreExecute回调方法,所以就没有加入该方法
     
     //后台线程的目的是更具URL下载数据
      protected Long doInBackground(URL... urls) {
        int count = urls.length;//urls是数组,不止一个下载链接
         long totalSize = 0;//下载的数据
          for (int i = 0; i < count; i++) {
              //Download是用于下载的一个类,和AsyncTask无关,大家可以忽略他的实现
             totalSize += Downloader.downloadFile(urls[i]);
              publishProgress((int) ((i / (float) count) * 100));//更新下载的进度
              // Escape early if cancel() is called
           if (isCancelled()) break;
          }
         return totalSize;
     }

      //更新下载进度
      protected void onProgressUpdate(Integer... progress) {
          setProgressPercent(progress[0]);
      }

      //将下载的数据更新到UI线程
     protected void onPostExecute(Long result) {
         showDialog("Downloaded " + result + " bytes");
      }
  }


不管你是否使用AsyncTask,在单线程模型中始终要记住两条法则:

1. 不要阻塞UI线程

2. 确保只在UI线程中访问Android UI工具包

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值