Android的主线程与子线程

来源:互联网 发布:人物动作设计软件 编辑:程序博客网 时间:2024/05/17 23:29

在上一篇文章Android的进程、线程与优先级中我们提到:

  • 线程(thread):是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。一个进程至少对应一个线程。

  • CPU轮流为每个任务分配其占用时间。每个任务都觉得自己在一直占用CPU,但事实上CPU时间是划分成片段分配给了所有任务。

因而使用线程的行为应当受到限制:

  • 进程资源有限,不能无限制地创建线程(创建和销毁线程都会有相应的开销)。

  • CPU的数量和轮转能力有限,过多的线程将导致CPU轮转周期变长,系统处理速度变慢。

在Android中,线程有更多一些的细分名目:主线程、子线程、HandlerThread、IntentService、AsyncTask。

  • 主线程:进程拥有的默认线程。Androidd的UI访问是没有加锁的,这样在多个线程访问UI是不安全的。所以Android中规定只能在UI线程中访问UI,故而主线程的响应速度不应该受到影响,所以所有耗时操作都应该放置到子线程中进行。

  • 子线程:进程中手动创建的线程,用于执行耗时任务。

  • HandlerThread:内部封装了Handler机制的子线程。运行时自动启动与子线程绑定的Looper。

  • IntentService:内部封装了HandlerThread的特殊Service。由于Service的优先级更高,所以适合执行一些高优先级的后台任务。

  • AsyncTask:一种内部封装了子线程和Handler机制的轻量级异步任务。


主线程(UI线程)

创建主线程:Android应用程序的入口

我们说“线程是程序执行的最小单元,主线程是进程拥有的默认线程”,那么创建进程的工作就必然包含了创建主线程的部分。同时,我们知道主线程的ID值与进程的进程号相同,因此可以推断:主线程就是进程默认的可执行部分,或者说:如果进程中总是只有一个线程,那么主线程就是进程本身。

既然我们希望了解主线程的创建过程的原因更多的是想知道应用程序从哪里开始运行。因此相比于了解创建主线程的过程,我们更应该关心的问题是:Android的应用程序入口在哪里?

我们知道Java中main()方法是Java应用程序的入口方法,也就是说,程序在运行的时候,第一个执行的方法就是main()方法。而Android应用程序的main()方法则在ActivityThread类中

但并不是说,直到ActivityThread.main()方法得到执行,新起的应用程序才开始运行。上面我们提到线程是进程的一个实体,在执行main()方法前,系统已经将应用的进程率先孵化出来,并在内部初始化了运行时库,并启动了Binder线程池。

事实上,直到一个新的应用程序进程创建完毕之后,才调用RuntimeInit类的静态成员函数invokeStaticMain将ActivityThread类的静态成员函数main设置为新创建的应用程序的入口函数。

