AsyncTask中线程转换的实现

本文探讨了Android中AsyncTask如何实现线程转换,重点分析了InternalHandler在主线程中的作用,通过Handler和Looper的原理解释了AsyncTask如何在后台执行任务并在主线程更新UI。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

说明:最开始接触网络的时候,那时候尝试写了写回调,但自己写不出线程的转换来,就必须在回调方法中写上runOnUiThread方法来切换到主线程。最近研究了一下Android中的线程,一时冲动有了写博客的想法,来记录下自己的成长之路。

Android中一般采用Handler来实现主线程与子线程的切换,这是最常用的,就不再废话了,那么我们来看一下AsyncTask的实现。

AsyncTask的使用前提是,必须在主线程中创建AsyncTask的子类对象,那么这个前提正是可以获取主线程的基础。

private static InternalHandler sHandler;

这是AsyncTask里的一个静态成员变量,显然,它就是线程转换的关键类,下面是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的构造方法中调用了Handler的Handler(Looper looper)这个构造方法,将主线程的looper传入,那么这个handler处理消息就会在looper的线程中执行。

继续来看Handler的源码

public Handler(Callback callback, boolean async) {
        ......

        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

这里也证明了如果在一个线程中没有执行Looper.prepare()方法,直接创建Handler是会抛出异常的,mLooper = Looper.myLooper(); 打开Looper的myLooper方法,来看源码

public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

可以看到Looper用一个ThreadLocal

Thread currentThread = Thread.currentThread();

其它代码不再贴出,但是到此我们可以看出Looper与创建Looper的线程是相联系的,我们使用Looper来从MessageQueue并交给Handler的HandleMessage来处理

回到主题
在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);
            }
        };

可以看到在doPackground方法执行完成后会调用postResult方法并将结果传入,来看postResult方法

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

getHandler的实现

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

可以发现最终会有InternalHandler来执行发送消息的方法,因为InternalHandler肯定是主线程的Handler,那么最终处理消息肯定是在主线程中

来看InternalHandler的handleMessage方法的源码

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

由语义就可以看出一个是得到了结果,一个是更新进度
更新进度会调用onProgressUpdate方法,得到结果会调用result.mTask.finish(result.mData[0]);

下面是mTask.finish()方法的源码

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

可以看到如果任务被取消会调用onCancelled方法,否则执行onPostExecute方法

总结:AsyncTask之所以可以在主线程执行进度更新的方法和onPostExecute方法,关键的类就行内部维护了一个肯定在主线程的类InternalHandler,本质就是Handler,由这个类来执行onProgressUpdate与onPostExecute方法,那么就实现了线程的转换。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值