AsyncTask使用与源码解析
Posted 单灿灿
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AsyncTask使用与源码解析相关的知识,希望对你有一定的参考价值。
安卓更新UI的方式大致有四种:
- 使用Handler消息传递机制;
- 使用AsyncTask异步任务;
- 使用runOnUiThread(action)方法;
- 使用Handler的post(Runnabel r)方法;
其中AsyncTask和Handler是两种异步方式。我有一篇文章专门讲解Android异步消息处理机制 Handler、Looper、Message这篇文章,从源码讲解,很适合看。
今天我们着重通过示例来讲解AsyncTask。
AsyncTask是什么?作用是什么?
AsyncTask可以理解为异步任务执行者,主要用来执行一个较为耗时的异步任务,然后更新UI。
AsyncTask的调用步骤
AsyncTask是抽象类,定义了三种泛型类型 Params,Progress,Result。
1) Params 启动任务执行的输入参数,比如HTTP请求的URL。调用execute()方法时传入的参数类型和doInBackgound()的参数类型
2) Progress 后台任务执行的百分比。更新进度时传递的参数类型,即publishProgress()和onProgressUpdate()的参数类型
3) Result 后台执行任务最终返回的结果,比如String。即doInBackground()的返回值类型。
使用步骤:
首先实例化AsyncTask
接着实现AsyncTask中定义的下面一个或几个方法
onPreExecute(),该方法将在执行实际的后台操作前被UI thread调用。可以在该方法中做一些准备工作,如在界面上显示一个进度条。
doInBackground(Params…),将在onPreExecute 方法执行后马上执行,该方法运行在后台线程中。这里将主要负责执行那些很耗时的后台计算工作。可以调用 publishProgress方法来更新实时的任务进度。该方法是抽象方法,子类必须实现。
onProgressUpdate(Progress…),在publishProgress方法被调用后,UI thread将调用这个方法从而在界面上展示任务的进展情况,例如通过一个进度条进行展示。
onPostExecute(Result),在doInBackground 执行完成后,onPostExecute 方法将被UI thread调用,后台的计算结果将通过该方法传递到UI thread.
下面通过代码示例来讲解。
Activity代码(里面包含全部内容,文末也有github地址):
public class AsyncTaskActivity extends AppCompatActivity
private List<TextView> mTextViewList;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_async_task);
mTextViewList = new ArrayList<>();
mTextViewList.add((TextView) findViewById(R.id.asyntask_one));
mTextViewList.add((TextView) findViewById(R.id.asyntask_two));
mTextViewList.add((TextView) findViewById(R.id.asyntask_three));
mTextViewList.add((TextView) findViewById(R.id.asyntask_four));
mTextViewList.add((TextView) findViewById(R.id.asyntask_five));
mTextViewList.add((TextView) findViewById(R.id.asyntask_six));
new MyAsyncTask(mTextViewList.get(0), 0).execute();
new MyAsyncTask(mTextViewList.get(1), 1).execute();
new MyAsyncTask(mTextViewList.get(2), 2).execute();
new MyAsyncTask(mTextViewList.get(3), 3).execute();
new MyAsyncTask(mTextViewList.get(4), 4).execute();
new MyAsyncTask(mTextViewList.get(5), 5).execute();
private class MyAsyncTask extends AsyncTask<Void, Integer, String> //here to shengshi use void
private TextView mTextView;
private int id;
/**
* 生成该类的对象,并调用execute方法之后
* 首先执行的是onProExecute方法
* 其次执行doInBackgroup方法
*/
public MyAsyncTask(TextView textView, int id)
super();
mTextView = textView;
this.id = id;
//运行在UI线程当中,并且运行在UI线程,可以对UI进行设置
@Override
protected void onPreExecute()
mTextView.setText("task " + id + " 即将开始执行异步线程");
@Override
protected String doInBackground(Void... params)
NetOperator netOperator = new NetOperator();
int i = 0;
for (i = 0; i <= 2000; i += 100)
netOperator.operator();
publishProgress(i / 200);//这是更新的进度
return id + " 的图片下载完成";//返回的是最后的String结果
//在doInBackground方法当中,,每次调用publishProgress方法都会触发onProgressUpdate执行
@Override
protected void onProgressUpdate(Integer... values)
mTextView.setText("task " + id + " 异步操作执行到 " + values[0] + " 进度");
//运行在UI线程当中,并且运行在UI线程,可以对UI进行设置
@Override
protected void onPostExecute(String s)
mTextView.setText("task " + id + " 异步操作执行结束 " + s);
//模拟加载环境,做一个耗时操作
public class NetOperator
public void operator()
try
//休眠0.01秒
Thread.sleep(10);
catch (InterruptedException e)
// TODO Auto-generated catch block
e.printStackTrace();
通过观察,我们看出了通过execute来启动AsyncTask的话,他是串行执行的。
下面改变一下执行方法executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
从上面我们可以看出,AsyncTask即可以串行执行,又可以并行执行,关键是看你怎么启动它
进入源码看一下他的执行
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params)
return executeOnExecutor(sDefaultExecutor, params);
@MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params)
if (mStatus != Status.PENDING)
switch (mStatus)
case RUNNING:
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
case FINISHED:
throw new IllegalStateException("Cannot execute task:"
+ " the task has already been executed "
+ "(a task can be executed only once)");
mStatus = Status.RUNNING;
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
可以看出来使用execute方法最终还是执行executeOnExecutor方法,只不过是里面传的参数不一样。
我们来分析一下sDefaultExecutor,THREAD_POOL_EXECUTOR这两个参数,为何导致执行结果不同。
THREAD_POOL_EXECUTOR:
/**
* An @link Executor that can be used to execute tasks in parallel.
* 可以用来并行执行任务的
*/
public static final Executor THREAD_POOL_EXECUTOR;
static
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
sPoolWorkQueue, sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;//THREAD_POOL_EXECUTOR就是一个线程池
看一下其中相关的参数:
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));//CORE_POOL_SIZE是核心线程数量,从2和(CPU核心-1与4中的最小值)取最大值
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;//最大线程数量
private static final int KEEP_ALIVE_SECONDS = 30;//保活时间为30s
private static final ThreadFactory sThreadFactory = new ThreadFactory()
//线程工厂,生产线程
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable r)
return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
;
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);//线程池的任务队列中可以同时有128个任务等待执行
我们现回头看executeOnExecutor方法,传入的是THREAD_POOL_EXECUTOR线程池,exec.execute方法中调用的就是THREAD_POOL_EXECUTOR的execute方法,任务就会在这个线程池中运行,调用这个方法,至少会有两个任务一起执行。
接着我们来看sDefaultExecutor
每天都在加班,太累了,明天接着分析,不好意思。
以上是关于AsyncTask使用与源码解析的主要内容,如果未能解决你的问题,请参考以下文章