AsyncTask、多線程及線程通訊

 

AsyncTask,它使建立須要與用戶界面交互的長時間運行的任務變得更簡單。相對來講AsyncTask更輕量級一些,適用於簡單的異步處理,不須要藉助線程和Handler便可實現。 java

AsyncTask是抽象類.AsyncTask定義了三種泛型類型 Params,Progress和Result。 android

  Params 啓動任務執行的輸入參數,好比HTTP請求的URL。 apache

  Progress 後臺任務執行的百分比。 網絡

  Result 後臺執行任務最終返回的結果,好比String。 併發

 

    AsyncTask的執行分爲四個步驟,每一步都對應一個回調方法,這些方法不該該由應用程序調用,開發者須要作的就是實現這些方法。 app

  1) 子類化AsyncTask 異步

  2) 實現AsyncTask中定義的下面一個或幾個方法 async

onPreExecute(), 該方法將在執行實際的後臺操做前被UI thread調用。能夠在該方法中作一些準備工做,如在界面上顯示一個進度條。 ide

doInBackground(Params...), 將在onPreExecute 方法執行後立刻執行,該方法運行在後臺線程中。這裏將主要負責執行那些很耗時的後臺計算工做。能夠調用 publishProgress方法來更新實時的任務進度。該方法是抽象方法,子類必須實現。 函數

onProgressUpdate(Progress...),在publishProgress方法被調用後,UI thread將調用這個方法從而在界面上展現任務的進展狀況,例如經過一個進度條進行展現。 

onPostExecute(Result), 在doInBackground 執行完成後,onPostExecute 方法將被UI thread調用,後臺的計算結果將經過該方法傳遞到UI thread

 

爲了正確的使用AsyncTask類,如下是幾條必須遵照的準則: 

  1) Task的實例必須在UI thread中建立 

  2) execute方法必須在UI thread中調用 

  3) 不要手動的調用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)這幾個方法 

  4) 該task只能被執行一次,不然屢次調用時將會出現異常 

doInBackground方法和onPostExecute的參數必須對應,這兩個參數在AsyncTask聲明的泛型參數列表中指定,第一個爲doInBackground接受的參數,第二個爲顯示進度的參數,第第三個爲doInBackground返回和onPostExecute傳入的參數。

 

能夠調用cancel(boolean)去取消一個任務,在cancel(boolean)調用後,isCancelled()會返回true,而且在doInBackground(Object[])調用後會當即調用onCancelled(Object),而不會去調用onPostExecute(Object)。在調用cancel(boolean)時,若是線程尚未開始執行,那麼線程不會去運行;若是線程已經開始運行了,那麼mayInterruptIfRunning 標誌決定了線程會否應該被中斷。所以咱們在doInBackground(Object[])中應該按期的檢查isCancelled()的值,以保證線程可以快速的中斷。

 

package com.example.asynctask; import java.io.IOException; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import android.os.AsyncTask; import android.os.Bundle; import android.app.Activity; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.Toast; import android.graphics.Bitmap; import android.graphics.BitmapFactory; public class Main_Activity extends Activity { private ImageView m_imageView; private Button m_button; private Button m_but; private ProgressBar m_proBar; Task task; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); m_imageView = (ImageView)findViewById(R.id.imageView); m_button = (Button)findViewById(R.id.download_btn); m_proBar = (ProgressBar)findViewById(R.id.progressBar); m_but = (Button)findViewById(R.id.cancel_btn); task = null; m_button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub
                task = new Task(); task.execute("http://www.baidu.com/img/shouye_b5486898c692066bd2cbaeda86d74448.gif"); } }); m_but.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub
                task.cancel(false); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present.
 getMenuInflater().inflate(R.menu.main_, menu); return true; } class Task extends AsyncTask<String,Integer,Bitmap>{ @Override protected Bitmap doInBackground(String... params) {//處理後臺執行的任務,在後臺線程執行 // TODO Auto-generated method stub
 publishProgress(0);//將會調用onProgressUpdate(Integer... progress)方法 
             HttpClient hc = new DefaultHttpClient(); publishProgress(30); HttpGet hg = new HttpGet(params[0]); Bitmap bm = null; HttpResponse hr = null; try { Thread.currentThread().sleep(1000); } catch (InterruptedException e1) { // TODO Auto-generated catch block
 e1.printStackTrace(); } if(isCancelled()) return null; try { hr = hc.execute(hg); bm = BitmapFactory.decodeStream(hr.getEntity().getContent()); } catch (ClientProtocolException e) { // TODO Auto-generated catch block
 e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block
 e.printStackTrace(); } if(isCancelled()) return null; publishProgress(100); return bm; } protected void onProgressUpdate(Integer... progress) {//在調用publishProgress以後被調用,在ui線程執行
            m_proBar.setProgress(progress[0]); } protected void onPostExecute(Bitmap result) {//後臺任務執行完以後被調用,在ui線程執行 
            if(result != null) { Toast.makeText(Main_Activity.this, "成功獲取圖片", Toast.LENGTH_LONG).show(); m_imageView.setImageBitmap(result); }else { Toast.makeText(Main_Activity.this, "獲取圖片失敗", Toast.LENGTH_LONG).show(); m_proBar.setProgress(0); } publishProgress(0); } protected void onPreExecute () {//在 doInBackground(Params...)以前被調用,在ui線程執行 
            m_imageView.setImageBitmap(null); m_proBar.setProgress(0);//進度條復位 
 } protected void onCancelled () {//在ui線程執行 
            m_proBar.setProgress(0);//進度條復位 
            Toast.makeText(Main_Activity.this, "取消加載", Toast.LENGTH_LONG).show(); } }; }

 

