AsyncTask的個人使用總結

包括下載圖片,下載apk,以及dialog的一些處理


首先我們看下官方文檔的對AsyncTask的定義。

public abstract class AsyncTask<Params, Progress, Result> {  
官方文檔對這三個參數的解釋如下:

Params, the type of the parameters sent to the task upon execution.
Progress, the type of the progress units published during the background computation.
Result, the type of the result of the background computation.
這三個泛型分別表示“啓動任務時輸入的參數”,“後臺執行的進度”,“執行完成後返回的結果”。


當一個異步任務執行時,一般會通過四個步驟來完成:


onPreExecute(),這個方法在AsyncTask開啓之後,第一個執行的方法,一般能用於設置任務,例如在用戶界面開啓一個進度條,或者開啓一個dialog等等。也可不設置。

doInBackground(Params...),這一步在執行玩onPreExecute()後立即執行,耗時操作主要在這裏面執行,主要接受傳進來的參數,如URl等並可以返回計算結果。在執行過程中可以調用publishProgress(Progress...)來更新進度信息。

onProgressUpdate(Progress...),調用完publishProgress()方法後,可以在此方法中,直接將進度更新到UI組件上。

onPostExecute(Result),doInBackground()方法執行完成後,會調用此方法,由於doInBackgorund()方法返回的是Long類型,並且onPostExecute()方法傳入的參數也是Long類型,所以,執行完doInBackground()會將結果傳入到onPostExecute()方法中,對結果進行處理,例如將結果顯示在UI組件上。也可以不返回結果,在onPostExecute中做自己想做的操作。


使用AsyncTask'需要遵守一下規則。



下面是擁有的方法:




下載過程都需要加上internet權限,如果涉及到我存儲,也需要加上write或者read權限


1.使用AsyncTask下載多張圖片到本地

package com.example.testimagedownload;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import android.R.integer;
import android.R.string;
import android.app.Activity;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ImageView;

public class MainActivity extends Activity {

	private File cache;

	Handler handler = new Handler() {
		public void handleMessage(Message msg) {
			switch (msg.what) {
			case 0:
				AsyncImageTask task = new AsyncImageTask(); // 開啓異步線程
				task.execute(images); // 將url數組穿進去  。如果只有一個地址,就不用傳參了也行
				break;

			default:
				break;
			}
		};
	};

	// 存放圖片時所用的名字
	public static final String[] imageName = { "a.jpg", "b.jpg", "c.jpg",
			"d.jpg", "e.jpg", "f.jpg", "g.jpg", "h.jpg", "i.jpg" };

	public static final String[] images = {
			"http://img0.ph.126.net/7I6B58kXE20qqCZ0utlb_g==/3291568377754692414.jpg",
			"http://pic13.nipic.com/20110317/6905997_175430392162_2.jpg",
			"http://pic33.nipic.com/20130928/3901796_081439725135_2.jpg",
			"http://s8.51cto.com/wyfs01/M00/30/B2/wKioJlJbmUDz7hXUAAAxFABWIwg573.jpg",
			"http://a1.att.hudong.com/00/30/01300542906611141741303926721_s.jpg",
			"http://pic.58pic.com/58pic/13/39/88/73C58PICs3y_1024.JPG",
			"http://imgk.zol.com.cn/ask/1/998_a9ddbf3a05c8bc1233c4132caea67e44.jpg",
			"http://pic.58pic.com/58pic/14/82/09/15R58PICirn_1024.jpg",
			"http://pic11.nipic.com/20101129/3096042_225034073400_2.jpg" };

	// public List<String> contact = new ArrayList<String>();

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		// 創建緩存目錄,系統一運行就得創建緩存目錄的,
		// cache = new File(Environment.getExternalStorageDirectory(), "cache");
		File dataDir = getFilesDir().getParentFile();
		cache = new File(dataDir, "applist"); 
		if (!cache.exists()) {
			cache.mkdirs();
		}
		handler.sendEmptyMessage(0);
	}

	private final class AsyncImageTask extends AsyncTask<String, Integer, Uri> {

