总结线程交互

来源:互联网 发布:叶根友特楷简体 mac版 编辑:程序博客网 时间:2024/06/04 23:30

  说到线程,大家都知道,可以当作android进程的一个轻量级的表现,只是不占有空间和资源。在android中,有一个线程是我们最常接触到的,当我们做的一个应用,在第一次进入的时候,进入第一个Activity的时候,android自身就会自动创建一个用于控制一些控件以及绘图的MainUI线程,也就是我们说的activity主线程。

  说到这里,就不得不提到一个概念,它就是消息队列,由于activity 的主线程里面已经给我们准备好了消息队列,所以我们只需要在用的时候直接用就可以了,但在自己创建的子线程里面却不行,因为子线程本身并没有消息队列这个东西,在我们做线程交互的时候,刷新主界面的时候,往往是通过Handle来完成的,这里不得不提到另一个东东,它叫LOOP,当我们从子线程里面,通过handle来发送一个消息出来之后,LOOP会把这个消息发送回到主线程里面,然后通过消息队列的方法,来处理这些消息,最终达成我们刷新主界面的效果。

  那如何在我们自己创建的子线程里面实现消息队列,很简单,调用Looper.prepare(),那么系统就会自动的为该线程建立一个消息队列,然后调用 Looper.loop();之后就进入了消息循环,这个之后就可以发消息、取消息、和处理消息。这个方法对于平常,我们自己一些用来控制线程交互的实现,非常有用,所以分享一下。

  说到这里,可能大家时常会遇到一些handle之后,好像没用的现象,这是因为,handle之后,LOOP把消息传到了消息队列的尾部,这是没有问题的,但是在处理端的时候,就有可能会出现阻塞的现象,所以,用handle来处理一些复杂的图象更新的时候,有时候有出现一些不可靠的现象。但Handle本身有自己的优势,就是使用简单,易懂,而且对于一般应用来说,出错的情况并不是很频繁,所以使用也就特别多。

  有可能大家会问,什么是可靠的呢,这里就不得不提到另一个东西,叫AsyncTask,简单来说,就是异步任务。 

  实现:

  1)  子类化AsyncTask
       2)  实现AsyncTask中定义的下面一个或几个方法
         onPreExecute() 开始执行前的准备工作;
         doInBackground(Params...) 开始执行后台处理,可以调用publishProgress方法来更新实时的任务进度;
         onProgressUpdate(Progress...)  在publishProgress方法被调用后,UI thread将调用这个方法从而在界面上展示任务的进展情况,例如通过一个进度条进行展示。
         onPostExecute(Result) 执行完成后的操作,传送结果给UI 线程。

  注意:     1) AsyncTask的实例必须在UI thread中创建;
        2) AsyncTask.execute方法必须在UI thread中调用;

  3)该task只能被执行一次,否则多次调用时将会出现异常。而且是不能手动停止

