Android系统线程间通信方式之AsyncTask机制

比较好的博客:
https://blog.csdn.net/qq_30379689/article/details/53203556
https://blog.csdn.net/guolin_blog/article/details/11711405
AsyncTask是对Handler与线程池的封装,目的也是实现线程间的通信,子线程执行耗时操作发送消息到主线程更新UI,使用线程池的主要原因是避免不必要的创建及销毁线程的开销

1. AsyncTask使用示例

public class MainActivity extends Activity implements Button.OnClickListener {
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		Button bt_down = (Button) findViewById(R.id.button)
		bt_down.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				try {
					URL url = new URL("http://blog.csdn.net/");
					new MyAsyncTask().execute(url);	    //0. 创建继承AsyncTask的实例化对象执行execute开始执行异步任务
				} catch (MalformedURLException e) {
					e.printStackTrace();
				}
			}
		});
    }
    private class MyAsyncTask extends AsyncTask<URL, Integer, Long> {	//AsyncTask是一个抽象类,Handler是一个普通的类
		protected void onPreExecute() {				    //1. 主线程执行onPreExecute(执行异步任务前执行)
			//异步任务开启之前回调,在主线程中执行
			super.onPreExecute();
		}
		protected Long doInBackground(URL... urls) {	//2. 线程池执行doInBackground(执行异步任务)
			//执行异步任务,在线程池中执行
			long totalSize = 0;
			int i = 0;
			try {
				while (i < 100) {
					Thread.sleep(50);
					i = i + 5;
					publishProgress(i);
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			totalSize = totalSize + i;
			return totalSize;
		}
		protected void onProgressUpdate(Integer... progress) {	//3. 执行doInBackground的过程中执行publishProgress,主线程回调执行onProgressUpdate
			//当doInBackground中调用publishProgress时回调,在主线程中执行
			pb_progress.setProgress(progress[0]);
		}
		protected void onPostExecute(Long result) {				//4. 主线程执行onPostExecute(执行异步任务后执行)
			//在异步任务执行之后回调,在主线程中执行
			Toast.makeText(MainActivity.this, "下载完成,结果是" + result, Toast.LENGTH_SHORT).show();
		}
		protected void onCancelled() {							//5. 异步任务被取消时回调
			//在异步任务被取消时回调
			super.onCancelled();
		}
	}
}

AsyncTask用法总结:
a. 首先定义一个继承自AsyncTask的MyAsyncTask并复写onPreExecute、doInBackground、onPostExecute方法
b. 主线程实例化MyAsyncTask,并调用execute方法,会依次执行onPreExecute、doInBackground、onPostExecute方法
c. 其中onPreExecute和onPostExecute在主线程中执行,doInBackground在子线程中执行,doInBackground在执行publishProgress时会回调到主线程执行onProgressUpdate刷新UI

AsyncTask复写函数理解:
a. onPreExecute:用于界面的初始化操作,比如显示一个进度条对话框等
b. doInBackground:处理耗时任务,不可以进行UI操作的,如果需要更新UI元素,比如说反馈当前任务的执行进度,可以调用publishProgress来完成, publishProgress时会回调到主线程执行onProgressUpdate刷新UI
c. onPostExecute:doInBackground执行return返回之后调用,并将返回结果当作参数传入

2. 创建Handler的流程

AsyncTask中onPreExecute和onPostExecute在主线程中执行,doInBackground在子线程中执行,子线程切到主线程刷新UI是通过Handler实现的,创建Handler的流程如下所示:
在这里插入图片描述
创建的Handler保存在AsyncTask. mHandler

3. 调用onPreExecute的流程

3.1 分析new MyAsyncTask()

在这里插入图片描述
执行new MyAsyncTask()实例化一个AsyncTask,且AsyncTask.mFuture = new FutureTask(mWorker),且mWorker = new WorkerRunnable<Params, Result>(),在new WorkerRunnable()时会复写call()方法,执行call()时会执行doInBackground

3.2 分析new MyAsyncTask()

在这里插入图片描述
执行new MyAsyncTask().execute(url)时会直接调用AsyncTask的onPreExecute

4. 调用doInBackground的流程

4.1 调用doInBackground的流程

在3.2中可以看到执行完AsyncTask的onPreExecute之后会调用exec.execute(mFuture),其中exec = new SerialExecutor(),mFuture = new FutureTask(mWorker),mWorker = new WorkerRunnable(),且mWorker.mParams = new URL(“http://blog.csdn.net/”)
在这里插入图片描述
new Runnable()并复写run方法,进入子线程
在这里插入图片描述
在这里插入图片描述
在子线程中执行doInBackground

4.2 doInBackground调用publishProgress的流程

在这里插入图片描述
在这里插入图片描述
如果在doInBackground中调用了publishProgress,则使用Handler发送一个Message — MESSAGE_POST_RESULT,在主线程中处理这个消息时会调用onProgressUpdate

5. 调用onPostExecute的流程

在这里插入图片描述
4.1中执行完doInBackground之后会调用postResult,在postResult中使用Handler发送一个Message — MESSAGE_POST_RESULT,在主线程中处理这个消息时会调用onPostExecute,其中result为执行doInBackground的返回值

6. 总结

6.1 几个问题

a. 如果多次执行MyAsyncTask.execute()会重复执行异步任务吗?
不会,当第一次执行MyAsyncTask.execute()时MyAsyncTask.mStatus = Status.PENDING,不会抛出异常,且将状态改变为MyAsyncTask.mStatus = Status.RUNNING,当第二次执行MyAsyncTask.execute()时MyAsyncTask.mStatus != Status.PENDING,会抛出异常,不会往下执行,所以不会多次执行异步任务
b. MyAsyncTask.execute()时依次执行onPreExecute、doInBackground、onPostExecute方法,且onPreExecute和onPostExecute在主线程中执行,doInBackground在子线程中执行那么从onPreExecute到doInBackground是如何从主线程切换到子线程?从doInBackground到onPostExecute是如何从子线程切换到主线程?
执行MyAsyncTask.execute()时会在主线程执行onPreExecute,接着会使用SerialExecutor创建子线程,并在子线程中执行doInBackground,最终会执行postResult,使用Handler机制发送一个Message切换到主线程执行onProgressUpdate刷新UI

6.2 AsyncTask原理总结

执行MyAsyncTask.execute()时会在主线程执行onPreExecute,接着会使用SerialExecutor创建子线程,并在子线程中执行doInBackground,最终会执行postResult将doInBackground的执行结果result保存到AsyncTaskResult.mData中,将AsyncTaskResult保存到Message.obj中,使用Handler机制发送一个Message切换到主线程,取出result,判断当前异步任务是否已经被取消,如果已经被取消则会调用onCancelled()方法,如果没有被取消则会调用onPostExecute,当在执行doInBackground的过程中如果执行publishProgress时会使用Handler机制发送一个Message切换到主线程执行onProgressUpdate刷新UI

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值