前言
?Android沿用了Java的線程模型,除了Thread外崇决,Android還實(shí)現(xiàn)了AsyncTask、HandlerThread底挫、IntentService恒傻,它們的底層實(shí)現(xiàn)也是線程。
?根據(jù)官網(wǎng)消息建邓,Android R已正式棄用AsyncTask盈厘,那為什么我還繼續(xù)寫(xiě)這篇文章?原因很簡(jiǎn)單官边,雖然被棄用了沸手,但是Android的源碼中仍然有用到AsyncTask的地方外遇,從這點(diǎn)出發(fā)我們?nèi)匀恍枰肁syncTask的簡(jiǎn)單使用。
?本文講的是AsyncTask
相關(guān)文章閱讀
HandlerThread
IntentService
1 使用步驟
?Async是一種輕量級(jí)的異步任務(wù)類契吉,它可以在線程池中執(zhí)行后臺(tái)任務(wù)跳仿,然后把把執(zhí)行結(jié)果反饋給主線程。
①AsyncTask<Params, Progress, Result>是一個(gè)抽象類捐晶,我們需要繼承它并實(shí)現(xiàn)關(guān)鍵方法菲语。
/**
* public abstract class AsyncTask<Params, Progress, Result>
* Params:參數(shù)類型
* Progress:任務(wù)執(zhí)行進(jìn)度類型
* Result:返回結(jié)果類型
*/
class MyTask : AsyncTask<String, Int, String>() {
/**
* 在主線程中執(zhí)行
* 在異步任務(wù)執(zhí)行之前
* 可用于做一些準(zhǔn)備工作
* */
override fun onPreExecute() {
super.onPreExecute()
}
/**
* 在線程池中執(zhí)行,params標(biāo)識(shí)異步輸入?yún)?shù)
* */
override fun doInBackground(vararg params: String?): String {
//更新任務(wù)進(jìn)度
publishProgress()
}
/**
* 在主線程中執(zhí)行
* 當(dāng)后臺(tái)任務(wù)執(zhí)行進(jìn)度改變時(shí)調(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ù)被取消時(shí)調(diào)用惑灵,此時(shí)onPostExecute就不會(huì)被調(diào)用
* */
override fun onCancelled() {
super.onCancelled()
}
}
②頁(yè)面布局
<?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="還沒(méi)開(kāi)始哦~"
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í)行之前
* 可用于做一些準(zhǔn)備工作
* */
override fun onPreExecute() {
downloadPercent.text = "準(zhǔn)備下載英支。佩憾。。"
}
/**
* 在線程池中執(zhí)行潭辈,params標(biāo)識(shí)異步輸入?yún)?shù)
* */
override fun doInBackground(vararg params: String?): String {
//更新任務(wù)進(jìn)度
var progress = 0;
while (progress < 99) {
progress += 1
publishProgress(progress)
Thread.sleep(160)
}
return ""
}
/**
* 在主線程中執(zhí)行
* 當(dāng)后臺(tái)任務(wù)執(zhí)行進(jìn)度改變時(shí)調(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ù)被取消時(shí)調(diào)用鸯屿,此時(shí)onPostExecute就不會(huì)被調(diào)用
* */
override fun onCancelled() {
downloadPercent.text = "取消了"
downloadPb.progress = 0
}
}
}
2 AsyncTask的優(yōu)缺點(diǎn)
2.1 優(yōu)點(diǎn)
- AsyncTask是一個(gè)輕量級(jí)的異步任務(wù)類澈吨,內(nèi)部封裝了Handler和Thread把敢,可以自動(dòng)實(shí)現(xiàn)線程的切換。
- AsyncTask可以設(shè)置我們自己的線程池谅辣,達(dá)到收斂線程的目的修赞。
2.2 缺點(diǎn)及注意點(diǎn)
- AsyncTask被聲明為內(nèi)部類時(shí),若不是靜態(tài)內(nèi)部類桑阶,可能會(huì)發(fā)生Activity銷毀時(shí)AsyncTask還持有Activity的引用導(dǎo)致Activity無(wú)法被回收柏副。
- 在OnDestory時(shí)調(diào)用AsyncTask的cancel方法取消異步功能
- Android默認(rèn)旋轉(zhuǎn)就會(huì)創(chuàng)建實(shí)例,因此屏幕旋轉(zhuǎn)時(shí)會(huì)導(dǎo)致之前的MyTask對(duì)象改變蚣录,Google提供了三種方案:
①對(duì)于少量數(shù)據(jù): 通過(guò)onSaveInstanceState()割择,保存有關(guān)應(yīng)用狀態(tài)的數(shù)據(jù)。 然后在 onCreate() 或 onRestoreInstanceState() 期間恢復(fù) Activity 狀態(tài)萎河。
②對(duì)于大量數(shù)據(jù):用 Fragment 保留需要回復(fù)的對(duì)象荔泳。
③在Manifest中設(shè)置configChanges,不重啟Activity虐杯。
<activity
android:name=".ConfigChangesTestActivity"
android:configChanges="screenSize|orientation" >
</activity>
總結(jié)
?過(guò)去很多年見(jiàn)過(guò)與用到AsyncTask的次數(shù)并不多玛歌,因?yàn)锳syncTask存在很多明顯的問(wèn)題,使用過(guò)程中總是需要特別留意擎椰,而我們還可以使用RxJava進(jìn)行替代支子,因此對(duì)于使用AsyncTask并無(wú)太強(qiáng)烈的想法。直到今天AsyncTask被棄用达舒,谷歌建議使用kotlin協(xié)程進(jìn)行替代值朋,可以說(shuō)這天我等了很久叹侄,啊哈哈哈~就這樣吧