Android-AsyncTask

AsyncTask在最新的API中已经被弃用了,但是之前的项目中用到过,还看看源码以及它的问题叭!

首先看一下构造:

public AsyncTask(@Nullable Looper callbackLooper) {
		// 如果创建AsyncTask对象的时候没有传递Looper进来,那么默认绑定主线程的Looper
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);

        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);
                }
            }
        };
    }


    private static Handler getMainHandler() {
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                sHandler = new InternalHandler(Looper.getMainLooper());
            }
            return sHandler;
        }
    }

构造里面创建了一个WorkRunnable对象,这个对象实现了Callable接口,重写了call()方法,在这个call()方法里面就可以看到我们写的doInBackground()方法是在这里被调用的。之后通过postResult()发送出去;

那么一般我们使用AsyncTask的时候,会重写onPreExecute()doInBackground()onPostExecute()这几个方法;然后new 一个AsyncTask对象,传入参数,调用execute()方法执行。那我们就从execute()切入。

@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
    return executeOnExecutor(sDefaultExecutor, params);// 注意这里传进去了一个sDefaultExecutor
}

@MainThread
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;
}

我们看到FutureTask对象交给线程池之后就返回了。那么这个线程池是什么呢???是一个内部定义的串行线程池SerialExecutor,看一下它的实现:

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
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);
        }
    }
}

串行线程池在这里就是

  1. 把传进来的任务封装成一个Runnable对象,添加对一个队列之中
  2. 在执行完成之后,会从队列中拿出下一个就给交给另一个线程池THREAD_POOL_EXECUTOR执行

我们继续看这个THREAD_POOL_EXECUTOR:

public static final Executor THREAD_POOL_EXECUTOR;
private static final int CORE_POOL_SIZE = 1;
private static final int MAXIMUM_POOL_SIZE = 20;
private static final int BACKUP_POOL_SIZE = 5;
private static final int KEEP_ALIVE_SECONDS = 3;

static {
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
            CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
            new SynchronousQueue<Runnable>(), sThreadFactory);
    threadPoolExecutor.setRejectedExecutionHandler(sRunOnSerialPolicy);
    THREAD_POOL_EXECUTOR = threadPoolExecutor;
}

private static final RejectedExecutionHandler sRunOnSerialPolicy =
        new RejectedExecutionHandler() {
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        android.util.Log.w(LOG_TAG, "Exceeded ThreadPoolExecutor pool size");
        // As a last ditch fallback, run it on an executor with an unbounded queue.
        // Create this executor lazily, hopefully almost never.
        synchronized (this) {
            if (sBackupExecutor == null) { // 如果后备线程池没有创建,则创建一个
                sBackupExecutorQueue = new LinkedBlockingQueue<Runnable>();
                sBackupExecutor = new ThreadPoolExecutor(
                        BACKUP_POOL_SIZE, BACKUP_POOL_SIZE, KEEP_ALIVE_SECONDS,
                        TimeUnit.SECONDS, sBackupExecutorQueue, sThreadFactory);
                sBackupExecutor.allowCoreThreadTimeOut(true);
            }
        }
        sBackupExecutor.execute(r);//否则直接交给后备线程池执行
    }
};

可以看到这是一个核心线程数为1,最大线程数为20的线程池。同时看一下它的拒绝策略,发现是另外一个核心线程=5,最大线程数=5的线程池。

执行完成之后,就会通过postResult()把结果传递出去:

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

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;
        }
    }
}

private void finish(Result result) {
    if (isCancelled()) {
        onCancelled(result);
    } else {
        onPostExecute(result);
    }
    mStatus = Status.FINISHED;//标记已完成
}

通过getHandler()拿到与主线程关联的Handler,然后构建消息发送到主线程,主线程调用onPostExecute()。至此我们就把重写的方法串起来啦!!

Question:

  1. 为什么AsyncTask要在主线程创建?
    旧版本才有这个问题,旧版本的源码private static final InternalHandler sHandler = new InternalHandler();,注意是无参构造,那么在子线程创建Handler的时候就会去关联子线程的Looper。这样的话就没办法更新到主线程了。AsyncTask的设计就是方便更新UI嘛,如果那样子就没违背了这个设计的初衷。在新的版本中就没有这个问题了。

  2. 可能存在什么问题?
    可能会报空指针异常,原因是AsyncTask执行的时候,Activity销毁了,那么AsyncTask在这个时候返回来更新UI,就会出错;解决的方案:把Activity弱引进来,在onPostExecute()更新UI之前,先判空一下。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值