实现AsyncTask很简单:创建一个子类,重写doInBackground进行后台执行,并在后台任务执行之前,执行期间和执行之后为任何所需的UI更新添加帮助器方法。 尽管它很简单,但是还有一些要考虑的事项:
只要工作线程是活动的,它所引用的所有对象都保存在内存中,
因此,AsyncTask应该声明为一个独立的或静态的内部类,以便工作线程避免对外部类的隐式引用
AsyncTask通常向可能引用Context的UI线程发出更新,该UI线程通常是指是具有View视图的Activity。但是您应该避免在AsyncTask中引用View视图,这样View视图就不会在不需要的时候保存在内存中。因此,AsyncTask应该声明为一个静态内部类,该类持有对相关Context的引用。当不再需要引用时,通过将其设置为null来删除引用。
合理运用取消策略中断或取消正在执行的后台任务
Example:Download Images
这个示例显示了如何在Activity中使用AsyncTask从网络下载图像。界面由一个进度条(一个mprogressbar,它显示下载的图像的数量)和一个Layout(使用mlayoutImages,它的子元素构成下载的图像)组成。
在Activity创建时,下载任务开始执行,并在Activity销毁时取消下载任务。
class FileDownloadActivity:AppCompatActivity() {
private lateinit var mFileDownLoaderTask:DownloadTask
companion object{
// @1
var DOWNLOAD_URLS:Array = arrayOf(
"https://storage.googleapis.com/spec-host-backup/mio-components%2Fassets%2F1E7lXZfa3b5CAyF5bA33u2luiX3s08Scf%2Fbnb-limited.png",
"https://storage.googleapis.com/spec-host-backup/mio-components%2Fassets%2F1Mf9DGzjrs8ky6_pgjc1SBKLpF5mZd9GP%2Fbnb-consistent.png",
"https://storage.googleapis.com/spec-host-backup/mio-components%2Fassets%2F1BC1wiAWjQ9wD5rn9EbxDLvUsxOwkcQ8f%2Fbnb-convenient.png",
"https://storage.googleapis.com/spec-host-backup/mio-design%2Fassets%2F0B3wFuHgbfPkzeXY2V2VKdm45Vzg%2Faccessibility-hierarchy-1-do.png",
"https://storage.googleapis.com/spec-host-backup/mio-design%2Fassets%2F1hn9Ffe7iuhpl4HpJsIC6ikz0IPMwEfcJ%2Ftheming-color-surfacesbgs.png",
"https://storage.googleapis.com/spec-host-backup/mio-design%2Fassets%2F13Oed330QwZjx6LCPqXlIiWPzVI_fZZh8%2Fcolor-colorsystem-schemecreation-secondary-baseline-1.png",
"https://storage.googleapis.com/spec-host-backup/mio-design%2Fassets%2F1jTwR_tLfYC3x-B1bD8hN7Nza9x2y1Kny%2Ftheming-color-oncolors.png",
"https://storage.googleapis.com/spec-host-backup/mio-design%2Fassets%2F1PqH1prDsSruO48qhgq6ZkuG-GSVVixMR%2Fcolor-colorsystem-schemecreation-accessibility-2.png",
"https://storage.googleapis.com/spec-host-backup/mio-design%2Fassets%2F1Jo9yjAaKpYl3jijuskjU6_pfmML7n7B5%2Fcolor-colorsystem-schemecreation-altprimarysecondary-3.png",
"https://storage.googleapis.com/spec-host-backup/mio-design%2Fassets%2F181H5cwjIitZNB5aMubkSHjqfBAr8mos2%2Fcolor-colorsystem-schemecreation-altprimarysecondary-4.png",
"https://storage.googleapis.com/spec-host-backup/mio-design%2Fassets%2F1gNgK8xWBxDYQSuNvK1MoS3kFfPbetcgs%2Fcolor-colorsystem-schemecreation-altprimarysecondary-5.png",
"https://storage.googleapis.com/spec-host-backup/mio-design%2Fassets%2F1SDGX3-el7fSZgwPwWVnMr7ri00_YV-Al%2Fcolor-colorsystem-schemecreation-altprimarysecondary-6.png",
"https://storage.googleapis.com/spec-host-backup/mio-design%2Fassets%2F1Cr__9NRDY9K--yaovyZdora4YWV5bICC%2Fcolor-colorsystem-schemecreation-dataviz.png",
"https://storage.googleapis.com/spec-host-backup/mio-design%2Fassets%2F12Tq1c4gZumASdmV4-Gz3Z2hsiqsrMOF_%2Fcasestudies-crane-productarch-tabsbackdrop-mobile.png"
)
//@4
class DownloadTask(var activity: Activity):AsyncTask(){
private var mCount = 0
val TASK_TAG = "FileDownloadActivity"
override fun onPreExecute() {
super.onPreExecute()
//@5
activity.progress_bar.visibility = View.VISIBLE
activity.progress_bar.progress = 0
}
override fun doInBackground(vararg urls: String?): Void? {
Log.d(TASK_TAG,"doInBackground")
for(index in urls.indices){
//11
Log.i("count",index.toString())
//@6
var bitmap = downloadFile(urls[index])
//@7
publishProgress(bitmap)
}
return null
}
//@8
override fun onProgressUpdate(vararg values: Bitmap?) {
super.onProgressUpdate(*values)
Log.d(TASK_TAG,"onProgressUpdate")
if(activity!=null){
activity.progress_bar.progress = ++mCount
var imageView = ImageView(activity)
imageView.setImageBitmap(values[0])
activity.layout_images.addView(imageView)
}
}
override fun onPostExecute(result: Void?) {
super.onPostExecute(result)
Log.d(TASK_TAG,"onPostExecute")
//@9
activity.progress_bar.visibility = View.GONE
}
override fun onCancelled() {
super.onCancelled()
Log.d(TASK_TAG,"onCancelled")
//@10
activity.progress_bar.visibility = View.GONE
}
private fun downloadFile(url: String?): Bitmap? {
var bitmap: Bitmap? = null
try {
bitmap = BitmapFactory.decodeStream(URL(url).content as InputStream)
} catch (e: MalformedURLException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
}
return bitmap
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_file_download)
progress_bar.max = DOWNLOAD_URLS.size
mFileDownLoaderTask = DownloadTask(this)
//@2
mFileDownLoaderTask.execute(*DOWNLOAD_URLS)
}
override fun onDestroy() {
super.onDestroy()
//@3
mFileDownLoaderTask.cancel(true)
}
}
@1-- 图片的URL
@2-- 将url传递给doInBackground。
@3-- 当活动被销毁时,AsyncTask和它的引用被取消
@4-- 创建一个AsyncTask:将一个字符串对象数组传递给doInBackgroud,并在后台执行期间返回Bitmap对象。后台线程没 有将结果传递给UI线程,因此最后一个参数被声明为Void。
@5-- 在后台任务执行之前显示进度条。
@6-- 通过网络下载图像并将其分配给Bitmap
@7-- 将图像发送到UI线程。
@8-- 通过更新进度条和显示新图像来响应后台线程发送的进度更新。
@9 @10-- 删除进度条。
@11-- 这里我们打印执行的url的索引来判断是否取消成功
如果您点击FILEDOWNLOADACTIVITY按钮,开始下载图片,在下载任务还没完成时,返回到MainActvity,打印出的结果如下图所示:
看到这,很显然,我们以为.cancel(true)就会结束掉我们开启的正在执行的异步任务,但是实际上并没有结束掉我们想要结束的异步任务。原因在上一节已经说过了。
所以要想正确的结束掉异步任务,还记得最强取消策略的,您应该添加如下的@12、@13处所示的代码:
override fun doInBackground(vararg urls: String?): Void? {
Log.d(TASK_TAG,"doInBackground")
for(index in urls.indices){
//@12
try{
for(index in urls.indices){
//@13
if(!isCancelled){
Log.i("count",index.toString())
val bitmap = downloadFile(urls[index])
publishProgress(bitmap)
}
}
}catch (e:InterruptedException){
//do nothing
Log.i("count","exception")
}
}
return null
}