Android中通過(guò)AsyncTask類(lèi)來(lái)制作炫酷進(jìn)度條的實(shí)例教程
AsyncTask (API level 3,所以幾乎所有目前在市面上流通的 Android 版本皆可使用)
是除 Thread 外的另一種選擇,Android 團(tuán)隊(duì)鼓勵(lì)主執(zhí)行緒(UI thread) 專(zhuān)注于操作 & 畫(huà)面的流暢呈現(xiàn),
其余工作 (如網(wǎng)絡(luò)資料傳輸、檔案/磁碟/資料存取) 最好都在背景執(zhí)行;
Thread 通常要搭配 Handler 使用,而 AsyncTask 用意在簡(jiǎn)化背景執(zhí)行 thread 程序碼的撰寫(xiě)。
如果您預(yù)期要執(zhí)行的工作能在幾秒內(nèi)完成,就可以選擇使用 AsyncTask,若執(zhí)行的時(shí)間很長(zhǎng),
Android 則強(qiáng)烈建議采用 Executor, ThreadPoolExecutor and FutureTask。
要使用 AsyncTask,必定要建立一個(gè)繼承自 AsyncTask 的子類(lèi)別,并傳入 3 項(xiàng)資料:
- Params -- 要執(zhí)行 doInBackground() 時(shí)傳入的參數(shù),數(shù)量可以不止一個(gè)
- Progress -- doInBackground() 執(zhí)行過(guò)程中回傳給 UI thread 的資料,數(shù)量可以不止一個(gè)
- Rsesult -- 傳回執(zhí)行結(jié)果
若您沒(méi)有參數(shù)要傳入,則填入 Void (注意 V 為大寫(xiě))。
AsyncTask 的運(yùn)作有 4 個(gè)階段:
- onPreExecute -- AsyncTask 執(zhí)行前的準(zhǔn)備工作,例如畫(huà)面上顯示進(jìn)度表,
- doInBackground -- 實(shí)際要執(zhí)行的程序碼就是寫(xiě)在這里,
- onProgressUpdate -- 用來(lái)顯示目前的進(jìn)度,
- onPostExecute -- 執(zhí)行完的結(jié)果 - Result 會(huì)傳入這里。
除了 doInBackground,其他 3 個(gè) method 都是在 UI thread 呼叫
炫酷進(jìn)度條實(shí)例
我們以一個(gè)實(shí)例來(lái)說(shuō)明,“點(diǎn)擊按鈕開(kāi)始下載QQAndroid安裝包,然后顯示一個(gè)對(duì)話(huà)框來(lái)反饋下載進(jìn)度”。我們先初始化一個(gè)對(duì)話(huà)框,由于要顯示進(jìn)度,我們用Github上面一個(gè)能夠顯示百分比的進(jìn)度條 NumberProgressbar,啟動(dòng)任務(wù)的按鈕我們使用 circlebutton,一個(gè)有酷炫動(dòng)畫(huà)的按鈕,Github上面有很多非常好的開(kāi)源項(xiàng)目,當(dāng)然炫酷的控件是其中一部分了,后面有機(jī)會(huì),會(huì)去學(xué)習(xí)一些比較流行的控件它們的實(shí)現(xiàn)原理,今天就暫且拿來(lái)主義了~~。
1.先初始化進(jìn)度條提示對(duì)話(huà)框。
builder = new AlertDialog.Builder(
MainActivity.this);
LayoutInflater inflater = LayoutInflater.from(MainActivity.this);
mDialogView = inflater.inflate(R.layout.progress_dialog_layout, null);
mNumberProgressBar = (NumberProgressBar)mDialogView.findViewById(R.id.number_progress_bar);
builder.setView(mDialogView);
mDialog = builder.create();
2.設(shè)置按鈕點(diǎn)擊事件。
findViewById(R.id.circle_btn).setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
dismissDialog();
mNumberProgressBar.setProgress(0);
myTask = new MyAsyncTask();
myTask.execute(qqDownloadUrl);
}
});
3.DownloadAsyncTask實(shí)現(xiàn),有點(diǎn)長(zhǎng)。
private class DownloadAsyncTask extends AsyncTask<String , Integer, String> {
@Override
protected void onPreExecute() {
super.onPreExecute();
mDialog.show();
}
@Override
protected void onPostExecute(String aVoid) {
super.onPostExecute(aVoid);
dismissDialog();
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
mNumberProgressBar.setProgress(values[0]);
}
@Override
protected void onCancelled(String aVoid) {
super.onCancelled(aVoid);
dismissDialog();
}
@Override
protected void onCancelled() {
super.onCancelled();
dismissDialog();
}
@Override
protected String doInBackground(String... params) {
String urlStr = params[0];
FileOutputStream output = null;
try {
URL url = new URL(urlStr);
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
String qqApkFile = "qqApkFile";
File file = new File(Environment.getExternalStorageDirectory() + "/" + qqApkFile);
if (file.exists()) {
file.delete();
}
file.createNewFile();
InputStream input = connection.getInputStream();
output = new FileOutputStream(file);
int total = connection.getContentLength();
if (total <= 0) {
return null;
}
int plus = 0;
int totalRead = 0;
byte[] buffer = new byte[4*1024];
while((plus = input.read(buffer)) != -1){
output.write(buffer);
totalRead += plus;
publishProgress(totalRead * 100 / total);
if (isCancelled()) {
break;
}
}
output.flush();
} catch (MalformedURLException e) {
e.printStackTrace();
if (output != null) {
try {
output.close();
} catch (IOException e2) {
e2.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
if (output != null) {
try {
output.close();
} catch (IOException e2) {
e2.printStackTrace();
}
}
} finally {
if (output != null) {
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
}
這樣一個(gè)簡(jiǎn)單的下載文件文件就基本實(shí)現(xiàn)了,到目前為止談不上技巧,但是現(xiàn)在我們有一個(gè)問(wèn)題,就是如果我們的Activity正在后臺(tái)執(zhí)行一個(gè)任務(wù),可能耗時(shí)較長(zhǎng),那用戶(hù)可能會(huì)點(diǎn)擊返回退出Activity或者退出App,那么后臺(tái)任務(wù)不會(huì)立即退出,如果AsyncTask內(nèi)部有Activity中成員變量的引用,還會(huì)造成Activity的回收延時(shí),造成一段時(shí)間內(nèi)的內(nèi)存泄露,所以我們需要加上下面的第四步處理。
4.onPause中判斷應(yīng)用是否要退出,從而決定是否取消AsyncTask執(zhí)行。
@Override
protected void onPause() {
super.onPause();
if (myTask != null && isFinishing()) {
myTask.cancel(false);
}
}
這樣我們的異步任務(wù)就會(huì)在Activity退出時(shí),也隨之取消任務(wù)執(zhí)行,順利被系統(tǒng)銷(xiāo)毀回收,第四步很多時(shí)候會(huì)被遺漏,而且一般也不會(huì)有什么致命的問(wèn)題,但是一旦出問(wèn)題了,就很難排查,所以遵循編碼規(guī)范還是有必要的。
相關(guān)文章
Android獲取SD卡路徑及SDCard內(nèi)存的方法
這篇文章主要介紹了Android獲取SD卡路徑及SDCard內(nèi)存的方法,較為詳細(xì)的分析了Android針對(duì)SD卡操作所涉及的類(lèi)及其具體函數(shù)功能,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-02-02
Flutter?Android多窗口方案落地實(shí)戰(zhàn)
這篇文章主要為大家介紹了Flutter?Android多窗口方案落地實(shí)戰(zhàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02
Android屬性動(dòng)畫(huà)特點(diǎn)詳解
這篇文章主要為大家詳細(xì)介紹了Android屬性動(dòng)畫(huà)特點(diǎn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-11-11
Android Room數(shù)據(jù)庫(kù)容易遇到的問(wèn)題以及解決方法
這篇文章給大家介紹了我們?cè)贏ndroid Room數(shù)據(jù)庫(kù)容易遇到的坑以及解決方法,文中有詳細(xì)的代碼示例供我們參考,具有一定的參考價(jià)值,需要的朋友可以參考下2023-09-09
條件數(shù)據(jù)庫(kù)Android:sqllite的簡(jiǎn)單使用
條件數(shù)據(jù)庫(kù)Android:sqllite的簡(jiǎn)單使用,需要的朋友可以參考一下2013-05-05
Android自定義View實(shí)現(xiàn)簡(jiǎn)單水波紋效果
這篇文章主要為大家詳細(xì)介紹了Android自定義View實(shí)現(xiàn)簡(jiǎn)單水波紋效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08
Android自定義控件之小說(shuō)書(shū)架實(shí)現(xiàn)示例詳解
這篇文章主要為大家介紹了Android自定義控件之小說(shuō)書(shū)架示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪方法2023-04-04
Android開(kāi)發(fā)之Flutter與webview通信橋梁實(shí)現(xiàn)
這篇文章主要為大家介紹了Android開(kāi)發(fā)之Flutter與webview通信橋梁實(shí)現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06
Android使用SharedPreferences存儲(chǔ)XML文件的實(shí)現(xiàn)方法
這篇文章主要介紹了Android使用SharedPreferences存儲(chǔ)XML文件的實(shí)現(xiàn)方法,實(shí)例分析了SharedPreferences類(lèi)的基本初始化與文件存儲(chǔ)相關(guān)技巧,需要的朋友可以參考下2016-07-07

