AsyncTask异步任务类,比Handle更轻量级,更适合简单的异步操作。内部封装了Handle,在使用AsyncTask类进行刷新控件的刷新操作时,不用再额外创建声明Handle,可以直接使AsyncTask内部封装好的几个方法实现。
一、AsyncTask的实现
使用AsyncTask主要通过实现内部封装的onPreExecute(),doInBackGround(),onProgressSetUpdate(),onPostExecute()等几个方法来进行操作。通过调用.excute()方法开始执行
1、onPreExecute()
onPreExcute()会在后台任务开始之前执行,可以进行一些界面上的初始化操作。
2、doInBackground(Object o)
运行在AsyncTask内部开辟的子线程,一些耗时会阻塞UI的操作都应该放在这个方法内处理,如从网络读取数据、下载任务等,这里的Object o参数,我们可以通过AsyncTask的实例调用.excute(Object o)方法时传入。
3、onProgressSetUpdate()
运行在主线程,也就是UI线程,AsyncTask必须在UI线程声明创建。onProgressSetUpdate(Object o)方法主要是用来显示任务执行的进度,给用户直观的感受。Object o通过publishProgress(Object o)方法传入,因为耗时操作一般是在doInBackGround()方法中执行,所以一般会在doInBackGround()方法中调用pubilshProgress(Object o)传参只onProgressSetUpdate(),然后执行控件的刷新。
4、onPostExecute()
运行在主线程。doInBackground()会有一个返回值,这个返回值会作为参数传入onPostExecute()方法中,可以利用返回的数据进行一些UI操作,进行收尾工作。
二、AsyncTask泛型参数设置
AsyncTask如果不设置泛型参数,那么上面介绍的几个方法参数、返回值都默认为Object,在使用时都必须进行强转,个人感觉很繁琐。我们可以通过设置AsyncTask的泛型参数来解决这个问题。
AsyncTask有三个参数,分别是Params、Progress、Result
1、Params
execute(Params)传入的参数同时也是doInBackGround(Params)方法的参数。
2、Progress
onProgressUpdate(Progress)和publishProgress方法的参数
3、Result
onPostExecute(Result)方法的参数,也是doInBackground()方法的返回值
如果是使用匿名内部类,泛型参数则在声明的使用就需要设置、确定:
new AsyncTask<String, Void, Bitmap>() { @Override protected Bitmap doInBackground(String... params) { return null; } }.execute("");
如果是新建类继承自AsyncTask,在定义类时设置:
class DownLoadAsyncTask extends AsyncTask<String, Integer, Boolean>
三、AysncTask的具体使用
public class AsyncTaskDownLoadActivity extends AppCompatActivity { Button mDownLoadBtn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_async_task_down_load_layout); mDownLoadBtn = (Button) findViewById(R.id.start_download_btn); mDownLoadBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { DownLoadAsyncTask downLoadAsyncTask = new DownLoadAsyncTask(AsyncTaskDownLoadActivity.this); downLoadAsyncTask.execute("下载地址");//开始执行后台异步任务 } }); } class DownLoadAsyncTask extends AsyncTask<String, Integer, Boolean> { Context mContext; ProgressDialog mProgressDialog; public DownLoadAsyncTask(Context context) { mContext = context; mProgressDialog = new ProgressDialog(context);//实例化一个进度条对话框 } @Override protected void onPreExecute() { Log.v("AsyncTask", "onPreExecute()"); super.onPreExecute(); mProgressDialog.show();//初始化操作,显示对话框 } @Override protected void onProgressUpdate(Integer... values) { Log.v("AsyncTask", "onProgressUpdate()"); super.onProgressUpdate(values); mProgressDialog.setMessage("已经下载了" + values[0] + "%");//更新进度条对话框 } @Override protected Boolean doInBackground(String... params) { Log.v("AsyncTask", "doInBackground()"); int n = 1; while (n <= 10) { Random random = new Random(); n = n + random.nextInt(5); //设置随机数,模拟下载 SystemClock.sleep(500); publishProgress(n);//通过调用publishProgress()方法,使AysncTask回调onProgressUpdate(),并传入数据n } return true; } @Override protected void onPostExecute(Boolean aBoolean) { Log.v("AsyncTask", "onPostExecute()"); super.onPostExecute(aBoolean); mProgressDialog.dismiss();//取消进度条对话框显示 if (aBoolean) Toast.makeText(mContext, "下载完成", Toast.LENGTH_LONG).show(); else Toast.makeText(mContext, "下载失败", Toast.LENGTH_LONG).show(); } } }
为了方便理解几个方法的调用时机和执行顺序,可以打印日志,观察一下:
注:
(1)AsyncTask实例必须在UI线程中创建
(2)AsyncTask.execute()必须在主线程中执行
(3)AysnTask默认是单线程执行,内部有一个任务队列,从任务队列中取出任务执行完成过后才会开始执行下一个任务。
如果需要使用AysncTask执行多线程并发任务可以通过.executeOnExecutor()方法来启动