子线程更新UI的方法的总结

在一个Android 程序开始运行的时候,会单独启动一个Process。默认的情况下,所有这个程序中的Activity或者Service(Service和 Activity只是Android提供的Components中的两种,除此之外还有Content Provider和Broadcast Receiver)都会跑在这个Process。
        一个Android 程序默认情况下也只有一个Process,但一个Process下却可以有许多个Thread。
       在这么多Thread当中,有一个Thread,我们称之为UI Thread。UI Thread在Android程序运行的时候就被创建,是一个Process当中的主线程Main Thread,主要是负责控制UI界面的显示、更新和控件交互。在Android程序创建之初,一个Process呈现的是单线程模型,所有的任务都在一个线程中运行。因此,我们认为,UI Thread所执行的每一个函数,所花费的时间都应该是越短越好。而其他比较费时的工作(访问网络,下载数据,查询数据库等),都应该交由子线程去执行,以免阻塞主线程。
        那么,UI Thread如何和其他Thread一起工作呢?常用方法是:
        诞生一个主线程的Handler物件,当做Listener去让子线程能将讯息Push到主线程的Message Quene里,以便触发主线程的handlerMessage()函数,让主线程知道子线程的状态,并在主线程更新UI。
       例如,在子线程的状态发生变化时,我们需要更新UI。如果在子线程中直接更新UI,通常会抛出下面的异常:
       android.view.ViewRoot$CalledFromWrongThreadException:Only the original thread that created a view hierarchy can touch its views.
       意思是,无法在子线程中更新UI。为此,我们需要通过Handler物件,通知主线程Ui Thread来更新界面。

Android的用户界面工具包不是线程安全的,只能在UI线程中操作它.

· Activity.runOnUiThread(Runnable)

与view.post类似

Java代码 

  1. public void onClick( View v ) {  
  2. new Thread( new Runnable() {  
  3. public void run() {  
  4. // 耗时操作
  5. ​    ​    ​    ​    ​    ​      loadNetWork();  
  6. ​                         Activity.runOnUiThread.( new Runnable() {  
  7.                                   myText.setText( 来自网络的信息);  
  8.                           });  
  9.                  }  
  10.         }).start();  

· View.post(Runnable)

  1. public void onClick( View v ) {  
  2. new Thread( new Runnable() {  
  3. public void run() {  
  4. // 耗时操作
  5. ​    ​    ​    ​    ​    ​      loadNetWork();  
  6. ​                          myText.post(new Runnable() { 
  1.                                   myText.setText( 来自网络的信息) ;  
  2.                           });  
  3.                  }  
  4.         }).start();  

· View.postDelayed(Runnable, long)

 

· Handler

子线程调用Handler的sendMessage(message)发送事件。


  • mHandler = new Handler() {  
  • @Override
  • public void handleMessage(Message msg) {  
  • //操作界面
  •        myText.setText( 来自网络的信息);  
  • super.handleMessage(msg);  
  •    }  
  •   }; 

  • public
    class MyThread extends Thread {  
  • public void run() {  
  • ​    ​    ​    // 耗时操作
  • ​    ​    ​    ​loadNetWork();  
  •             Message msg = new Message();  
  •             mHandler.sendMessage(msg);//向Handler发送消息,
  •       }  
  • 这些类和方法也往往使你的代码更复杂,更难以阅读。更糟糕的是,它需要频繁执行复杂的操作界面更新。

    · AsyncTask


  • //UI线程中执行
  • new DownloadImageTask().execute( "www.91dota.com" ); 

  • private
    class LoadTask extends AsyncTask {  
  • protected String doInBackground( String... url ) {  
  • return loadDataFormNetwork( url[0] );//后台耗时操作
  •     }  
  • protected void onPostExecute( String result ) {  
  •           myText.setText( result ); //得到来自网络的信息刷新页面
  •    } 
  • 为了解决这个问题,1.5和更高版本的Android平台提供了一个实用类称为AsyncTask,简化了长时间运行的任务,需要与用户界面的交互。
    类似AsyncTask的一个类UserTask也可用于Android 1.0和1.1版本,它提供了完全相同的API,所有您需要做的是把它的源代码复制到你的应用程序中。
    AsyncTask的目标是要为你的线程提供管理服务,我们前面的例子可以很容易的用AsyncTask来改写:
    public void onClick(View v) {  
      new DownloadImageTask().execute("http://www.ideasandroid.com/image.png");  
    }  
    private class DownloadImageTask extends AsyncTask<String, Void,Bitmap> {  
         protected Bitmap doInBackground(String... urls) {  
             return loadImageFromNetwork(urls[0]);  
         }  
         protected void onPostExecute(Bitmap result) {  
             mImageView.setImageBitmap(result);  
         }  

    正如你所看到的,我们必须通过继承AsyncTask类来使用它,非常重要的一点是:AsyncTask必须在UI线程中实例化它,并且只能执行一次。
    以下是AsyncTask的简要使用方法:
    ◆您可以指定三个参数类型,泛型参数,进度值(执行过程中返回的值)和最终值(执行完返回的值)。
    ◆该方法doInBackground()自动执行工作线程(后台线程)
    ◆onPreExecute(),onPostExecute()和onProgressUpdate()都是在UI线程调用
    ◆由doInBackground返回的值()发送到onPostExecute()
    ◆您可以在执行doInBackground()时调用publishProgress()然后在UI组程中执行onProgressUpdate()。
    ◆您可以从任何线程随时取消任务
    不管你是否使用AsyncTask,时刻牢记单一线程模型的两条规则:
    1、不要锁住用户界面。
    2、确保只在UI线程中访问Android用户界面工具包中的组件。
    AsyncTask只是可以让你更容易地做这些事情。

    (摘抄:http://android-xiaohui.iteye.com/blog/985345

    http://user.qzone.qq.com/68845164/blog/1315937247?ptlang=2052#!)

    posted @ 2011-06-11 00:44  hardiman  阅读(1672)  评论(0编辑  收藏  举报