		// 後臺運行的子線程子線程
		@Override
		protected Uri doInBackground(String... params) {
			// String[] list = (String[]) params; // 可以轉換,也可以不轉換
			try {
				for (int i = 0; i < params.length; i++) {
					getImageURI(params[i], cache, imageName[i]);
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
			return null;
		}

		// 這個放在在ui線程中執行
		@Override
		protected void onPostExecute(Uri result) {
			super.onPostExecute(result);
		}
	}

	/*
	 * 從網絡上獲取圖片,如果圖片在本地存在的話就直接拿,如果不存在再去服務器上下載圖片 這裏的path是圖片的地址
	 */
	public Uri getImageURI(String path, File cache, String name)
			throws Exception {
		System.out.println("ContactServicegetImageURI----->Start");

		File file = new File(cache, name);
		// 如果圖片存在本地緩存目錄,則不去服務器下載
		if (file.exists()) {
			return Uri.fromFile(file);// Uri.fromFile(path)這個方法能得到文件的URI
		} else {
			// 從網絡上獲取圖片
			URL url = new URL(path);
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			conn.setConnectTimeout(5000);
			conn.setRequestMethod("GET");
			conn.setDoInput(true);
			if (conn.getResponseCode() == 200) {

				InputStream is = conn.getInputStream();
				FileOutputStream fos = new FileOutputStream(file);
				byte[] buffer = new byte[1024];
				int len = 0;
				while ((len = is.read(buffer)) != -1) {
					fos.write(buffer, 0, len);
				}
				is.close();
				fos.close();

				if (file.length() == 0) {
					// exception
				}
				// 返回一個URI對象
				return Uri.fromFile(file);
			}
		}

		System.out.println("ContactServicegetImageURI----->end");
		return null;
	}
}


2.使用AsyncTask根據url下載apk文件

(同時包括dialog提示正在下載,還有點擊返回鍵停止下載等。還有提示下載成功或者失敗功能。)

MainActivity.java

package com.example.asynctaskdemo;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.R.integer;
import android.app.Activity;
import android.app.Dialog;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity implements OnClickListener {

	private Button button1, button2;
	AsyncApkTask task = null;
	int contentLength = 0;
	String appUrlStr = "http://u.androidgame-store.com/new/game1/51/108751/lltskb_1442224809595.apk?f=baidu_1";
	String appName = "aa應用";

	public Dialog mLoading = null;
	public Dialog resultDialog = null;

	Handler handler = new Handler() {
		public void handleMessage(android.os.Message msg) {
			switch (msg.what) {
			case 0:
				// 開啓下載的線程
				task = new AsyncApkTask();
				task.execute();
				break;
			case 1:
				mLoading.show();
				break;
			case 2:
				mLoading.dismiss();
				// 將目前的AsycnTask銷燬,雖然這個是無效的。
				task.cancel(true);
				resultDialog = ResultDialogUtils.createLoadingDialog(
						MainActivity.this, "下載失敗!", appName);
				resultDialog.show();
				sendEmptyMessageDelayed(4, 2000); // 2秒之後,銷燬顯示結果的dialog
				break;
			case 3:
				mLoading.dismiss();
				resultDialog = ResultDialogUtils.createLoadingDialog(
						MainActivity.this, "下載成功!", appName);
				resultDialog.show();
				sendEmptyMessageDelayed(4, 2000); // 2秒之後,銷燬顯示結果的dialog
				break;
			case 4:
				if (resultDialog != null && resultDialog.isShowing()) {
					resultDialog.dismiss();
				}
				break;
			default:
				break;
			}
		};
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		button1 = (Button) findViewById(R.id.button1);
		button2 = (Button) findViewById(R.id.button2);
		button1.setOnClickListener(this);
		button2.setOnClickListener(this);

		// 初始化進度條dialog,第一個參數一定要傳遞MainActivity.this,
		// 如果是同getApplication,dialog無法正常顯示,因爲在非activity界面是無法顯示dialog的
		mLoading = DialogUtils.createLoadingDialog(MainActivity.this, handler,
				appName);

	}

	@Override
	public void onClick(View v) {
		int id = v.getId();
		switch (id) {
		case R.id.button1:
			handler.sendEmptyMessage(0);
			break;
		case R.id.button2:

			break;
		default:
			break;
		}
	}

	/**
	 * 下載apk的異步線程
	 */
	public final class AsyncApkTask extends AsyncTask<String, Integer, Uri> {

		@Override
		protected void onPreExecute() {
			// 發送handler,開啓正在下載的dialog
			handler.sendEmptyMessage(1);
			super.onPreExecute();
		}

		@Override
		protected Uri doInBackground(String... params) {
			try {
				// getFilesDir()獲得的files的絕對路徑,使用getParentFile()獲得是其父路徑。
				// 結果也就是/data/data/baoming
				File file = getFilesDir().getParentFile();
				// 在上面得到的路徑下,創建applist目錄
				File file2 = new File(file, "applist");
				if (!file2.exists()) { // 如果該目錄不存在,就創建
					file2.mkdirs();
				}
				File file4 = new File(file2, "abc.apk");
				if (!file4.exists()) { // 如果文件不存在創建文件
					file4.createNewFile();
				}
				URL url = new URL(appUrlStr);

				if (isCancelled()) {
					if (file4.exists()) {
						file4.delete();
					}
					return null;
				}
				URLConnection conn = url.openConnection();
				// 獲得將要下載的網絡文件的大小
				contentLength = conn.getContentLength();
				InputStream is = conn.getInputStream();
				byte[] buff = new byte[contentLength];
				int length;
				OutputStream os = new FileOutputStream(file4);
				while ((length = is.read(buff)) != -1) {
					// if (isCancelled()) {
					//
					// os.close();
					// is.close();
					// file4.delete();
					//
					// return null;
					// }
					os.write(buff, 0, length);
				}
				os.close();
				is.close();
			} catch (MalformedURLException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}

			return null;
		}

		// 這個放在在ui線程中執行
		@Override
		protected void onPostExecute(Uri result) {
			File file = getFilesDir().getParentFile();
			File file2 = new File(file, "applist");
			File file3 = new File(file2, "abc.apk");
			if (contentLength != file3.length()) { // 如果大小不一致,說明下載不成功,就將不完整的apk刪除掉
				file3.delete();
				handler.sendEmptyMessage(2); // 然後發送下載失敗的消息
			} else {
				handler.sendEmptyMessage(3); // 如果大小一致,說明下載成功了,顯示下載成功的消息
			}
			super.onPostExecute(result);
		}
	}

}

DialogUtils.java

package com.example.asynctaskdemo;

import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Handler;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnKeyListener;
import android.widget.LinearLayout;
import android.widget.TextView;

public class DialogUtils {

