zoukankan      html  css  js  c++  java
  • AsyncTask源码分析

    AsyncTask类是我们在开发中经常需要用到的一个类,这个类有个最大的好处就是将耗时的操作和UI操作分开来处理,这样在这一个类中我们就可以很方便的处理耗时操作和UI操作了。
    先上一个简单的例子来看看基本的用法。

    public class MainActivity extends AppCompatActivity {
    
        private ImageView mImageView;
        private static final String URLSTRING = "https://img3.doubanio.com/view/photo/photo/public/p2360705951.jpg";
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mImageView = (ImageView) this.findViewById(R.id.imageview);
            new MyAsyncTask().execute();
        }
    
    
        class MyAsyncTask extends AsyncTask<Void, Integer, Bitmap> {
    
            @Override
            protected Bitmap doInBackground(Void... voids) {
                URL url = null;
                HttpURLConnection conn = null;
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                try {
                    url = new URL(URLSTRING);
                    conn = (HttpURLConnection) url.openConnection();
                    if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
                        InputStream ins = conn.getInputStream();
                        int length = 0;
                        byte[] data = new byte[1024];
                        while ((length = ins.read(data, 0, data.length)) != -1) {
                            bos.write(data, 0, length);
                        }
                        byte[] buffer = bos.toByteArray();
                        return BitmapFactory.decodeByteArray(buffer, 0, buffer.length);
                    }
    
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    conn.disconnect();
                    try {
                        bos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                return null;
            }
    
            @Override
            protected void onPostExecute(Bitmap bitmap) {
                mImageView.setImageBitmap(bitmap);
            }
        }
    
    }

    这个例子很简单,就是加载一个网络图片,并且显示到ImageView上去。

    效果如下:
    这里写图片描述

    下面源码的分析也从如何操作耗时操作和如何操作UI操作两个方面来分析AsyncTask。

    • 耗时操作
      对于耗时操作,AsyncTask内部是使用ThreadPool线程池来操作的。直接上源码
     private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
        private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
        private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
        private static final int KEEP_ALIVE = 1;
    
        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);
    
        /**
         * An {@link Executor} that can be used to execute tasks in parallel.
         */
        public static final Executor THREAD_POOL_EXECUTOR
                = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                        TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
    

    CPU_COUNT、CORE_POOL_SIZE、MAXIMUM_POOL_SIZE、KEEP_ALIVE这些常量包含了cpu数量、线程池数量、最大线程池数量、同时或者的最多的线程数量,这些都是用于构造线程池执行器的参数。sThreadFactory是一个线程构造器,sPoolWorkQueue是一个容量为128的阻塞队列。这些参数最后构造了THREAD_POOL_EXECUTOR,通过这个线程池执行器,耗时的任务就可以通过阻塞队列依次的被执行。

    • UI线程操作
      UI线程的操作是通过构造了一个关联UI线程的InternalHandler来处理的。,上源码。
     private static class InternalHandler extends Handler {
            public InternalHandler() {
                super(Looper.getMainLooper());
            }
    
            @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]);
                        break;
                    case MESSAGE_POST_PROGRESS:
                        result.mTask.onProgressUpdate(result.mData);
                        break;
                }
            }
        }

    在InternalHandler类的构造方法中,传递一个Looper.getMainLooper()参数,就可以将这个Handler关联到UI线程上,所有Handler中的处理也就分发到了UI线程上。所以我们可以利用这个Handler来执行UI操作。

    现在我们可以大致得出一个结论:耗时的操作是通过线程池THREAD_POOL_EXECUTOR执行的;UI的操作是通过InternalHandler类操作的。

    对于AsyncTask的使用最简单的莫过于上面的new MyAsyncTask().execute(),这个调用涉及到构造方法和executor()两个方法,下面就通过这两个方法的执行来彻底梳理一下AsyncTask的流程。

    • 构造方法
     public AsyncTask() {
            mWorker = new WorkerRunnable<Params, Result>() {
                public Result call() throws Exception {
                    mTaskInvoked.set(true);
    
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    //noinspection unchecked
                    return postResult(doInBackground(mParams));
                }
            };
    
            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 occured while executing doInBackground()",
                                e.getCause());
                    } catch (CancellationException e) {
                        postResultIfNotInvoked(null);
                    }
                }
            };
        }

    从代码中可以看到,在构造方法中,生成了一个WorkRunnable对象,WorkRunnable这个类实际上就是一个实现了Callable接口的抽象类,在call()方法中,我们调用了doInBackground()方法,并且将最终的结果通过postResult()分发出去;Callable接口并不是我们需要的,因为线程池需要Runnable的接口,所以又生成了一个FutureTask的对象用来将Callable接口转换成Runnable接口。所以构造方法的目的是生成一个mFuture的FutureTask对象。

    • executor方法
      executor方法最后调用的executeOnExecutor()方法,我们看源码:
    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;
        }

    在这个方法中,最终调用了exec.execute(mFuture),exec就是sDefaultExecutor,最终调用了线程池ThreadPoolExecutor中的executor方法执行doInBackground方法,并且在这个方法执行完毕之后调用postResult()方法。

     private Result postResult(Result result) {
            @SuppressWarnings("unchecked")
            Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                    new AsyncTaskResult<Result>(this, result));
            message.sendToTarget();
            return result;
        }

    postResult方法调用了internalHandler中的消息处理。

       case MESSAGE_POST_RESULT:
                        // There is only one result
                        result.mTask.finish(result.mData[0]);
                        break;

    result.mTask指的就是AsynTask这个对象,结果就是调用了finish()方法。

       private void finish(Result result) {
            if (isCancelled()) {
                onCancelled(result);
            } else {
                onPostExecute(result);
            }
            mStatus = Status.FINISHED;
        }

    最后执行了onPostExecute()这个方法,并且是通过InternalHandler在UI线程完成的。

    最后总结一下:在构造方法中,将doInBackground()方法最终包装成一个FutureTask类,然后通过 execute()方法,将这个方法传递到线程池中执行;等执行完毕之后,通过InternalHandler将这个结果发送到AsyncTask的finish()方法中执行,在finish方法中执行onPostExecutor()方法。大致流程就是这样~~

  • 相关阅读:
    hanlp在jdk11 maven8编译后在jdk8 报错
    Linux top命令输出到文件——持续输出某个进程的信息
    maven with depend
    解决mount时发生错误wrong fs type, bad option, bad superblock
    leetcode中 01背包问题相关汇总
    leetcode刷题总结901-950
    Xgboost如何处理缺失值/
    leetcode刷题总结851-900
    leetcode刷题总结801-850
    leetcode刷题总结751-800
  • 原文地址:https://www.cnblogs.com/summerpxy/p/13648324.html
Copyright © 2011-2022 走看看