zoukankan      html  css  js  c++  java
  • AsyncTask学习

    在学习Android的时候,我们用到比较多的异步处理的类大概就是AsyncTask,但是很多时候只知道调用,却不知道思考一些东西。

    本文就简单的总结和分析了一些AsyncTask的知识。

    一、AsyncTask使用
    直接继承AsyncTask,它一共有3个泛型参数Params, Progress, Result.

    public abstract class AsyncTask<Params, Progress, Result> 
    • Params表示AsyncTask执行任务的参数的类型(传入的参数的类型,在doInBackground用到的,使用execute方法中传入)
    • Progress表示在后台线程处理的过程中,可以阶段性地发布结果的数据类型(在onProgressUpdate中用到,使用publicProgress中传入)
    • Result表示任务全部完成后所返回的数据类型(doInBackground方法的返回值)

     必须实现的方法有一个:

    protected abstract Result doInBackground(Params... params);

    这个方法是在异步线程中执行的,我们主要操作和实现的就是这个方法。

    有3个方法需要熟悉:

    #异步执行之前也就是doInBackground之前执行
    protected void onPreExecute()
    #异步执行之后也就是doInBackground之后执行
    protected void onPostExecute(Result result)
    #执行过程中执行
    protected void onProgressUpdate(Progress... values) 

    这3个方法都是在UI线程中,所以可以直接更新UI。

    执行的方法有两个:

    public final AsyncTask<Params, Progress, Result> execute(Params... params) {

    execute方法,每次只能执行一个线程,不支持并发。

    public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
                Params... params) {

    executeOnExecutor可以添加自己的线程池,是可以支持并发的。

    AsyncTask使用的注意事项

    • AsyncTask的实例必须在主线程中创建。

    • AsyncTask的execute方法必须在主线程中调用。

    • onPreExecute()、onPostExecute(Result),、doInBackground(Params…) 和 onProgressUpdate(Progress…)这四个方法都是回调方法,Android会自动调用,我们不要自己调用。

    • 对于一个AsyncTack的实例,只能执行一次execute,在该实例上第二次执行execute时就会抛出异常。

    前两条基本是一个意思,就是使用AsyncTask的时候在UI线程中创建/执行。4个主要的方法不能在外部去调用,一个AsyncTask执行一次。

    二、源码分析

    AsyncTask主要是通过线程池+handler来实现。

    线程池:

        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 work
        private 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; 
    
        /**
         * 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;
        }

    使用ThreadPoolExecutor创建一个线程池,这线程池的核心线程是动态的,根据cpu的数量来定(2-4)个,在4.4之前的核心线程数是5。

        private static class SerialExecutor implements Executor {
            final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
            Runnable mActive;
    
            public synchronized void execute(final Runnable r) {
                mTasks.offer(new Runnable() {
                    public void run() {
                        try {
                            r.run();
                        } finally {
                            scheduleNext();
                        }
                    }
                });
                if (mActive == null) {
                    scheduleNext();
                }
            }
    
            protected synchronized void scheduleNext() {
                if ((mActive = mTasks.poll()) != null) {
                    THREAD_POOL_EXECUTOR.execute(mActive);
                }
            }
        }

    把Runnable放入双端队列末尾,交给线程池去处理。(java.util.ArrayDeque.offer(E e) 方法将指定元素E在此deque队列的末尾。

    java.util.ArrayDeque.poll() 检索并移除此queue队列表示的队列的头部,如果此queue队列为空,返回null)

    具体的线程:

            mWorker = new WorkerRunnable<Params, Result>() {
                public Result call() throws Exception {
                    mTaskInvoked.set(true);
                    Result result = null;
                    try {
                        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                        //noinspection unchecked
                        result = doInBackground(mParams);
                        Binder.flushPendingCommands();
                    } catch (Throwable tr) {
                        mCancelled.set(true);
                        throw tr;
                    } finally {
                        postResult(result);
                    }
                    return 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);
                    }
                }
            };

    主要就是这个FutureTask+Callable实现了异步线程,WorkerRunnable 实现了Callable接口。

    (实现多线程的方式有几种?可能现在需要多记一种Callable)

    主要Handler:

        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]);
                        break;
                    case MESSAGE_POST_PROGRESS:
                        result.mTask.onProgressUpdate(result.mData);
                        break;
                }
            }
        }

    在实例化AsyncTask的时候会去准备好线程池、线程和handler,在execute执行的时候把线程扔到线程池中执行,执行中可以发送数据给handler(publishProgress),结束后发消息给handler(postResult)。

    根据源代码可以总结出:

    1. execute方法会调用executeOnExecutor方法,使用的线程池还是默认的
    2. executeOnExecutor和execute在UI线程执行,那么里面调用的所有方法也是在UI线程中,所以onPreExecute()方法在UI线程中
    3. handler使用的是UI线程的looper = Looper.getMainLooper(),那么Handler的handleMessage方法在UI线程中,所以onPostExecute和onProgressUpdate在UI线程中。
  • 相关阅读:
    ThinkPHP中自定义常量
    【转】在Asp.net中弹出对话框,然后跳转到其他页面问题
    【转】SVN版本控制器的安装和配置
    【原】用上传控件进行文件上传时,页面程序代码都不执行,显示“页面信息无法显示”
    【转】net Web Service 方法重载
    【转】SQL里的EXISTS与in、not exists与not in
    【转】利用wsdl.exe生成webservice代理类
    【转】获取图片大小
    【转】用了AJAX后,不能用javascript弹出对话框
    【转】net Web Service 方法重载
  • 原文地址:https://www.cnblogs.com/doubleyoujs/p/7761116.html
Copyright © 2011-2022 走看看