在程序中使用了網絡,所以須要在AndroidManifest.xml添加

<uses-permission android:name="android.permission.INTERNET"></uses-permission>

Handler

Looper 是消息隊列的管理者,消息循環

Handler 是消息的處理者

Message 消息

MessageQueue 消息隊列

 

Handler 只可以關聯一個線程的Looper,一個Looper只能管理一個MessageQueue。能夠經過關聯的Handler向線程發送Message或者Runnable到消息隊列中。

package com.example.handlemsg; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.annotation.SuppressLint; import android.app.Activity; import android.util.Log; import android.view.Menu; import android.view.View; import android.widget.Button; import android.widget.TextView; public class MainActivity extends Activity { TextView tv; Button but1; Button but2; MyHandler hd, subHd; HandlerThread sub; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv = (TextView)findViewById(R.id.tv); but1 = (Button)findViewById(R.id.button1); but2 = (Button)findViewById(R.id.button2); hd = new MyHandler(); but1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub //給主線程本身發送一條消息
                hd.sendEmptyMessage(0); } }); but2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub //新建一個帶有Looper的線程
                sub = new HandlerThread("sub-thread"); sub.start(); //給子線程關聯Handler,併發送一條消息給子線程
                subHd = new MyHandler(sub.getLooper()); subHd.sendEmptyMessage(0); //給子線程發送一個Runnable,在Runnable中發送一條消息給主線程
                subHd.post(new Runnable(){ @Override public void run() { // TODO Auto-generated method stub //發送一條消息給主線程
                        hd.sendEmptyMessage(0); } }); } }); //終止子線程 //subHd.getLooper().quit();
 } @SuppressLint("HandlerLeak") class MyHandler extends Handler{ public MyHandler() { // TODO Auto-generated constructor stub
            super(); } public MyHandler(Looper looper) { // TODO Auto-generated constructor stub
            super(looper); } public void handleMessage(Message msg){ switch(msg.what) { case 0: Log.d(Thread.currentThread().getName(), "msg 0"); break; case 1: Log.d(Thread.currentThread().getName(), "msg 1"); break; default: Log.d(Thread.currentThread().getName(), "msg default"); break; } }//handlemsg
 }//MyHandler
 }

synchronized

1.  synchronized 方法控制對類成員變量的訪問:每一個類實例對應一把鎖,每一個 synchronized 方法都必須得到調用該方法的類實例的鎖方能執行,不然所屬線程阻塞,方法一旦執行,就獨佔該鎖,直到從該方法返回時纔將鎖釋放,此後被阻塞的線程方能得到該鎖,從新進入可執行狀態。這種機制確保了同一時刻對於每個類實例,其全部聲明爲 synchronized 的成員函數中至多隻有一個處於可執行狀態(由於至多隻有一個可以得到該類實例對應的鎖),從而有效避免了類成員變量的訪問衝突(只要全部可能訪問類成員變量的方法均被聲明爲 synchronized)。  

2. synchronized 塊是這樣一個代碼塊,其中的代碼必須得到對象 syncObject (如前所述,能夠是類實例或類)的鎖方能執行。因爲能夠針對任意代碼塊,且可任意指定上鎖的對象,故靈活性較高。  

對synchronized(this)的一些理解 

1、當兩個併發線程訪問同一個對象object中的這個synchronized(this)同步代碼塊時,一個時間內只能有一個線程獲得執行。另外一個線程必須等待當前線程執行完這個代碼塊之後才能執行該代碼塊。  

2、然而,當一個線程訪問object的一個synchronized(this)同步代碼塊時,另外一個線程仍然能夠訪問該object中的非synchronized(this)同步代碼塊。  

3、尤爲關鍵的是,當一個線程訪問object的一個synchronized(this)同步代碼塊時,其餘線程對object中全部其它synchronized(this)同步代碼塊的訪問將被阻塞。  

4、當一個線程訪問object的一個synchronized(this)同步代碼塊時,它就得到了這個object的對象鎖。結果,其它線程對該object對象全部同步代碼部分的訪問都被暫時阻塞。

參考:http://blog.csdn.net/cjjky/article/details/7353390

相關文章
相關標籤/搜索