	/**
	 * 創建自定義ProgressDialog
	 */
	public static Dialog createLoadingDialog(Context context,
			final Handler mHandler, String appName) {

		LayoutInflater inflater = LayoutInflater.from(context);
		View v = inflater.inflate(R.layout.layout_loading_dialog, null); // 得到加載view
		TextView app_name = (TextView) v.findViewById(R.id.dialog_app_name);
		app_name.setText("(" + appName + ")");
		LinearLayout layout = (LinearLayout) v.findViewById(R.id.dialog_view); // 加載佈局
		Dialog loadingDialog = new Dialog(context, R.style.loading_dialog); // 創建自定義樣式dialog
		loadingDialog.setCancelable(false); // 不可以用"返回鍵"取消
		loadingDialog.setContentView(layout, new LinearLayout.LayoutParams(
				LinearLayout.LayoutParams.WRAP_CONTENT,
				LinearLayout.LayoutParams.WRAP_CONTENT));

		// 監聽dialog界面的返回鍵
		loadingDialog.setOnKeyListener(new DialogInterface.OnKeyListener() {

			@Override
			public boolean onKey(DialogInterface dialog, int keyCode,
					KeyEvent event) {
				if (keyCode == KeyEvent.KEYCODE_BACK) {
					dialog.dismiss();
					mHandler.sendEmptyMessage(2);
				}
				return false;
			}

		});

		return loadingDialog;
	}
}


ResultDialogUtils.java

package com.example.asynctaskdemo;

import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Handler;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnKeyListener;
import android.widget.LinearLayout;
import android.widget.TextView;

public class ResultDialogUtils {