ActivityThrad管理主线程的执行,并根据AMS的要求(使用Binder机制通信,AMS为客户端,ActivityThread.ApplicationThread为服务端)通过Handler消息机制调度并执行Activity、BroadCast等组件以及其它操作(在我们关心的范围内,可以认为ActivityThread等同于主线程)。

            \android\app\ActivityThread.main()            public static void main(String[] args) {            SamplingProfilerIntegration.start();            … …            // 创建/绑定主线程的Looper            // Looper、Handler是构成Android应用消息循环机制的主要部分            Looper.prepareMainLooper();            // 创建ActivityThread的实例            ActivityThread thread = new ActivityThread();            //建立Binder通道 (创建新线程)            thread.attach(false);            // 创建一个Handler            if (sMainThreadHandler == null) {                sMainThreadHandler = thread.getHandler();            }            // 开启Looper循环,这是一个死循环            Looper.loop();            // 除非Looper出现异常,否则该语句永远得不到执行            throw new RuntimeException("Main thread loop unexpectedly exited");        }

主线程如何在死循环中处理任务

新建一个应用,主Activity的代码如下:

        public class MainActivity extends Activity {            @Override            protected void onCreate(Bundle savedInstanceState) {                super.onCreate(savedInstanceState);                setContentView(R.layout.activity_main);                // 发送一个Message,what=1                handler.sendEmptyMessage(1);                Log.d("GooDong","Exit onCreat------");            }            @Override            protected void onResume() {                super.onResume();                // 发送一个Message,what=2                handler.sendEmptyMessage(2);                Log.d("GooDong","Exit onResume------");            }            private Handler  handler  = new Handler(new Handler.Callback() {                @Override                public boolean handleMessage(Message msg) {                    // 打印Message的标记值                    Log.d("GooDong","Message in ,msg.what = "+msg.what);                    return false;                }            });        }

运行结果:

        D/GooDong(1336): Exit onCreat------        D/GooDong(1336): Exit onResume------        D/GooDong(1336): Message in ,msg.what = 1        D/GooDong(1336): Message in ,msg.what = 2

从上述运行结果我们可以看出:

  • Looper.loop()执行之前,主Activity的生命周期已经结束了执行onResume()来到前台;
  • Looper.loop()执行之后,主线程就进入消息循环机制的死循环。

那么问题来了:

  1. Android中为什么主线程不会因为Looper.loop()里的死循环卡死?
  2. Activity的生命周期是怎么实现在死循环体外能够执行起来的?

上面我们提到,Android中规定只能在主线程中访问UI,这就意味着,如果主线程结束运行,那么这些资源就会被回收,看起来就是程序崩溃了。因而在Android中使用了死循环确保主线程的可执行代码是能一直执行下去的,不会被退出。

真正会卡死主线程的操作是在回调方法onCreate/onStart/onResume等操作时间过长,会导致掉帧,甚至发生ANR,looper.loop本身不会导致应用卡死

在ActivityThread.main()中有这样一行代码:

        // 创建ActivityThread的实例           ActivityThread thread = new ActivityThread();        // 建立Binder通道 (创建新线程)           thread.attach(false);

进入attach方法:

        private void attach(boolean system) {            sCurrentActivityThread = this;            mSystemThread = system;            if (!system) {                … …                // RuntimeInit获得一个ApplicationThread的Binder实例                RuntimeInit.setApplicationObject(mAppThread.asBinder());                final IActivityManager mgr = ActivityManagerNative.getDefault();                try {                    // IActivityManager绑定了当前的ApplicationThread                    mgr.attachApplication(mAppThread);                } catch (RemoteException ex) {                    // Ignore                }               … …            } else {                … …            }           … …        }

thread.attach(false)会创建一个Binder线程(具体是指ApplicationThread,Binder的服务端,用于接收系统服务AMS发送来的事件),该Binder线程通过Handler将Message发送给主线程。

尽管是处于死循环,实际上主线程大多数时候处于休眠状态,并不会消耗CPU资源。原因是,主线程在MessageQueue没有消息时,便阻塞在loop的queue.next()中的nativePollOnce()方法里。此时主线程会释放CPU资源进入休眠状态,直到下个消息到达或者有事务发生,通过往pipe管道写端写入数据来唤醒主线程工作。这里采用的epoll机制,是一种IO多路复用机制,可以同时监控多个描述符,当某个描述符就绪(读或写就绪),则立刻通知相应程序进行读或写操作,本质同步I/O,即读写是阻塞的。

Activity的生命周期都是依靠主线程的Looper.loop,当收到不同Message时则采用相应措施:在H.handleMessage(msg)方法中,根据接收到不同的msg,执行相应的生命周期。ActivityThread的内部类H继承于Handler,通过handler消息机制,简单说Handler机制用于同一个进程的线程间通信:

          private class H extends Handler {            public static final int PAUSE_ACTIVITY          = 101;            public static final int RESUME_ACTIVITY         = 107;                        … …            public void handleMessage(Message msg) {                switch (msg.what) {                    case PAUSE_ACTIVITY:                        // 执行Activity的onPause()流程                        … …                    case RESUME_ACTIVITY:                       // 执行Activity的onResume()流程                        … …                }            }

HandlerThread

在上一篇文章Android的进程、线程与优先级中我们给了一个Java子线程的简单示范,这里不再阐述子线程的相关内容。

HandlerThread继承了Thread,它是一种可以直接使用Handler的Thread。在它的run()方法烘通过Looper.prepare()来创建消息队列,并通过Looper.loop()来开启消息循环。

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

显然HandlerThread只是简单封装了Handler消息队列创建过程的Thread。HandlerThread只能通过消息机制来处理任务,这一点跟普通的Thread不同。在Android中的一个具体使用场景是IntentService,我们在将在下节介绍。

另外,无论我们是使用HandlerThread还是自行在线程中创建消息队列,承载该操作的子线程最终都陷入死循环,因此当明确不需要再使用该线程时应当手动调用Looper的quit或者quitSafely方法来终结这个线程

IntentService

IntentService继承自Service。它比Service方便的地方在于,封装了HandlerThread和Handler:

        // IntentService.onCreate()            public void onCreate() {            super.onCreate();            // 创建了一个HandlerThread实例            HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");            //,并启动了该线程            thread.start();            // 获取了子线程的Looper            mServiceLooper = thread.getLooper();            // 创建一个Handler对象并将其与子线程的Looper关联起来            mServiceHandler = new ServiceHandler(mServiceLooper);        }

同时,相比一般的后台任务线程,IntentService拥有更高的优先级(更不容易被系统回收)。请注意:这不是说,在IntentService中开启的线程也有较高的优先级。

上述代码中我们看到,当IntentService第一次启动调用onCreate时,会创建一个HandlerThread和一个Handler,这样就可以通过Handler将任务发布到HanlderThread中处理了。IntentService会在onStart中处理每个后台任务:

        // 每次启动IntentService,onStartCommand只会调用一次        public int onStartCommand(Intent intent, int flags, int startId) {            onStart(intent, startId);            return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;        }        public void onStart(Intent intent, int startId) {            Message msg = mServiceHandler.obtainMessage();            msg.arg1 = startId;            msg.obj = intent;            mServiceHandler.sendMessage(msg);        }

最终启动IntentService的Intent会在ServiceHandler中得到处理:

       private final class ServiceHandler extends Handler {            public ServiceHandler(Looper looper) {                super(looper);            }            public void handleMessage(Message msg) {                onHandleIntent((Intent)msg.obj);                stopSelf(msg.arg1);            }        }        // onHandleIntent是一个抽象类,需要子类实现        protected abstract void onHandleIntent(Intent intent);

stopSelf(int startId)在尝试停止服务前会判断最近启动服务的次数是否和startId相等,如果相等就立刻停止服务。直到onHandlerIntent方法执行完最后一个任务,stopSelf(int startId)才能把IntentService停止。

由于Handler机制中的任务只能顺序处理,所以IntentService中的任务也只能顺序处理。

下面举一个例子说明IntentService的工作过程,Service是四大组件之一,必须在注册文件中注册。:

    /** 继承IntentService自的类 */    public class MyIntentService extends IntentService{        private static final String TAG = "GooDong";        //  如果是显示启动Service,一定要有一个参数为空的构造函数        public MyIntentService() {            super(TAG);        }        public MyIntentService(String name) {            super(name);        }        // 覆写抽象方法,处理任务        @Override        protected void onHandleIntent(Intent intent) {            String actionCode = intent.getStringExtra("action_code");            Log.d(TAG, "receive task , actionCode = "+actionCode);            SystemClock.sleep(1000);            Log.d(TAG, "handle task , actionCode = "+actionCode);        }        @Override        public void onDestroy() {            Log.d(TAG, "Enter onDestroy---------");            super.onDestroy();        }   }    /**  在主Activity中启动任务 */    public class MainActivity extends Activity {        private static final String TAG = "GooDong";        @Override        protected void onCreate(Bundle savedInstanceState) {            Log.d(TAG, "Enter onCreate---------");            super.onCreate(savedInstanceState);            setContentView(R.layout.activity_main);            Intent myService = new Intent(this , MyIntentService.class);            myService.putExtra("action_code","task1");            startService(myService);            myService.putExtra("action_code","task2");            startService(myService);            myService.putExtra("action_code","task3");            startService(myService);            myService.putExtra("action_code","task4");            startService(myService);        }   }

结果打印:

    D/GooDong(1637): receive task , actionCode = task1    D/GooDong(1637): handle task , actionCode = task1    D/GooDong(1637): receive task , actionCode = task2    D/GooDong(1637): handle task , actionCode = task2    D/GooDong(1637): receive task , actionCode = task3    D/GooDong(1637): handle task , actionCode = task3    D/GooDong(1637): receive task , actionCode = task4    D/GooDong(1637): handle task , actionCode = task4    D/GooDong(1637): Enter onDestroy---------

可以看出,task1、task2、task3、task4按顺序执行,并且直到最后的task4执行完毕之后IntentService才被停止。

AsyncTask

使用AsyncTask

AsyncTask封装了Handler和Thread。使用AsyncTask可以方便地执行一些异步的任务,任务执行期间可以获取任务的进度,任务结束后可将结果更新到UI线程中。

AsyncTask是一个抽象的泛型方法,有三个泛型参量:

  • Params:表示传入参数的类型
  • Progress表示后台任务的执行进度的类型
  • Result表示后台任务的返回结果

如果不需要具体的参数,则可以指定为Void。
AsyncTask提供了四个核心方法:

  • onPreExecute(),在主线程中执行,在异步任务执行前调用
  • donInBackGround(),在线程中执行,用于执行异步任务
  • onProcessUpdate(),在主线程中执行返回当前任务执行进度
  • onPostExecute(),在主线程中执行,异步任务完成后调用,在这里返回任务结果

AsyncTask的使用需要注意以下几点:

  • AsyncTask的类必须在主线程中加载
  • AsyncTask的对象必须在主线程中创建
  • AsyncTask.execute()只能在主线程中调用
  • 一个AsyncTask只能调用一次

AsyncTask的工作原理

AsyncTask采用了模板方法设计模式。这种模式指:
定义一个操作中的算法的框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的执行结构即可重定义该算法的某些特定步骤。
其类图如下:
这里写图片描述

AsyncTask中的四个模板方法:

        // 抽象方法,必须覆写        protected abstract Result doInBackground(Params... params);        //空方法,可选择性覆写        protected void onPreExecute() {}        protected void onPreExecute() {}        protected void onProgressUpdate(Progress... values) {}

执行异步任务的入口:

    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) {            // 这说明AsyncTask任务只能执行一次            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;    }

execute是一个final方法,最终调用到executeOnExecutor方法,在该方法中判断AsyncTask的状态,如果不是PENDING状态则抛出异常,这也就解释了为什么AyncTask只能执行一次。
接着调用onPreExecute()。因为AsyncTask要求在主线程中执行,所以onPreExecute()也就是在主线程中执行的。然后params参数传递给了mWorker对象的mParams字段,执行了exec.execute(mFuture)。
接下来看看mWorker和mFuture是什么:

    public AsyncTask() {        mWorker = new WorkerRunnable<Params, Result>() {            public Result call() throws Exception {                mTaskInvoked.set(true);                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);                //noinspection unchecked                return postResult(doInBackground(mParams));            }        };        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 occured while executing                                  doInBackground()", e.getCause());                } catch (CancellationException e) {                    postResultIfNotInvoked(null);                }            }        };    }        public class FutureTask<V> implements RunnableFuture<V>    {        public FutureTask(Callable<V> callable) {                if (callable == null)                    throw new NullPointerException();                this.callable = callable;                this.state = NEW;               }        run(){            Callable<V> c = callable;            … …            result = c.call();            … …        }    }    public interface RunnableFuture<V> extends Runnable, Future<V>     {        void run();    }

mFuture有一个父类接口是Runnable,在实现的run()方法中执行了mWorker的call()方法,call()方法中调用了doInBackground(mParams)。所以当在线程池中执行mFuture时,其实是在子线程中执行了doInBackground(mParams)方法,并通过postResult()将执行结果返回。

    // 定义了一个Handler    private static final InternalHandler sHandler = new InternalHandler();    // postResult的实现    private Result postResult(Result result) {        // 注意这里不仅仅将消息封装入消息中,AsyncTask的对象引用也被封装了        Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,                new AsyncTaskResult<Result>(this, result));        message.sendToTarget();        return result;    }    //Handler的具体实现    private static class InternalHandler extends Handler {        @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:                    // 通过onProgressUpdate返回任务执行进度                    result.mTask.onProgressUpdate(result.mData);                    break;            }        }    }    // 结束任务    private void finish(Result result) {        if (isCancelled()) {            onCancelled(result);        } else {             // 通过onPostExecute将结果回调给用户            onPostExecute(result);        }        mStatus = Status.FINISHED;    }

在postResult中将AsyncTask对象引用执行结果封装在消息中,让消息处理返回的结果。InternalHandler有两个处理,一个是返回结果,另一个是返回执行进度。可以看到,onProgressUpdate()实际上是在主线程中执行的。最终在调用了AsyncTask的finish()方法结束执行任务。onPostExecute()也是在主线程中执行的。

0 0
原创粉丝点击