从源码角度理解Android线程

来源:互联网 发布:网络打鱼秘籍 编辑:程序博客网 时间:2024/06/07 16:10

线程分为主线程和子线程,主线程主要是做与界面相关的事,而子线程往往用于做耗时操作。Android中扮演线程的角色有很多,如:AsyncTask、IntentService以及HandlerThread。AsyncTask的底层使用的是线程池,其他两种直接使用线程。

AsyncTask封装了线程池和Handler,在它的内部使用Handler去更新UI线程。HandlerThread是一个具有消息循环的线程。IntentService是一种服务,内部采用HandlerThread来执行任务,由于是一种服务,不是Service,所以不会轻易被系统杀死。

由于频繁的创建和销毁线程会消耗大量的系统资源,所以一般是用线程池来进行控制,Android的线程池源于Java。

一、主线程和子线程

主线程是进程拥有的线程,Java默认只有一个主线程,主线程主要处理界面交互的逻辑,必须有较高的响应度,不然会造成界面延缓卡顿,这就要求主线程不能执行耗时任务,耗时任务交由子线程,即工作线程。

Android沿用了Java的线程模式,其中主线程叫UI线程,作用是运行四大组件以及处理它们同用户交互,而子线程执行耗时的任务,否则会出现ANR现象。


二、Android的线程形态

除了传统的Thread以外,还包含AsyncTask、HandlerThread以及IntentService,这三者底层实现也是线程。

1.AsyncTask

AsyncTask是一个轻量级的异步任务类,他可以在线程池中执行后台任务,然后把任务的进度和最终的结果传递给主线程并在主线程中更新UI。AsyncTask封装了Thread和Handler,但是AsyncTask不适合执行特别耗时的任务,虽然说内部封装了线程池,但是该线程池只有一条线程。

AsyncTask是一个抽象的泛型类,它提供了Params、Progress、Result这三个泛型参数,其中Params表示参数的类型,Progress表示后台的执行任务的类型,Result表示后台任务的执行结果类型,如果不需要传入参数,可以使用void来代替。AsyncTask的声明如下:

  • Params 启动任务执行的输入参数,比如HTTP请求的URL。
  • Progress 后台任务执行的百分比。
  • Result 后台执行任务最终返回的结果,比如String。
public abstract class AsyncTask<Params,Progress,Result>

AsyncTask提供了4个核心方法,含义如下:

  • onPreExecute(): 在主线程中执行,在异步任务加载执行之前,此方法会调用,用于做一些任务准备工作。
  • doInBackground(Params… params):在线程池中执行,此方法用于执行异步任务,params表示异步任务的输入参数。在此方法中可以通过publishProgress来更新任务进度,publishProgress会调用omProgressUpdate方法。另外此方法需要返回结果给onPostExecute方法。
  • onProgressUpdate(Progress…values):在主线程中执行,当后台任务执行发生改变会调用此方法。
  • onPostExecute(Result result):在主线程中执行,在异步任务执行的后面,其中result参数是后台任务的返回值,即doInBackground的返回值。

上面的几个方法,onPreExecute先执行,接着是doInBackground,最后是onPostExecute。此外,AsyncTask还提供了onCancelled方法,它在主线程中用,当异步任务被取消,就会调用该方法,这个时候onPostExecute就不会被调用。

    private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {        protected Long doInBackground(URL... urls) {            int count = urls.length;            long totalSize = 0;            for (int i = 0; i < count; i++) {                // totalSize += Downloader.downloadFile(urls[i]);                publishProgress((int) ((i / (float) count) * 100));                // Escape early if cancel() is called                if (isCancelled())                    break;            }            return totalSize;        }        protected void onProgressUpdate(Integer... progress) {            // setProgressPercent(progress[0]);        }        protected void onPostExecute(Long result) {            // showDialog("Downloaded " + result + " bytes");        }    }

该Demo主要模拟文件下载的过程,输入的参数类型是URL,后台任务的进程参数为Integer,而后台返回的结果是Long

new DownloadFilesTask().execute(new URL("http://www.baidu.com"),new URL("http://www.renyugang.cn"));

在DownloadFilesTask中,doInBackground用来执行具体的下载任务并通过publishProgress来更新下载的进度,同时要判断是否被外界取消。当下载完成后会调用onProgressUpdate来显示结果。doInBackground是在线程池中执行的,onProgressUpdate是在主线程中,当publishProgress被调用时,会顺带调用onProgressUpdate。当任务执行完毕后,也会调用onPostExecute,我们可以通过这个方法告知用户下载完毕。

AsyncTask在具体使用过程中也有一些限制,主要如下几点:

  • (1)AsyncTask必须在主线程中加载,Android4.1以上的系统已经自动完成了,在ActivityThread的main方法中会调用AsyncTask的init方法。
  • (2)AsyncTask的实例必须在主线程中创建
  • (3)execute方法必须在UI线程中调用
  • (4)不要在程序中手动调用onPreExecute、onPostExecute。doInBackground、onProgressUpdate方法。
  • (5)一个AsyncTask对象只能执行一次,只能调用一次execute方法。
  • (6)在Android 1.6之前,AsyncTask是串行执行任务,1.6后可以并行执行,但是3.0以后,为了避免并行带来的bug,又采用串行,虽然这样,但也可以通过AsyncTask的executeOnExecutor方法来并行执行任务。

2.AsyncTask的工作原理

分析AsyncTask的工作原理,我们从它的execute方法爱是分析,execute又会调用executeOnExecutor方法,实现如下:

    @MainThread    public final AsyncTask<Params, Progress, Result> execute(Params... params) {        return executeOnExecutor(sDefaultExecutor, params);    }        @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;    }

sDefaultExecutor实际上是一个串行的线程池,一个进程中所有的AsyncTask都在这个线程池中排队执行,在executeOnExecutor方法中,最先执行的是onPreExecute,然后线程池开始执行,下面试线程池的分析,如下所示:

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

从SerialExecutor的实现可以看出AsyncTask是排队执行的过程。首先会把AsyncTask的Params参数封转成FutureTask对象,FutureTask是并发类,在这里充当Runnable的作用,接着FutureTask交给SerialExecutor的execute方法执行,SerialExecutor的execute会通过mTask的offer将FutureTask对象插入到mTask中,如果这个时候没有正在活动的AsyncTask,或者当一个AsyncTask任务执行完,就会调用SerialExecutor的scheduleNext方法来执行下一个任务,直至任务被执行完毕。

AsyncTask中有两个线程池(SerialExecutor和THREAD_POOL_EXECUTOR)和一个Handler(InternalHandler),其中SerialExecutor用于任务的排队,THREAD_POOL_EXECUTOR用于真正的执行任务,InternalHandler用于将执行环境切换到主线程。AsyncTask的构造方法中有这么一段代码,由于FutureTask的run方法会调用mWorker的call方法,FutureTask会被提交到AsyncTask包含的线程池中执行,因此mWorker的call方法会在线程池中执行。

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

mWorker的call方法中,首先将mTaskInvoked标记位true,表示当前任务被执行过,然后执行AsyncTask的doInBackground方法,接着将返回值传给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 Handler getHandler() {        synchronized (AsyncTask.class) {            if (sHandler == null) {                sHandler = new InternalHandler();            }            return sHandler;        }    }

在上面代码中,会通过getHandler返回一个sHandler,通过sHandler返回一个MESSAGE_POST_RESULT的消息,这个sHandler的定义如下:

    private static InternalHandler sHandler;    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;            }        }    }