	/**
	 * 創建自定義ProgressDialog
	 */
	public static Dialog createLoadingDialog(Context context, String result,
			String appName) {

		LayoutInflater inflater = LayoutInflater.from(context);
		View v = inflater.inflate(R.layout.layout_result_dialog, null); // 得到加載view
		TextView result_tv = (TextView) v.findViewById(R.id.result_tv);
		result_tv.setText(result);
		TextView app_name = (TextView) v.findViewById(R.id.dialog_app_name1);
		app_name.setText("(" + appName + ")");
		LinearLayout layout = (LinearLayout) v.findViewById(R.id.dialog_view); // 加載佈局
		Dialog loadingDialog = new Dialog(context, R.style.loading_dialog); // 創建自定義樣式dialog
		loadingDialog.setCancelable(false); // 不可以用"返回鍵"取消
		loadingDialog.setContentView(layout, new LinearLayout.LayoutParams(
				LinearLayout.LayoutParams.WRAP_CONTENT,
				LinearLayout.LayoutParams.WRAP_CONTENT));

		return loadingDialog;
	}
}

layout_loading_dialog.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/dialog_view"
    android:layout_width="190dp"
    android:layout_height="120dp"
    android:background="@drawable/background_dialog"
    android:gravity="center_vertical|center"
    android:orientation="vertical"
    android:padding="12dp" >
    
    <ProgressBar
        style="?android:attr/progressBarStyleSmall"
        android:layout_width="30dip"
        android:layout_height="30dip"
        android:indeterminateDrawable="@anim/progress_bar" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="3dp"
        android:text="正在下載中"
        android:textColor="#FFFFFF"
        android:textSize="20sp" />

    <TextView
        android:id="@+id/dialog_app_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#FFFFFF"
        android:textSize="16sp" />

</LinearLayout>

layout_result_dialog.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/dialog_view"
   android:layout_width="190dp"
    android:layout_height="120dp"
    android:background="@drawable/background_dialog"
    android:gravity="center_vertical|center"
    android:orientation="vertical"
    android:padding="12dp" >

    <TextView
        android:id="@+id/result_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="3dp"
        android:text=""
        android:textColor="#FFFFFF"
        android:textSize="20sp" />

    <TextView
        android:id="@+id/dialog_app_name1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#FFFFFF"
        android:textSize="16sp" />

</LinearLayout>

anim---> progress_bar.xml

<?xml version="1.0" encoding="utf-8"?>
<animated-rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/isdoing"
    android:fromDegrees="0.0"
    android:pivotX="50.0%"
    android:pivotY="50.0%"
    android:toDegrees="360.0" />

styles.xml

 <style name="loading_dialog" parent="android:Theme.Dialog">
        <item name="android:windowFrame">@null</item>
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowIsFloating">true</item>
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:backgroundDimEnabled">false</item>
    </style>

還有就是兩張圖片,自行腦補。



1.Cancelling a Task
我們可以在任何時刻來取消我們的異步任務的執行,通過調用 cancel(boolean)方法,調用完這個方法後系統會隨後調用 isCancelled() 方法並且返回true。如果調用了這個方法,那麼在 doInBackgroud() 方法執行完之後,就不會調用 onPostExecute() 方法了,取而代之的是調用 onCancelled() 方法。爲了確保Task已經被取消了,我們需要經常調用 isCancelled() 方法來判斷,如果有必要的話。
2.在使用AsyncTask做異步任務的時候必須要遵循的原則:
AsyncTask類必須在UI Thread當中加載,在Android Jelly_Bean版本後這些都是自動完成的
AsyncTask的對象必須在UI Thread當中實例化
execute方法必須在UI Thread當中調用
不要手動的去調用AsyncTaskonPreExecute, doInBackground, publishProgress, onProgressUpdate, onPostExecute方法,這些都是由Android系統自動調用的
AsyncTask任務只能被執行一次





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