前言
Android沿用了Java的线程模型,除了Thread外,Android还实现了AsyncTask、HandlerThread、IntentService,它们的底层实现也是线程。
根据官网消息,Android R已正式弃用AsyncTask,那为什么我还继续写这篇文章?原因很简单,虽然被弃用了,但是Android的源码中仍然有用到AsyncTask的地方,从这点出发我们仍然需要懂得AsyncTask的简单使用。
本文讲的是AsyncTask
相关文章阅读
HandlerThread
IntentService
1 使用步骤
Async是一种轻量级的异步任务类,它可以在线程池中执行后台任务,然后把把执行结果反馈给主线程。
①AsyncTask<Params, Progress, Result>是一个抽象类,我们需要继承它并实现关键方法。
/**
* public abstract class AsyncTask<Params, Progress, Result>
* Params:参数类型
* Progress:任务执行进度类型
* Result:返回结果类型
*/
class MyTask : AsyncTask<String, Int, String>() {
/**
* 在主线程中执行
* 在异步任务执行之前
* 可用于做一些准备工作
* */
override fun onPreExecute() {
super.onPreExecute()
}
/**
* 在线程池中执行,params标识异步输入参数
* */
override fun doInBackground(vararg params: String?): String {
//更新任务进度
publishProgress()
}
/**
* 在主线程中执行
* 当后台任务执行进度改变时调用
* */
override fun onProgressUpdate(vararg values: Int?) {
super.onProgressUpdate(*values)
}
/*
* 在主线程中执行
* 在异步任务执行之后
* result为doInBackground的返回值
* */
override fun onPostExecute(result: String?) {
super.onPostExecute(result)
}
/*
*异步任务被取消时调用,此时onPostExecute就不会被调用
* */
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>
③调用execute()方法执行异步任务。
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设置线程池,收敛线程
val ex = Executors.newFixedThreadPool(1)
myTask.executeOnExecutor(ex)
}
inner class MyTask : AsyncTask<String, Int, String>() {
/**
* 在主线程中执行
* 在异步任务执行之前
* 可用于做一些准备工作
* */
override fun onPreExecute() {
downloadPercent.text = "准备下载。。。"
}
/**
* 在线程池中执行,params标识异步输入参数
* */
override fun doInBackground(vararg params: String?): String {
//更新任务进度
var progress = 0;
while (progress < 99) {
progress += 1
publishProgress(progress)
Thread.sleep(160)
}
return ""
}
/**
* 在主线程中执行
* 当后台任务执行进度改变时调用
* */
override fun onProgressUpdate(vararg values: Int?) {
downloadPb.progress = values[0]!!
downloadPercent.text = "${values[0]!!}%"
}
/*
* 在主线程中执行
* 在异步任务执行之后
* result为doInBackground的返回值
* */
override fun onPostExecute(result: String?) {
downloadPercent.text = "加载完毕"
}
/*
*异步任务被取消时调用,此时onPostExecute就不会被调用
* */
override fun onCancelled() {
downloadPercent.text = "取消了"
downloadPb.progress = 0
}
}
}
2 AsyncTask的优缺点
2.1 优点
- AsyncTask是一个轻量级的异步任务类,内部封装了Handler和Thread,可以自动实现线程的切换。
- AsyncTask可以设置我们自己的线程池,达到收敛线程的目的。
2.2 缺点及注意点
- AsyncTask被声明为内部类时,若不是静态内部类,可能会发生Activity销毁时AsyncTask还持有Activity的引用导致Activity无法被回收。
- 在OnDestory时调用AsyncTask的cancel方法取消异步功能
- Android默认旋转就会创建实例,因此屏幕旋转时会导致之前的MyTask对象改变,Google提供了三种方案:
①对于少量数据: 通过onSaveInstanceState(),保存有关应用状态的数据。 然后在 onCreate() 或 onRestoreInstanceState() 期间恢复 Activity 状态。
②对于大量数据:用 Fragment 保留需要回复的对象。
③在Manifest中设置configChanges,不重启Activity。
<activity
android:name=".ConfigChangesTestActivity"
android:configChanges="screenSize|orientation" >
</activity>
总结
过去很多年见过与用到AsyncTask的次数并不多,因为AsyncTask存在很多明显的问题,使用过程中总是需要特别留意,而我们还可以使用RxJava进行替代,因此对于使用AsyncTask并无太强烈的想法。直到今天AsyncTask被弃用,谷歌建议使用kotlin协程进行替代,可以说这天我等了很久,啊哈哈哈~就这样吧