sHandler是一个静态变量,为了能够将环境切换到主线程,必须要在主线程中创建sHandler,这就变相要求AsyncTask也需要在主线程中加载。sHandler收到MESSAGE_POST_RESULT这个消息后,会调用AsyncTask的finish的方法:

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

AdyncTask的finish方法逻辑比较简单,如果AsyncTask被执行了,那么onCancelled就被调用,否则就执行onPostExecute方法。

3.HandlerThread

HandlerThread继承了Thread,本质上是一个Thread,只不过内部建立了Looper,可以使用Handler,主要是在run方法中通过Looper.prepare()来创建消息队列,然后通过Lopper.loop()来开启消息循环,在实际应用中就允许在HandlerThread中创建Handler了。HandlerThread的run方法如下:

    @Override    public void run() {        mTid = Process.myTid();        Looper.prepare();        synchronized (this) {            mLooper = Looper.myLooper();            notifyAll();        }        Process.setThreadPriority(mPriority);        onLooperPrepared();        Looper.loop();        mTid = -1;    }

从HandlerThread的实现来看,HandlerThread内不能创建了消息队列,这和普通的Thread不一样,要通过Handler的消息方式通知HandlerThread去执行任务。在使用完HandlerThread后,可以通过quit或者quitSafety来退出。

4.IntentService

IntentService是一种特殊的Service,它继承Service并且是个抽象类,所以要用它的子类。IntentService是一种服务,所以优先级比单纯的线程高,里面封装了HandlerThread和Handler,这一点从他的onCreate方法可以看出。

    @Override    public void onCreate() {        // TODO: It would be nice to have an option to hold a partial wakelock        // during processing, and to have a static startService(Context, Intent)        // method that would launch the service & hand off a wakelock.        super.onCreate();        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");        thread.start();        mServiceLooper = thread.getLooper();        mServiceHandler = new ServiceHandler(mServiceLooper);    }

当IntentService第一次被启动的时候,它的onCreate会被调用,然后创建一个HandlerThread对象,用它的Looper来构建一个Handler对象,这样每次发送handler发送消息的时候都会在HandlerThread线程中执行。

每次启动IntentHandler,都会调用onStartCommand方法,IntentService在onStartCommand中处理每个后台任务的Intent,同时调用onStart方法:

    @Override    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {        onStart(intent, startId);        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;    }        @Override    public void onStart(@Nullable Intent intent, int startId) {        Message msg = mServiceHandler.obtainMessage();        msg.arg1 = startId;        msg.obj = intent;        mServiceHandler.sendMessage(msg);    }

可以看出,IntentService仅仅通过mServiceHandler发送一个消息,这个消息会在HandlerThread中处理,mServiceHandler收到消息后,会将Intent对象传递到onHandlerIntent中去处理,这个Intent和一开始传进来的Intent是一样的。当onHandlerIntent方法执行结束后,IntentService会调用stopSelf(int startId)来停止服务,该方法会等消息队列没有消息后才停止,而stopSelf()会立即就停止。

    private final class ServiceHandler extends Handler {        public ServiceHandler(Looper looper) {            super(looper);        }        @Override        public void handleMessage(Message msg) {            onHandleIntent((Intent)msg.obj);            stopSelf(msg.arg1);        }    }

InstentService的onHandleIntent方法是一个抽象方法,我们需要在子类中实现,它的作用是通过Intent参数中区分具体的任务并执行任务,执行完后通过stopSelf(int startId)来停止服务。另外,每次执行一个后台任务必须启动一次IntentHandler,而内部通过消息的方式向HandlerThread请求执行任务,HandlerThread的Looper是顺序执行任务,这就意味着IntentService也是顺序执行任务。

原创粉丝点击