54、Android AsyncTask学习笔记

一、AsyncTask简介

AsyncTask是Android提供的一个轻量级异步任务机制,使用AsyncTask可以方便的执行异步任务,并将结果更新到main thread。AsyncTask中是通过Handler机制来让work thread和main thread通信的。

二、AsyncTask使用

AsyncTask有三个泛型参数,分别是Params, Progress, Result。Params是指后台任务运行的参数,用于在doInBackground使用,Progress是用来指示后台任务执行进度的单位,Result是后台任务的返回结果,在doInBackground方法中返回,交给onPostExecute处理。这些参数不需要时可以用Void代替。

public class TestAsyncTask extends AsyncTask<Void, Integer, Void> {
    private String taskName;

    public TestAsyncTask(String name) {
        super();
        taskName = name;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        // onPreExecute在doInBackground之前执行,用于执行准备工作
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);
        // onProgressUpdate用来更新后台任务的执行进度。
    }

    @Override
    protected void onPostExecute(Void aVoid) {
        super.onPostExecute(aVoid);
        // onPostExecute做一些更新UI的操作
        Log.v("stone", "task = " + taskName + " onPostExecute in " + Thread.currentThread().toString());
    }

    @Override
    protected Void doInBackground(Void... params) {
        // 只有doInBackground是运行在workthread中的.其他方法运行在主线程
        // 耗时的操作放在doInBackground进行 
        Log.v("stone", "task = " + taskName + " doInBackground in " + Thread.currentThread().toString());
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.toString();
        }
        return null;
    }

}

//AsyncTask的两种启动方式
new TestAsyncTask("task_" + i).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
new TestAsyncTask("tasktesk_" + i).execute();
三、AsyncTask源码分析
1、AsyncTask构造初始化
public AsyncTask(@Nullable Looper callbackLooper) {
		// 创建Handler
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);
		// 初始化Callable 回调使用
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                Result result = null;
                try {
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    // doInBackground()  方法回调
                    result = doInBackground(mParams);
                    Binder.flushPendingCommands();
                } catch (Throwable tr) {
                    mCancelled.set(true);
                    throw tr;
                } finally {
                    postResult(result);
                }
                return result;
            }
        };
		// Runable 线程池真正执行的对象
        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);
                }
            }
        };
    }

构造方法主要初始化
Handler:发送消息
mWorker: 会在回调call() 方法中调用 doInBackground()
mFuture :会交给Executor去执行

2、AsyncTask 执行
 @MainThread
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }


 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()方法,这就解释了为什么onPreExecute方法是最新被调用的
        onPreExecute();

        mWorker.mParams = params;
        exec.execute(mFuture);

        return this;
    }

把mFuture交给我们传入的Executor来执行。对面我们前文提到了AsyncTask的两种启动方式,他们执行方式的不同是因为传入的Executor不同导致的。我们前面提到过execute方法传给executeOnExecutor的是一个sDefaultExecutor对象,通过源码来看一下sDefaultExecutor是什么:

	// AsyncTask中的静态内部类
  private static class SerialExecutor implements Executor {
  		// AsyncTask 任务栈队列
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;

        public synchronized void execute(final Runnable r) {
        	// 添加一个 AsyncTask
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                    // 这里的 r就是 mFuture
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }

        protected synchronized void scheduleNext() {
        	// 取出一个 Runnable  执行
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }

SerialExecutor 是一个静态内部类,内部维护 ArrayDeque mTasks 队列,通过execute(final Runnable r) 将AsyncTask添加到mTasks( mTasks.offer())中,之后通过mTask.poll() 方法取出交给 线程池执行THREAD_POOL_EXECUTOR.execute(mActive)。
线程池回调Runnable(mFuture)的run()方法,而mFuture如何引起mWorker的回调呢?
源码:

// 构造传递callable 
  public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }
// 线程池execute(Runable)时执行
public void run() {
		... 
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                	// Callable 执行call方法
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    .....
            }
        } finally {
          ...
        }
    }

至此 AsyncTask的执行流程就完成了。
小结:
1、AsyncTask 初始化一个mWorker(Callable) 、一个mFuture(Runable)和创建一个Handler
2、当 AsyncTask 执行execute()方法时,就是mFuture添加offer()到 mTasks 队列中,之后取出poll()交给线程池执行。
3、线程池执行Runable 会回调mWorker 的run方法从而在子线程执行doInBackground()

3、AsyncTask回调
private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
       	// 发送消息
        message.sendToTarget();
        return result;
    }
   
 // Message  类方法  
 public void sendToTarget() {
        target.sendMessage(this);
    }

由getHandler()

 private Handler getHandler() {
        return mHandler;
    }

mHandler 如何初始化呢?AsyncTask构造函数中初始化 InternalHandler

public AsyncTask(@Nullable Looper callbackLooper) {
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);
            .....
}

InternalHandler 接收发送的消息

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
                    // 分发消息 onCancelled 、onPostExecute
                    result.mTask.finish(result.mData[0]);
                    break;
                case MESSAGE_POST_PROGRESS:
                	// 分发消息 onProgressUpdate
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }

小结
1、在mWorker中回调执行 postResult(result)
2、postResult将执行的结果通过Handler消息机制发送出去
3、InternalHandler中接收Handler发送的消息,并分发AsyncTask的onCancelled 、onPostExecute、onProgressUpdate方法
4、InternalHandler 通过 sHandler = new InternalHandler(Looper.getMainLooper())创建因此onCancelled 、onPostExecute、onProgressUpdate 等方法运行在主线程

四、AsyncTask运行机制总结

AsyncTask初始化及执行:
1、AsyncTask 初始化一个mWorker(Callable) 、一个mFuture(Runable)和创建一个Handler
2、当 AsyncTask 执行execute()方法时,就是mFuture添加offer()到 mTasks 队列中,之后取出poll()交给线程池执行。
3、线程池执行Runable 会回调mWorker 的run方法从而在子线程执行doInBackground()

AsyncTask执行结果回调:
1、在mWorker中回调执行 postResult(result)
2、postResult将执行的结果通过Handler消息机制发送出去
3、InternalHandler中接收Handler发送的消息,并分发AsyncTask的onCancelled 、onPostExecute、onProgressUpdate方法
4、InternalHandler 通过 sHandler = new InternalHandler(Looper.getMainLooper())创建因此onCancelled 、onPostExecute、onProgressUpdate 等方法运行在主线程

五、AsyncTask不足

AsyncTask是Handler与线程池的封装。
网络请求等耗时操作在线程池中完成,通过handler发送给主线程完成UI更新。
使用线程池的主要原因是避免不必要的创建及销毁线程的开销。

六、线程池属性
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;

ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                sPoolWorkQueue, sThreadFactory);
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;

核心线程数为:最少两个最多4个,最大线程数是2倍的CPU核个数+1,任务排队队列大小为128,

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值