Android之線程使用AsyncTask異步任務(一)

線程的概念

手機客戶端有個概念,即UI主線程,我們能看到的按鈕控件等其實都是有一條UI的主線程在運行着。如果有一條UI主線程在運行,在UI的主線程中我們去訪問網絡資源(存數據或者取數據),我們會遇到阻塞的現象。學習線程的好處:UI主線程是用於負責展示UI控件的,我們要完成耗時任務的操作,比如提交數據或者存數據應該在另外一個線程完成。


如果我們讓不同的組件在這裏運行,我們應該讓他運行在獨立的線程中,比如說,UI主線程在這運行着,同時我又下文件,又上傳數據,又看電影,這些分別不同的操作應該放在獨立的線程操作,不應該放在一個線程中操作。

系統不會給我們創建一個獨立的線程給每一個組件,也就是說,當我們點擊一個按鈕,訪問網絡圖片時(這是在主線程中操作的),我們期望的是不改在主線程中操作,系統不會幫我們創建的。如果不從主線程中分離開,這樣就會有好多組件的操作在主線程中操作,會導致主線程任務繁忙,尤其是耗時操作的時候(導致阻塞),反應超過5s就會可能產生ANR(application not responding)。


所以,UI主線程不能當做工作線程,Android中的線程模式應該是單線程的模式。

①不要阻塞UI主線程(不在UI線程訪問網絡等)。

②不在UI以外的線程當中訪問UI(UI的概念就是在主線程中呈現的)。


異步和同步的區別:

看下圖(參考別人的)



處理複雜的工作線程兩種機制:Handler或者AsyncTask


AsyncTask(異步任務)允許我們在用戶UI上執行異步的工作,這個執行可能是個阻塞的操作,它可以把結果發佈給UI。舉個例子,當我們下載一個文件時,刻度條就是UI,我們一邊下載,一邊讓刻度條走動來達到更新UI的效果。


異步任務操作的方法:

聲明一個類MyTask繼承(extends)AsyncTask(抽象類)->實現doInBackground()方法->爲了更新UI實現onPostExecute()方法->把這些結果從doInBackground()方法中傳遞到UI上->執行這個異步任務,只需在UI線程中調用execute()方法。


AsyncTask異步任務分爲三個參數Params,Progress和Result,四個步驟調用onPreExecute,doInBackground,onProgressUpdate和onPostExecute。

三個參數:

①Params:這個參數類型表示我們執行異步任務要發送的參數,也就是說,這個異步任務要執行什麼東西,比如訪問網絡這裏就是一個網址。

Progress:這個參數是一個進度單位的類型,這個進度單位是在後臺計算完成之後被髮布的單位。

Result:表示後臺執行的返回結果。

並非所有的異步任務都要用到三個參數,如果不用就用Void類型代替。

四個步驟:

執行一個完整的異步任務,要依次經歷以下四個步驟(步驟是有順序的①②③④順序執行),其中,doInBackground()方法是必須要執行的,即繼承了AsyncTask方法就一定要實現doInBackground方法,也就是說你得做一件事情,否則異步任務沒有意義

onPreExecute(),異步任務被執行之前執行,UI展示的時候執行。這個步驟通常用來構建一個異步任務,比如,我們可以顯示一個進度條給用戶看。

doInBackground(Params...),在onPreExecute()之後doInBackground()會立即執行,這個步驟通常用來執行後臺的操作(耗時操作)。Params...這個參數表示我們要執行的參數。參數的結果會被計算出來,並且通過這個步驟返回給最後一個步驟onPostExecute()。在這個步驟中間我們可以用publicProgress(Progress...)來發佈一個或多個的進度單位,在第三個步驟onProgressUpdate()被調用時,把這個值發佈給UI線程。

onProgressUpdate(Progress...)

onPostExecute(Result),後臺計算出結果後會執行在UI上面,UI上的結果通常會來自doInBackground(Params...)。

注意:假設我不使用提示框第①個步驟不需要調用,如果我不需要把這個結果更新給UI第④個步驟不需要調用,如果我在下載的時候不更新進度條,第③個步驟不需要,這就是爲什麼一個類繼承了AsyncTask方法的時候僅僅需要doInBackground方法。

下面舉個例子:點擊下載網絡圖片按鈕,實現下載網絡圖片功能

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.android_asynctask_downloadimage.MainActivity" >

    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginLeft="60dp"
        android:layout_marginTop="40dp"
         />

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:text="下載網絡圖片" />
	
</RelativeLayout>

MainActivity.java

package com.example.android_asynctask_downloadimage;

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 org.apache.http.util.EntityUtils;

import android.support.v7.app.ActionBarActivity;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;

public class MainActivity extends ActionBarActivity {

	private Button btn1;
	private ImageView imageView1;
	private final String IMAGE_PATH="https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png";
	private ProgressDialog dialog;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		btn1=(Button) this.findViewById(R.id.button1);
		imageView1=(ImageView) this.findViewById(R.id.imageView1);
		dialog=new ProgressDialog(MainActivity.this);
		dialog.setTitle("提示");
		dialog.setCancelable(false);
		dialog.setMessage("正在下載圖片,請等待...");
		
		btn1.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				new MyTask().execute(IMAGE_PATH);//執行異步任務
			}
		});//點擊這個按鈕下載圖片,需要訪問網絡,記得在清單文件AndroidManifest.xml中加授權android.permission.INTERNET
	}

	/**
	 * 異步任務執行網絡下載圖片
	 * @author liuya
	 *
	 */
	public class MyTask extends AsyncTask<String, Integer, byte[]>{

		@Override
		protected void onPreExecute() {
			// TODO Auto-generated method stub
			super.onPreExecute();
			dialog.show();
		}
		
		/**
		 * 後臺訪問網絡
		 */
		@Override
		protected byte[] doInBackground(String... params) {
			// TODO Auto-generated method stub
			HttpClient httpClient=new DefaultHttpClient();
			HttpGet httpGet=new HttpGet(params[0]);//可變參數,三個點代表可變參數
			byte[] result=null;
			try {
				HttpResponse httpResponse=httpClient.execute(httpGet);
				if(httpResponse.getStatusLine().getStatusCode()==200){
					result=EntityUtils.toByteArray(httpResponse.getEntity());
				}
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}finally{
				httpClient.getConnectionManager().shutdown();
			}
			
			return result;
		}
		
		/**
		 * 更新UI
		 */
		@Override
		protected void onPostExecute(byte[] result) {
			// TODO Auto-generated method stub
			super.onPostExecute(result);
			Bitmap bitmap=BitmapFactory.decodeByteArray(result, 0, result.length);
			imageView1.setImageBitmap(bitmap);
			dialog.dismiss();
		}
		
	}
	
	@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;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// Handle action bar item clicks here. The action bar will
		// automatically handle clicks on the Home/Up button, so long
		// as you specify a parent activity in AndroidManifest.xml.
		int id = item.getItemId();
		if (id == R.id.action_settings) {
			return true;
		}
		return super.onOptionsItemSelected(item);
	}
}

效果圖如下








發佈了84 篇原創文章 · 獲贊 8 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章