下面是一个例子,AsyncTask_eoe

  1. package xiaohang.zhimeng;   
  2.   
  3. import android.app.Activity;   
  4. import android.os.AsyncTask;   
  5. import android.os.Bundle;   
  6. import android.os.Handler;   
  7. import android.os.Message;   
  8. import android.os.SystemClock;   
  9. import android.widget.TextView;   
  10. import android.widget.Toast;   
  11.   
  12. /**  
  13.  * 一个使用异步任务的例子。一般来说一个异步任务只执行一次,这个例子有点非主流,任务结束后会触发下一次任务执行。 
  14.  * 由任务task在屏幕上打印数字,第一次任务执行由主Activity的onCreate触发,每次任务结束后 
  15.  * 设定下一次触发的时间,共执行5次。对于任务来说doInBackground()接收任务的参数params,并执行产生数字的动作,每一个数字 
  16.  * 产生后调用一次publishProgress()来更新UI,这个函数本身也是异步的只是用来发个消息调用完成后立即返回, 
  17.  * 而产生数字的动作在继续进行。更新界面的操作在onProgressUpdate()中设定。 所有的on函数都由系统调用,不能用户调用。 
  18.  * 代码中使用Handler是为了能触发任务执行,android规定这种异步任务每次执行完就结束,若要重新执行需要new一个新的。 
  19.  * 异步任务只能在UI线程里面创建和执行  
  20.  */  
  21. public class testAsync extends Activity {   
  22.     private final int MSG_TIMER = 10000;   
  23.     private TextView vText = null;   
  24.   
  25.     @Override  
  26.     protected void onCreate(Bundle savedInstanceState) {   
  27.         // TODO Auto-generated method stub  
  28.         super.onCreate(savedInstanceState);   
  29.         setContentView(R.layout.test);   
  30.         vText = (TextView) findViewById(R.id.TextView01);   
  31.         vText.setText("Num...");   
  32.   
  33.         new task().execute("->");   
  34.   
  35.     }   
  36.   
  37.     // 接收任务task发来的消息,触发一个新的任务   
  38.     private final Handler handler = new Handler() {   
  39.   
  40.         @Override  
  41.         public void handleMessage(Message msg) {   
  42.             // TODO Auto-generated method stub  
  43.             super.handleMessage(msg);   
  44.             System.out.println("Handler name -----------> " + Thread.currentThread().getName());   
  45.             System.out.println("Handler id ------------> " + Thread.currentThread().getId());   
  46.             switch (msg.what) {   
  47.             case MSG_TIMER:   
  48.                 new task().execute("->");   
  49.                 break;   
  50.             }   
  51.         }   
  52.     };   
  53.   
  54.     // 任务执行次数   
  55.     private static int times = 1;   
  56.   
  57.     // AsyncTask<>的参数类型由用户设定,这里设为三个String   
  58.     // 第一个String代表输入到任务的参数类型,也即是doInBackground()的参数类型  
  59.     // 第二个String代表处理过程中的参数类型,也就是doInBackground()执行过程中的产出参数类型,通过publishProgress()发消息  
  60.     // 传递给onProgressUpdate()一般用来更新界面   
  61.     // 第三个String代表任务结束的产出类型,也就是doInBackground()的返回值类型,和onPostExecute()的参数类型  
  62.     private class task extends AsyncTask<String, String, String> {   
  63.            
  64.         // 后台执行的耗时任务,接收参数并返回结果   
  65.         // 当onPostExecute()执行完,在后台线程中被系统调用  
  66.         @Override  
  67.         protected String doInBackground(String... params) {   
  68.             System.out.println("doInBackground name -----> " + Thread.currentThread().getName());   
  69.             System.out.println("doInBackground  id -----> " + Thread.currentThread().getId());   
  70.             // TODO Auto-generated method stub  
  71.             // 在这里产生数据,送给onProgressUpdate以更新界面  
  72.             String pre = params[0];   
  73.             System.out.println("pre is ----->" + pre);   
  74.   
  75.             for (int i = 0; i < 5; i++) {   
  76.                 System.out.println("note i am begin sleep ");   
  77.                 publishProgress(pre + i);   
  78.                        
  79.                    
  80.                 // 这里是否需要停顿下   
  81.                 System.out.println("hua li de bu zhuo " + pre + i);   
  82.                 SystemClock.sleep(1000);   
  83.             }   
  84.   
  85.             return "任务结束";   
  86.         }   
  87.   
  88.         // 任务执行结束后,在UI线程中被系统调用   
  89.         // 一般用来显示任务已经执行结束   
  90.         @Override  
  91.         protected void onPostExecute(String result) {   
  92.             // TODO Auto-generated method stub  
  93.             System.out.println("onPostExecute name --------> " + Thread.currentThread().getName());   
  94.             System.out.println("onPostExecute id --------> " + Thread.currentThread().getName());   
  95.             super.onPostExecute(result);   
  96.   
  97.             Toast.makeText(testAsync.this, result, Toast.LENGTH_SHORT).show();   
  98.   
  99.             // 任务执行5次后推出   
  100.             if (times > 5) {   
  101.                 return;   
  102.             }   
  103.   
  104.             // 设定下一次任务触发时间   
  105.             Message msg = Message.obtain();   
  106.             msg.what = MSG_TIMER;    
  107.             handler.sendMessageDelayed(msg, 10000L);   
  108.         }   
  109.   
  110.         // 最先执行,在UI线程中被系统调用   
  111.         // 一般用来在UI中产生一个进度条   
  112.         @Override  
  113.         protected void onPreExecute() {   
  114.             // TODO Auto-generated method stub  
  115.             System.out.println("onPreExecute id -------> " + Thread.currentThread().getId());   
  116.             System.out.println("onPreExecute name -------> " + Thread.currentThread().getName() );   
  117.             super.onPreExecute();   
  118.             Toast.makeText(testAsync.this"开始执行第" + times + "次任务: " + this,   
  119.                     Toast.LENGTH_SHORT).show();   
  120.             times++;   
  121.         }   
  122.   
  123.         // 更新界面操作,在收到更新消息后,在UI线程中被系统调用   
  124.         @Override  
  125.         protected void onProgressUpdate(String... values) {   
  126.             // TODO Auto-generated method stub  
  127.             System.out.println("onProgressUpdate id ---------> " + Thread.currentThread().getId());   
  128.             System.out.println("onProgressUpdate name -------> " + Thread.currentThread().getName());   
  129.             super.onProgressUpdate(values);   
  130.             vText.append(values[0]);   
  131.         }   
  132.   
  133.     }   
  134.   
  135. }  

     这个例子,写得很好,里面写了很多关于它的一些使用的方法,注意在使用execute(XXX)里面的参数,就是对应到下面几个方法里面的参数,AsyncTask<Params, Progress, Result>,这个就是相应的映射的参数表。


原创粉丝点击