AsyncTask(一)AsyncTask的使用

来源:互联网 发布:帝国cms影视大全源码 编辑:程序博客网 时间:2024/05/29 03:23

前言:

虽然现在RxJava非常流行,但是还是觉得应该分析一下Android的原生异步线程实现。

打算用2篇文章来过一下这个知识点。其中第一部分主要为使用例子,第二部分从源码的角度来验证那样使用的原因。


第一篇:

第二篇

AsyncTask。顾名思义,异步的任务。

android.os.AsyncTask是一个抽象类,其类定义如下:

public abstract class AsyncTask<Params, Progress, Result>
其中Params对应传入参数,Progress对应执行进度参数,Result对应执行结果参数。需要一一对应。

doInBackground的参数和Params一致,返回结果和Result一致;

onProgressUpdate的参数和Progress一致;

onPostExecute的参数和Result一致。

一个例子如下:

private class AsyncTaskDemo extends AsyncTask<HashMap<String,String>, Integer, String> {        @Override        protected String doInBackground(HashMap<String,String>... params) {            return null;        }        @Override        protected void onProgressUpdate(Integer...progress){        }        @Override        protected void onPostExecute(String result) {            super.onPostExecute(result);        }    }

它有 3个启动入口:
第一个用于串行执行;
第二个用于自定义执行,可以传入AsyncTask.THREAD_POOL_EXECUTOR进行并行计算
第三用于执行制定Runnable。
它提供了5个生命周期方法:
其顺序为:
 onPreExecute -> doInBackGround -> onPostExecute
 publishProgress(需要手动调用,也就是说进度是自己计算的) -> onProgressUpdate
 onCacelled
 
其中,doInBackGround是个抽象方法,是AsyncTask实现类中必须要实现的。
此外,doInBackGround不在UIThread中执行,不能直接操作UI。
串行执行结果:
11-03 15:47:11.285 14236-14236/? D/thm: AsyncTask1:onPreExecute11-03 15:47:11.285 14236-14236/? D/thm: AsyncTask2:onPreExecute11-03 15:47:11.285 14236-14236/? D/thm: AsyncTask3:onPreExecute11-03 15:47:11.285 14236-14236/? D/thm: AsyncTask4:onPreExecute11-03 15:47:11.310 14236-14236/? D/thm: AsyncTask1:2011-03 15:47:11.335 14236-14236/? D/thm: AsyncTask1:4011-03 15:47:11.360 14236-14236/? D/thm: AsyncTask1:6011-03 15:47:11.385 14236-14236/? D/thm: AsyncTask1:8011-03 15:47:11.415 14236-14236/? D/thm: AsyncTask1:10011-03 15:47:11.415 14236-14236/? D/thm: AsyncTask1: is finished11-03 15:47:11.445 14236-14236/? D/thm: AsyncTask2:2011-03 15:47:11.470 14236-14236/? D/thm: AsyncTask2:4011-03 15:47:11.495 14236-14236/? D/thm: AsyncTask2:6011-03 15:47:11.525 14236-14236/? D/thm: AsyncTask2:8011-03 15:47:11.550 14236-14236/? D/thm: AsyncTask2:10011-03 15:47:11.550 14236-14236/? D/thm: AsyncTask2: is finished11-03 15:47:11.575 14236-14236/? D/thm: AsyncTask3:2011-03 15:47:11.605 14236-14236/? D/thm: AsyncTask3:4011-03 15:47:11.630 14236-14236/? D/thm: AsyncTask3:6011-03 15:47:11.660 14236-14236/? D/thm: AsyncTask3:8011-03 15:47:11.685 14236-14236/? D/thm: AsyncTask3:10011-03 15:47:11.685 14236-14236/? D/thm: AsyncTask3: is finished11-03 15:47:11.720 14236-14236/? D/thm: AsyncTask4:2011-03 15:47:11.745 14236-14236/? D/thm: AsyncTask4:4011-03 15:47:11.770 14236-14236/? D/thm: AsyncTask4:6011-03 15:47:11.800 14236-14236/? D/thm: AsyncTask4:8011-03 15:47:11.825 14236-14236/? D/thm: AsyncTask4:10011-03 15:47:11.825 14236-14236/? D/thm: AsyncTask4: is finished

