AsyncTask中线程转换的实现

来源:互联网 发布:淘宝明星店铺收费 编辑:程序博客网 时间:2024/05/16 00:48

说明:最开始接触网络的时候,那时候尝试写了写回调,但自己写不出线程的转换来,就必须在回调方法中写上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方法,那么就实现了线程的转换。

0 0
原创粉丝点击