前言
?Android沿用了Java的線程模型,除了Thread外,Android還實現(xiàn)了AsyncTask、HandlerThread、IntentService,它們的底層實現(xiàn)也是線程。
?根據(jù)官網(wǎng)消息,Android R已正式棄用AsyncTask,那為什么我還繼續(xù)寫這篇文章?原因很簡單,雖然被棄用了,但是Android的源碼中仍然有用到AsyncTask的地方,從這點出發(fā)我們?nèi)匀恍枰肁syncTask的簡單使用。
?本文講的是AsyncTask
相關(guān)文章閱讀
HandlerThread
IntentService
1 使用步驟
?Async是一種輕量級的異步任務(wù)類,它可以在線程池中執(zhí)行后臺任務(wù),然后把把執(zhí)行結(jié)果反饋給主線程。
①AsyncTask<Params, Progress, Result>是一個抽象類,我們需要繼承它并實現(xiàn)關(guān)鍵方法。
/**
* public abstract class AsyncTask<Params, Progress, Result>
* Params:參數(shù)類型
* Progress:任務(wù)執(zhí)行進度類型
* Result:返回結(jié)果類型
*/
class MyTask : AsyncTask<String, Int, String>() {
/**
* 在主線程中執(zhí)行
* 在異步任務(wù)執(zhí)行之前
* 可用于做一些準備工作
* */
override fun onPreExecute() {
super.onPreExecute()
}
/**
* 在線程池中執(zhí)行,params標識異步輸入?yún)?shù)
* */
override fun doInBackground(vararg params: String?): String {
//更新任務(wù)進度
publishProgress()
}
/**
* 在主線程中執(zhí)行
* 當(dāng)后臺任務(wù)執(zhí)行進度改變時調(diào)用
* */
override fun onProgressUpdate(vararg values: Int?) {
super.onProgressUpdate(*values)
}
/*
* 在主線程中執(zhí)行
* 在異步任務(wù)執(zhí)行之后
* result為doInBackground的返回值
* */
override fun onPostExecute(result: String?) {
super.onPostExecute(result)
}
/*
*異步任務(wù)被取消時調(diào)用,此時onPostExecute就不會被調(diào)用
* */
override fun onCancelled() {
super.onCancelled()
}
}
②頁面布局
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".TaskActivity">
<Button
android:id="@+id/downloadBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下載"
app:layout_constraintBottom_toTopOf="@+id/downloadPb"
app:layout_constraintEnd_toStartOf="@+id/downloadCancel"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ProgressBar
android:id="@+id/downloadPb"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/downloadPercent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="還沒開始哦~"
app:layout_constraintBottom_toTopOf="@+id/downloadPb"
app:layout_constraintEnd_toEndOf="@+id/downloadCancel"
app:layout_constraintStart_toStartOf="@+id/downloadBtn"
app:layout_constraintTop_toBottomOf="@+id/downloadBtn" />
<Button
android:id="@+id/downloadCancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="26dp"
android:layout_marginLeft="26dp"
android:text="取消下載"
app:layout_constraintBottom_toBottomOf="@+id/downloadBtn"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/downloadBtn"
app:layout_constraintTop_toTopOf="@+id/downloadBtn" />
</androidx.constraintlayout.widget.ConstraintLayout>
③調(diào)用execute()方法執(zhí)行異步任務(wù)。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
myTask = MyTask()
downloadBtn.setOnClickListener {
myTask.execute()
}
downloadCancel.setOnClickListener {
myTask.cancel(true)
}
}

效果圖
④完整代碼
class TaskActivity : AppCompatActivity() {
private lateinit var myTask: MyTask
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
myTask = MyTask()
downloadBtn.setOnClickListener {
myTask.execute()
}
downloadCancel.setOnClickListener {
myTask.cancel(true)
}
//為AsyncTask設(shè)置線程池,收斂線程
val ex = Executors.newFixedThreadPool(1)
myTask.executeOnExecutor(ex)
}
inner class MyTask : AsyncTask<String, Int, String>() {
/**
* 在主線程中執(zhí)行
* 在異步任務(wù)執(zhí)行之前
* 可用于做一些準備工作
* */
override fun onPreExecute() {
downloadPercent.text = "準備下載。。。"
}
/**
* 在線程池中執(zhí)行,params標識異步輸入?yún)?shù)
* */
override fun doInBackground(vararg params: String?): String {
//更新任務(wù)進度
var progress = 0;
while (progress < 99) {
progress += 1
publishProgress(progress)
Thread.sleep(160)
}
return ""
}
/**
* 在主線程中執(zhí)行
* 當(dāng)后臺任務(wù)執(zhí)行進度改變時調(diào)用
* */
override fun onProgressUpdate(vararg values: Int?) {
downloadPb.progress = values[0]!!
downloadPercent.text = "${values[0]!!}%"
}
/*
* 在主線程中執(zhí)行
* 在異步任務(wù)執(zhí)行之后
* result為doInBackground的返回值
* */
override fun onPostExecute(result: String?) {
downloadPercent.text = "加載完畢"
}
/*
*異步任務(wù)被取消時調(diào)用,此時onPostExecute就不會被調(diào)用
* */
override fun onCancelled() {
downloadPercent.text = "取消了"
downloadPb.progress = 0
}
}
}
2 AsyncTask的優(yōu)缺點
2.1 優(yōu)點
- AsyncTask是一個輕量級的異步任務(wù)類,內(nèi)部封裝了Handler和Thread,可以自動實現(xiàn)線程的切換。
- AsyncTask可以設(shè)置我們自己的線程池,達到收斂線程的目的。
2.2 缺點及注意點
- AsyncTask被聲明為內(nèi)部類時,若不是靜態(tài)內(nèi)部類,可能會發(fā)生Activity銷毀時AsyncTask還持有Activity的引用導(dǎo)致Activity無法被回收。
- 在OnDestory時調(diào)用AsyncTask的cancel方法取消異步功能
- Android默認旋轉(zhuǎn)就會創(chuàng)建實例,因此屏幕旋轉(zhuǎn)時會導(dǎo)致之前的MyTask對象改變,Google提供了三種方案:
①對于少量數(shù)據(jù): 通過onSaveInstanceState(),保存有關(guān)應(yīng)用狀態(tài)的數(shù)據(jù)。 然后在 onCreate() 或 onRestoreInstanceState() 期間恢復(fù) Activity 狀態(tài)。
②對于大量數(shù)據(jù):用 Fragment 保留需要回復(fù)的對象。
③在Manifest中設(shè)置configChanges,不重啟Activity。
<activity
android:name=".ConfigChangesTestActivity"
android:configChanges="screenSize|orientation" >
</activity>
總結(jié)
?過去很多年見過與用到AsyncTask的次數(shù)并不多,因為AsyncTask存在很多明顯的問題,使用過程中總是需要特別留意,而我們還可以使用RxJava進行替代,因此對于使用AsyncTask并無太強烈的想法。直到今天AsyncTask被棄用,谷歌建議使用kotlin協(xié)程進行替代,可以說這天我等了很久,啊哈哈哈~就這樣吧