Android之AsyncTask
1.AsyncTask从引用的包(package android.os)可以看出,它是Android给我们提供的一个处理异步任务的类.通过此类,可以实现异步处理最后完成UI更新.
2.对于Android UI更新,只能在主线程进程更新,此原因已经在前面(Android的消息机制Handler)介绍,所以剩下只能通过子线程或者异步进行更新.对于子线程进行更新,前面已经介绍,此处只介绍异步方法进行的更新.
3.对于为什么用异步更新,以及是否会降级ui性能,那么可以肯定的说如果不用异步处理一些耗时操作,新建立一个线程同样也会消耗资源,同样也会耗时.而且对于子线程必须做到和ui同步,即ui销毁前要对线程进行处理,否则很容易出现空指针或者ui已经结束子线程还在跑的情况.而对于异步处理是不会出现此情况的.下面会针对说明.
4.AsyncTask介绍:
(1)public abstract class AsyncTask<Params, Progress, Result>
Params:起动任务即异步处理的参数doInBackground(Params... params)
Progress:后台任务执行中返回进度值的类型,onProgressUpdate(Progress... values)
Result:后台任务执行完成后返回结果的类型,onPostExecute(Result result)
(2)一些方法说明:
onPreExecute:执行后台之前,需要的一些初始化,此方法隶属主线程
doInBackground:异步任务处理处,耗时操作在此方法完成,此方法的执行在子线程完成.
onPostExecute:当doInBackground方法完成后,系统自动调用此方法,且将doInBackground方法返回的值传入此方法进行ui的更新,此方法隶属主线程.
onProgressUpdate:在doInBackground方法中调用publishProgress方法更新任务执行进度后,将回调用此方法,通过此方法可以知道任务进展.
publishProgress:此方法是发布进度的时候使用,当异步方法doInBackground调用此方法后,onProgressUpdate会被回调.
(3)publishProgress此方法的工作源码可以说明异步处理为什么是安全的:
@WorkerThread protected final void publishProgress(Progress... values) { if (!isCancelled()) { getHandler().obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult<Progress>(this, values)).sendToTarget(); } } private static Handler getMainHandler() { synchronized (AsyncTask.class) { if (sHandler == null) { sHandler = new InternalHandler(Looper.getMainLooper()); } return sHandler; } } private static class InternalHandler extends Handler { public InternalHandler(Looper looper) { super(looper); } @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"}) @Override public void handleMessage(Message msg) { AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj; switch (msg.what) { case MESSAGE_POST_RESULT: // There is only one result result.mTask.finish(result.mData[0]);//执行的这个方法就是当前AsyncTask自身的finish()这个方法。而这正是说明了在正常执行完工作线程的doInBackground()之后再在主线程中执行finish() break; } } }
整个过程可以说明在更新进度的时候,会上对象锁(AsyncTask.class),在执行完异步后再在线程中执行finish方法,那么此时将不会有不界面销毁的时候组件还在work的情况.
5.下面通过demo演示一个典型的异步处理实力:加载图片。
package com.example.testactivityb; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; import android.os.AsyncTask; import android.os.Bundle; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.util.Log; import android.view.Menu; import android.view.View; import android.widget.ImageView; import android.widget.TextView; public class MainActivity extends Activity { private ImageView imageView ; private TextView textView; private static String URL = "http://pic1.sc.chinaz.com/files/pic/pic9/201808/zzpic13515.jpg"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); imageView = (ImageView) findViewById(R.id.image); textView = (TextView)findViewById(R.id.textView); textView.setText("hello world,after a moment,it will disapear"); Log.d(this.toString(), "onCreate main thread "); //通过调用execute方法开始处理异步任务.相当于线程中的start方法. new MyAsyncTask().execute(URL); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.activity_main, menu); return true; } class MyAsyncTask extends AsyncTask<String,Void,Bitmap> { //onPreExecute:异步处理前的操作,此方法依然在主线程中 @Override protected void onPreExecute() { super.onPreExecute(); Thread.dumpStack(); Log.d(this.toString(), "onPreExecute ..."); //此处将textView设置为可见,仅表示在此可以设置ui相关的操作 textView.setVisibility(View.VISIBLE); } //doInBackground:进行异步任务处理,另开了线程. @Override protected Bitmap doInBackground(String... params) { Log.d(this.toString(), "doInBackground ..."); //获取传进来的参数 String url = params[0]; Bitmap bitmap = null; URLConnection connection ; InputStream inputStream ; try { connection = new URL(url).openConnection();//url对象用openconnection()打开连接,获得URLConnection类对象,再用URLConnection类对象的connect()方法进行连接 inputStream = connection.getInputStream();//an input stream that reads from this open connection //为了更清楚的看到加载图片的等待操作,将子线程休眠下. Thread.sleep(4000); BufferedInputStream bis = new BufferedInputStream(inputStream); bitmap = BitmapFactory.decodeStream(bis);//通过decodeStream方法解析输入流 inputStream.close(); bis.close(); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } return bitmap; } //onPostExecute用于UI的更新.此方法的参数为doInBackground方法返回的值. @Override protected void onPostExecute(Bitmap bitmap) { super.onPostExecute(bitmap); Log.d(this.toString(), "onPostExecute ..."); //对UI进行操作,此时Bitmap是doInBackground处理后的结果. textView.setVisibility(View.GONE); imageView.setImageBitmap(bitmap); } } }
执行过程如下:
08-16 10:38:04.102 8437 8437 D AccessibilityManager: getInstance() new sInstance = android.view.accessibility.AccessibilityManager@a9d45fb, context = com.example.testactivityb.MainActivity@b6b7618, userId = 0 08-16 10:38:04.159 8437 8437 D com.example.testactivityb.MainActivity@b6b7618: onCreate main thread 08-16 10:38:04.161 8437 8437 D com.example.testactivityb.MainActivity$MyAsyncTask@7e9fcb7: onPreExecute ... 08-16 10:38:04.166 8437 8450 D com.example.testactivityb.MainActivity$MyAsyncTask@7e9fcb7: doInBackground ... 08-16 10:38:04.285 1475 1536 I ActivityManager: Displayed com.example.testactivityb/.MainActivity: +318ms 08-16 10:38:08.506 8437 8437 D com.example.testactivityb.MainActivity$MyAsyncTask@7e9fcb7: onPostExecute ...