Android AsyncTask 那些你不知道的事

来源:互联网 发布:maxwell软件下载 编辑:程序博客网 时间:2024/05/29 04:47
AsyncTask中的几个方法才能完成对任务的定制。经常需要去重写的方法有以下四个:


1. onPreExecute()

这个方法会在后台任务开始执行之间调用,用于进行一些界面上的初始化操作,比如显示一个进度条对话框等。

2. doInBackground(Params...)

这个方法中的所有代码都会在子线程中运行,我们应该在这里去处理所有的耗时任务。任务一旦完成就可以通过return语句来将任务的执行结果进行返回,如果AsyncTask的第三个泛型参数指定的是Void,就可以不返回任务执行结果。注意,在这个方法中是不可以进行UI操作的,如果需要更新UI元素,比如说反馈当前任务的执行进度,可以调用publishProgress(Progress...)方法来完成。

3. onProgressUpdate(Progress...)

当在后台任务中调用了publishProgress(Progress...)方法后,这个方法就很快会被调用,方法中携带的参数就是在后台任务中传递过来的。在这个方法中可以对UI进行操作,利用参数中的数值就可以对界面元素进行相应的更新。

4. onPostExecute(Result)

当后台任务执行完毕并通过return语句进行返回时,这个方法就很快会被调用。返回的数据会作为参数传递到此方法中,可以利用返回的数据来进行一些UI操作,比如说提醒任务执行的结果,以及关闭掉进度条对话框等。

execute = new AsyncTask<Void, Void, List<CacheContactForUI>>() {    @Override    protected void onPreExecute() {        isFinish.set(true);        loadingView.setVisibility(View.VISIBLE);        super.onPreExecute();    }    @Override    protected void onPostExecute(List<CacheContactForUI> result) {        CXLog.d(TAG, "result-size:" + result.size());        CacheContactItem contactItem = null;        for (CacheContactForUI foUiList : result) {            contactItem = foUiList.contactItem;            if(contactItem!=null){            ArrayList<ContactsAttrItem> phoneNumberMap = contactItem.getPhoneNumberMap();            ArrayList<ContactsAttrItem> templistPhoneNumber = new ArrayList<ContactsAttrItem>();            templistPhoneNumber.clear();            for (ContactsAttrItem itemNumber : phoneNumberMap) {                boolean added = true;                for (ContactsAttrItem temp : templistPhoneNumber) {                    if (itemNumber.getData().equals(temp.getData())) {                        templistPhoneNumber.remove(itemNumber);                        added = false;                    } else {                    }                }                if (added) {                    templistPhoneNumber.add(itemNumber);                    CXLog.e(TAG, "add");                }            }                CXLog.e(TAG, "addAll" );            phoneNumberMap.addAll(templistPhoneNumber);            contactItem.setPhoneNumberMap(templistPhoneNumber);                foUiList.setContactItem(contactItem);            }        }        mAdapter.setContactForUIsList(result);        mergeContactsList.setAdapter(mAdapter);        mAdapter.notifyDataSetChanged();        loadingView.setVisibility(View.GONE);        isFinish.set(false);    }    @Override    protected List<CacheContactForUI> doInBackground(Void... params) {        //isFinish.set(true);        //loadingView.setVisibility(View.VISIBLE);        return initData(itemId);    }    ;}.execute();

public AsyncTask() {    mWorker = new WorkerRunnable<Params, Result>() {        public Result call() throws Exception {            mTaskInvoked.set(true);            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);            //noinspection unchecked            Result result = doInBackground(mParams);            Binder.flushPendingCommands();            return postResult(result);        }    };    mFuture = new FutureTask<Result>(mWorker) {        @Override        protected void done() {            try {                postResultIfNotInvoked(get());            } catch (InterruptedException e) {                android.util.Log.w(LOG_TAG, e);            } catch (ExecutionException e) {                throw new RuntimeException("An error occurred while executing doInBackground()",                        e.getCause());            } catch (CancellationException e) {                postResultIfNotInvoked(null);            }        }    };}

3.0以前
  1. private static final int CORE_POOL_SIZE = 5;  
  2. private static final int MAXIMUM_POOL_SIZE = 128;  
  3. private static final int KEEP_ALIVE = 10;  
  4. ……  
  5. private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,  
  6.         MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);  
3.0以后
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();// We want at least 2 threads and at most 4 threads in the core pool,// preferring to have 1 less than the CPU count to avoid saturating// the CPU with background workprivate static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;private static final int KEEP_ALIVE_SECONDS = 30;


源码分析:
   用到很多线程的知识:Executor,FutureTask,AtomicBoolean,ThreadPoolExecutor,BlockingQueue

总结:并行还是串行

      在Android 1.6之前的版本,AsyncTask是串行的,在1.6至2.3的版本,改成了并行的。在2.3之后的版本又做了修改,可以支持并行和串行,当想要串行执行时,直接执行execute()方法,如果需要并行执行,则要执行executeOnExecutor(Executor)。

记得以前有个面试题经常会问道:AsyncTask运行的原理是什么?有什么缺陷?

以前对于缺陷的答案可能是:AsyncTask在并发执行多个任务时发生异常。其实还是存在的,在3.0以前的系统中还是会以支持多线程并发的方式执行,支持并发数也是我们上面所计算的128,阻塞队列可以存放10个;也就是同时执行138个任务是没有问题的;而超过138会马上出现

如果我们想要并行执行任务,可以调用AsyncTask的executeOnExecutor方法。如下:

new AsyncTask<Void,Void,Void>(){    @Override    protected Void doInBackground(Void... params) {        return null;    }}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,null);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

其实很好理解的。直接执行executeOnExecutor方法,传入AsyncTask.THREAD_POOL_EXECUTOR线程池。这样就绕过了SerialExecutor任务排队的过程。


AsyncTask内存泄漏问题;非静态内部类持有外部类的引用

AsyncTask可能存在新开大量线程消耗系统资源和导致应用FC的风险,因此,我们需要根据自己的需求自定义不同的线程池,由于篇幅问题,将留到下篇再讲。

  • AsyncTask不是被设计为处理耗时操作的,耗时上限为几秒钟,如果要做长耗时操作,强烈建议你使用Executor,ThreadPoolExecutor以及FutureTask

AsyncTask原理:
AnsycTask执行任务时,内部会创建一个进程作用域的线程池来管理要运行的任务,
也就就是说当你调用了AsyncTask.execute()后,AsyncTask会把任务交给线程池,
由线程池来管理创建Thread和运行Therad。最后和UI打交道就交给Handler去处理了。

问题:
“你在项目中,会用什么方案来替换AsyncTask呢?


http://blog.csdn.net/guolin_blog/article/details/11711405

http://blog.csdn.net/lmj623565791/article/details/38614699

0 0
原创粉丝点击