并行执行结果:
11-03 15:47:19.620 14236-14236/? D/thm: AsyncTask1:onPreExecute11-03 15:47:19.625 14236-14236/? D/thm: AsyncTask2:onPreExecute11-03 15:47:19.625 14236-14236/? D/thm: AsyncTask3:onPreExecute11-03 15:47:19.635 14236-14236/? D/thm: AsyncTask4:onPreExecute11-03 15:47:19.655 14236-14236/? D/thm: AsyncTask2:2011-03 15:47:19.655 14236-14236/? D/thm: AsyncTask1:2011-03 15:47:19.660 14236-14236/? D/thm: AsyncTask3:2011-03 15:47:19.680 14236-14236/? D/thm: AsyncTask2:4011-03 15:47:19.680 14236-14236/? D/thm: AsyncTask1:4011-03 15:47:19.680 14236-14236/? D/thm: AsyncTask4:2011-03 15:47:19.685 14236-14236/? D/thm: AsyncTask3:4011-03 15:47:19.705 14236-14236/? D/thm: AsyncTask2:6011-03 15:47:19.705 14236-14236/? D/thm: AsyncTask1:6011-03 15:47:19.710 14236-14236/? D/thm: AsyncTask3:6011-03 15:47:19.715 14236-14236/? D/thm: AsyncTask4:4011-03 15:47:19.730 14236-14236/? D/thm: AsyncTask2:8011-03 15:47:19.735 14236-14236/? D/thm: AsyncTask1:8011-03 15:47:19.735 14236-14236/? D/thm: AsyncTask3:8011-03 15:47:19.740 14236-14236/? D/thm: AsyncTask4:6011-03 15:47:19.755 14236-14236/? D/thm: AsyncTask2:10011-03 15:47:19.755 14236-14236/? D/thm: AsyncTask2: is finished11-03 15:47:19.760 14236-14236/? D/thm: AsyncTask1:10011-03 15:47:19.760 14236-14236/? D/thm: AsyncTask1: is finished11-03 15:47:19.765 14236-14236/? D/thm: AsyncTask4:8011-03 15:47:19.765 14236-14236/? D/thm: AsyncTask3:10011-03 15:47:19.765 14236-14236/? D/thm: AsyncTask3: is finished11-03 15:47:19.790 14236-14236/? D/thm: AsyncTask4:10011-03 15:47:19.790 14236-14236/? D/thm: AsyncTask4: is finished
看时间,显然并行执行消耗的总时间远低于串行执行。
但并行执行有其不安全性,即之前的数据可能会覆盖后面的数据。
比如以下MyAsyncTask2 ,同时启动4个Task:
 static  int i =0;    private class MyAsyncTask2 extends AsyncTask<Void, Integer, Void> {        private String mName = "AsyncTask";        public MyAsyncTask2(int id) {            super();            mName += id;        }        @Override        protected void onPreExecute() {            Log.d("thm",mName+":onPreExecute");        }        @Override        protected Void doInBackground(Void... voids) {            for(;i<100;){                try {                    Thread.sleep(25);                } catch (Exception e) {                    e.printStackTrace();                }//                Log.d("thm",mName+":"+i);                publishProgress(++i);            }            return null;        }        @Override        protected void onProgressUpdate(Integer...progress){            Log.d("thm", mName+":"+progress[0]);        }        @Override        protected void onPostExecute(Void aVoid) {            super.onPostExecute(aVoid);            Log.d("thm", mName+":"+" is finished");        }    }
运行结果如下,显然,这里执行了103次,而我们的预期目标是100次:
11-03 16:21:09.499 31561-31561/? D/thm: AsyncTask1:onPreExecute11-03 16:21:09.504 31561-31561/? D/thm: AsyncTask2:onPreExecute11-03 16:21:09.509 31561-31561/? D/thm: AsyncTask3:onPreExecute11-03 16:21:09.509 31561-31561/? D/thm: AsyncTask4:onPreExecute11-03 16:21:09.534 31561-31561/? D/thm: AsyncTask1:111-03 16:21:09.534 31561-31561/? D/thm: AsyncTask2:211-03 16:21:09.534 31561-31561/? D/thm: AsyncTask3:311-03 16:21:09.534 31561-31561/? D/thm: AsyncTask4:411-03 16:21:09.559 31561-31561/? D/thm: AsyncTask2:511-03 16:21:09.559 31561-31561/? D/thm: AsyncTask1:611-03 16:21:09.559 31561-31561/? D/thm: AsyncTask3:711-03 16:21:09.564 31561-31561/? D/thm: AsyncTask4:811-03 16:21:09.584 31561-31561/? D/thm: AsyncTask1:1011-03 16:21:09.584 31561-31561/? D/thm: AsyncTask3:1111-03 16:21:09.584 31561-31561/? D/thm: AsyncTask2:911-03 16:21:09.589 31561-31561/? D/thm: AsyncTask4:1211-03 16:21:09.609 31561-31561/? D/thm: AsyncTask1:1311-03 16:21:09.609 31561-31561/? D/thm: AsyncTask3:1411-03 16:21:09.609 31561-31561/? D/thm: AsyncTask2:1511-03 16:21:09.614 31561-31561/? D/thm: AsyncTask4:1611-03 16:21:09.634 31561-31561/? D/thm: AsyncTask1:1711-03 16:21:09.634 31561-31561/? D/thm: AsyncTask3:1811-03 16:21:09.634 31561-31561/? D/thm: AsyncTask2:1911-03 16:21:09.639 31561-31561/? D/thm: AsyncTask4:2011-03 16:21:09.659 31561-31561/? D/thm: AsyncTask1:2111-03 16:21:09.659 31561-31561/? D/thm: AsyncTask3:2211-03 16:21:09.659 31561-31561/? D/thm: AsyncTask2:2311-03 16:21:09.664 31561-31561/? D/thm: AsyncTask4:2411-03 16:21:09.684 31561-31561/? D/thm: AsyncTask1:2511-03 16:21:09.684 31561-31561/? D/thm: AsyncTask3:2611-03 16:21:09.684 31561-31561/? D/thm: AsyncTask2:2711-03 16:21:09.689 31561-31561/? D/thm: AsyncTask4:2811-03 16:21:09.709 31561-31561/? D/thm: AsyncTask3:3011-03 16:21:09.709 31561-31561/? D/thm: AsyncTask1:2911-03 16:21:09.709 31561-31561/? D/thm: AsyncTask2:3111-03 16:21:09.714 31561-31561/? D/thm: AsyncTask4:3211-03 16:21:09.734 31561-31561/? D/thm: AsyncTask1:3311-03 16:21:09.734 31561-31561/? D/thm: AsyncTask3:3511-03 16:21:09.734 31561-31561/? D/thm: AsyncTask2:3411-03 16:21:09.739 31561-31561/? D/thm: AsyncTask4:3611-03 16:21:09.759 31561-31561/? D/thm: AsyncTask1:3711-03 16:21:09.759 31561-31561/? D/thm: AsyncTask3:3811-03 16:21:09.764 31561-31561/? D/thm: AsyncTask2:3911-03 16:21:09.764 31561-31561/? D/thm: AsyncTask4:4011-03 16:21:09.789 31561-31561/? D/thm: AsyncTask3:4111-03 16:21:09.789 31561-31561/? D/thm: AsyncTask1:4211-03 16:21:09.789 31561-31561/? D/thm: AsyncTask4:4411-03 16:21:09.794 31561-31561/? D/thm: AsyncTask2:4311-03 16:21:09.814 31561-31561/? D/thm: AsyncTask3:4511-03 16:21:09.814 31561-31561/? D/thm: AsyncTask1:4611-03 16:21:09.814 31561-31561/? D/thm: AsyncTask4:4711-03 16:21:09.819 31561-31561/? D/thm: AsyncTask2:4811-03 16:21:09.839 31561-31561/? D/thm: AsyncTask1:4911-03 16:21:09.839 31561-31561/? D/thm: AsyncTask3:5011-03 16:21:09.844 31561-31561/? D/thm: AsyncTask2:5211-03 16:21:09.844 31561-31561/? D/thm: AsyncTask4:5111-03 16:21:09.864 31561-31561/? D/thm: AsyncTask1:5311-03 16:21:09.864 31561-31561/? D/thm: AsyncTask3:5411-03 16:21:09.869 31561-31561/? D/thm: AsyncTask2:5511-03 16:21:09.869 31561-31561/? D/thm: AsyncTask4:5611-03 16:21:09.894 31561-31561/? D/thm: AsyncTask1:5711-03 16:21:09.894 31561-31561/? D/thm: AsyncTask2:5811-03 16:21:09.899 31561-31561/? D/thm: AsyncTask3:5911-03 16:21:09.899 31561-31561/? D/thm: AsyncTask4:6011-03 16:21:09.924 31561-31561/? D/thm: AsyncTask1:6111-03 16:21:09.924 31561-31561/? D/thm: AsyncTask2:6211-03 16:21:09.924 31561-31561/? D/thm: AsyncTask3:6411-03 16:21:09.924 31561-31561/? D/thm: AsyncTask4:6311-03 16:21:09.949 31561-31561/? D/thm: AsyncTask1:6511-03 16:21:09.949 31561-31561/? D/thm: AsyncTask2:6611-03 16:21:09.949 31561-31561/? D/thm: AsyncTask3:6711-03 16:21:09.949 31561-31561/? D/thm: AsyncTask4:6811-03 16:21:09.974 31561-31561/? D/thm: AsyncTask1:6911-03 16:21:09.974 31561-31561/? D/thm: AsyncTask3:7011-03 16:21:09.974 31561-31561/? D/thm: AsyncTask4:7011-03 16:21:09.979 31561-31561/? D/thm: AsyncTask2:7111-03 16:21:09.999 31561-31561/? D/thm: AsyncTask1:7211-03 16:21:10.004 31561-31561/? D/thm: AsyncTask4:7411-03 16:21:10.004 31561-31561/? D/thm: AsyncTask3:7311-03 16:21:10.009 31561-31561/? D/thm: AsyncTask2:7511-03 16:21:10.024 31561-31561/? D/thm: AsyncTask1:7611-03 16:21:10.029 31561-31561/? D/thm: AsyncTask4:7711-03 16:21:10.039 31561-31561/? D/thm: AsyncTask3:7911-03 16:21:10.044 31561-31561/? D/thm: AsyncTask2:7811-03 16:21:10.049 31561-31561/? D/thm: AsyncTask1:8011-03 16:21:10.054 31561-31561/? D/thm: AsyncTask4:8111-03 16:21:10.064 31561-31561/? D/thm: AsyncTask3:8211-03 16:21:10.069 31561-31561/? D/thm: AsyncTask2:8311-03 16:21:10.079 31561-31561/? D/thm: AsyncTask1:8411-03 16:21:10.079 31561-31561/? D/thm: AsyncTask4:8511-03 16:21:10.094 31561-31561/? D/thm: AsyncTask3:8611-03 16:21:10.104 31561-31561/? D/thm: AsyncTask2:8711-03 16:21:10.114 31561-31561/? D/thm: AsyncTask4:8811-03 16:21:10.114 31561-31561/? D/thm: AsyncTask1:8911-03 16:21:10.119 31561-31561/? D/thm: AsyncTask3:9011-03 16:21:10.129 31561-31561/? D/thm: AsyncTask2:9111-03 16:21:10.139 31561-31561/? D/thm: AsyncTask4:9211-03 16:21:10.139 31561-31561/? D/thm: AsyncTask1:9311-03 16:21:10.144 31561-31561/? D/thm: AsyncTask3:9411-03 16:21:10.154 31561-31561/? D/thm: AsyncTask2:9511-03 16:21:10.169 31561-31561/? D/thm: AsyncTask3:9711-03 16:21:10.169 31561-31561/? D/thm: AsyncTask4:9611-03 16:21:10.169 31561-31561/? D/thm: AsyncTask1:9811-03 16:21:10.179 31561-31561/? D/thm: AsyncTask2:9911-03 16:21:10.219 31561-31561/? D/thm: AsyncTask2:10011-03 16:21:10.219 31561-31561/? D/thm: AsyncTask2: is finished11-03 16:21:10.219 31561-31561/? D/thm: AsyncTask1:10111-03 16:21:10.219 31561-31561/? D/thm: AsyncTask1: is finished11-03 16:21:10.219 31561-31561/? D/thm: AsyncTask4:10211-03 16:21:10.219 31561-31561/? D/thm: AsyncTask4: is finished11-03 16:21:10.219 31561-31561/? D/thm: AsyncTask3:10311-03 16:21:10.219 31561-31561/? D/thm: AsyncTask3: is finished
两种execute方式各有所长,具体使用那种还需依据实际情况来做。
当然现在的主流已经不再是AsyncTask了,比如现在很火爆的异步框架RxJava,采用观察者+异步的方式,且书写起来十分简便。
除去上面所提到的安全性,使用AsyncTask还需注意下面这些:
1.生命周期
AsyncTask不会随着Activity的销毁而销毁,它会一直执行直到doInBackground()方法执行完毕,然后执行onPostExecute/onCancelled。
如果我们的Activity销毁之前,没有取消AsyncTask,这有可能让我们的AsyncTask崩溃(crash)。
因为它想要处理的view已经不在了。所以,我们总是必须确保在销毁活动之前取消任务。
2.内存泄漏
如果AsyncTask被声明为Activity的非静态的内部类,那么AsyncTask会保留一个对Activity的引用。
如果Activity已经被销毁,AsyncTask的后台线程还在执行,它将继续在内存里保留这个引用,导致Activity无法被回收,引起内存泄漏。
3.结果丢失
屏幕旋转或Activity在后台被系统杀掉等情况会导致Activity的重新创建,之前运行的AsyncTask会持有一个之前Activity的引用,
这个引用已经无效,这时调用onPostExecute()再去更新界面将不再生效。
总之,如果在onPostExecute()中执行UI操作的话,必须在Activity的onDestroy()中做处理。
4.AsyncTask的类必须在UI线程加载(从4.1开始系统会帮我们自动完成),AsyncTask对象必须在UI线程创建
5.execute方法必须在UI线程调用
6.不要在你的程序中去直接调用onPreExecute(), onPostExecute, doInBackground, onProgressUpdate方法
7.一个AsyncTask对象只能执行一次,即只能调用一次execute方法,否则会报运行时异常
8.AsyncTask不是被设计为处理耗时操作的,耗时上限为几秒钟,如果要做长耗时操作,强烈建议你使用Executor,ThreadPoolExecutor以及FutureTask
官方文档如下:
  • The AsyncTask class must be loaded on the UI thread. This is done automatically as of JELLY_BEAN.
  • The task instance must be created on the UI thread.
  • execute(Params...) must be invoked on the UI thread.
  • Do not call onPreExecute()onPostExecute(Result)doInBackground(Params...)onProgressUpdate(Progress...) manually.
  • The task can be executed only once (an exception will be thrown if a second execution is attempted.)
测试代码比较少,这里直接附上:
package tian.hangmin.com.asyntaskdemo;import android.app.Activity;import android.content.Context;import android.os.AsyncTask;import android.os.Bundle;import android.util.Log;import android.view.View;import java.util.ArrayList;import java.util.HashMap;import java.util.Map;/** * Created by tianhm on 2016/11/3. */public class AsynTaskActivity extends Activity {    @Override    protected void onCreate(Bundle onSavedInstanceState) {        super.onCreate(onSavedInstanceState);        setContentView(R.layout.activity_asyntask_demo);        findViewById(R.id.button1).setOnClickListener(listener);        findViewById(R.id.button2).setOnClickListener(listener);    }    View.OnClickListener listener = new View.OnClickListener() {        @Override        public void onClick(View v) {            start(v.getId());        }    };    protected void start(int id){        if(id == R.id.button1){            new MyAsyncTask(1).execute();            new MyAsyncTask(2).execute();            new MyAsyncTask(3).execute();            new MyAsyncTask(4).execute();        } else if(id == R.id.button2){            new MyAsyncTask(1).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR , new Void[1]);            new MyAsyncTask(2).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR , new Void[1]);            new MyAsyncTask(3).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR , new Void[1]);            new MyAsyncTask(4).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR , new Void[1]);        } else if( i ==  R.id.button3){            new MyAsyncTask2(1).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR , new Void[1]);            new MyAsyncTask2(2).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR , new Void[1]);            new MyAsyncTask2(3).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR , new Void[1]);            new MyAsyncTask2(4).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR , new Void[1]);        }    }    private class MyAsyncTask extends AsyncTask<Void, Integer, Void> {        private String mName = "AsyncTask";        public MyAsyncTask(int id) {            super();            mName += id;        }        @Override        protected void onPreExecute() {            Log.d("thm",mName+":onPreExecute");        }        @Override        protected Void doInBackground(Void... voids) {            for(int i =0;i<100;){                try {                    Thread.sleep(25);                } catch (Exception e) {                    e.printStackTrace();                }//                Log.d("thm",mName+":"+i);                publishProgress(++i*100/5);            }            return null;        }        @Override        protected void onProgressUpdate(Integer...progress){            Log.d("thm", mName+":"+progress[0]);        }        @Override        protected void onPostExecute(Void aVoid) {            super.onPostExecute(aVoid);            Log.d("thm", mName+":"+" is finished");        }    }    static  int i =0;    private class MyAsyncTask2 extends AsyncTask<Void, Integer, Void> {        private String mName = "AsyncTask";        public MyAsyncTask2(int id) {            super();            mName += id;        }        @Override        protected void onPreExecute() {            Log.d("thm",mName+":onPreExecute");        }        @Override        protected Void doInBackground(Void... voids) {            for(;i<100;){                try {                    Thread.sleep(25);                } catch (Exception e) {                    e.printStackTrace();                }//                Log.d("thm",mName+":"+i);                publishProgress(++i);            }            return null;        }        @Override        protected void onProgressUpdate(Integer...progress){            Log.d("thm", mName+":"+progress[0]);        }        @Override        protected void onPostExecute(Void aVoid) {            super.onPostExecute(aVoid);            Log.d("thm", mName+":"+" is finished");        }    }}



xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical">    <Button        android:id="@+id/button1"        android:layout_marginTop="8dp"        android:text="串行开始"        android:layout_gravity="center"        android:layout_width="wrap_content"        android:layout_height="wrap_content" /> <Button     android:id="@+id/button2"     android:layout_marginTop="8dp"     android:text="并行开始"     android:layout_gravity="center"     android:layout_width="wrap_content"     android:layout_height="wrap_content" /> <Button     android:id="@+id/button3"     android:layout_marginTop="8dp"     android:text="并行不安全"     android:layout_gravity="center"     android:layout_width="wrap_content"     android:layout_height="wrap_content" /></LinearLayout>


                                             
0 0
原创粉丝点击