美文网首页
Service的生命周期

Service的生命周期

作者: 能写就别叨叨 | 来源:发表于2019-11-28 19:20 被阅读0次

原作者:[在一颗大大大榕树下
原链接:[ https://www.jianshu.com/p/902aa6a8f604 ]

概念:Android四大组件之一,没有可视化界面,是一个运行于后台的服务程序。

目录

  • Service和线程的区别和场景
  • 管理Service的生命周期
  • service和IntentService有什么区别
  • 启动服务绑定服务先后次序问题
  • 远程服务AIDL
  • Binder
  1. Service和线程的区别和场景

我们都知道,Service和线程呢,都是在后台运行的,那么google为什么要为android系统创造出Service这么一个组件呢?我们先来看下线程和Service的特点。

Thread

程序最小的执行单元,他是分配给CPU的基本单位

生命周期

  1. 新建(new Thread)
  2. 就绪 (线程已经启动,等待CPU资源)
  3. 运行(run已经获得资源)
  4. 死亡(执行完成或被杀死)
  5. 阻塞(因为某种原因线程让出cpu资源,就会进入阻塞状态)

这里可以看出来一个致命的问题

线程一但run了起来,就和Activity失去关联了。
即使Activity被干掉了,Thread依旧能快乐的执行下去。

Thread是无法控制的。
google:这问题很大。

image

OK,于是我们的Service就诞生了。

  1. 管理Service的生命周期

Service的生命周期

  • onCreate
  • onStart
  • onDestroy
  • onBind
  • onUnBind

我们来看一下,Activity是如何管理Service的,他的生命周期又是如何变化的。

  • 启动服务:startService
23:42:02.003 1173-1173/? I/MyService: onCreate
23:42:02.003 1173-1173/? I/MyService: onStartCommand

注意,多次调用startService() 方法,onCreate只会调用一次,但是onStartCommand会调用多次

  • 停止服务:stopService
23:45:17.443 1292-1292/com.yirong.androidpractice I/MyService: onDestroy

注意,在调用bindService之后,就算调用stopService也无法停止服务,必须先解绑

  • 绑定服务:bindService
   bindService(intent,this, Context.BIND_AUTO_CREATE)
   stopService(intent)

00:09:38.653 1361-1361/com.yirong.androidpractice I/MyService: onCreate
00:09:38.653 1361-1361/com.yirong.androidpractice I/MyService: onBind

划重点:bindService不调用onStart方法

  • 解绑服务:unBindService
00:10:40.882 1411-1411/com.yirong.androidpractice I/MyService: onUnbind
00:10:40.882 1411-1411/com.yirong.androidpractice I/MyService: onDestroy

  1. service和IntentService有什么区别

首先得划个重点:Service是在主线程中运行的,所以不能做耗时操作,会报ANR异常

image

不能做耗时操作,就意味着无法替代Thread的功能,那这Service啥意义啊?

这就是IntentServiceService区别了。

打开源码,按照惯例看下脑袋这块儿的小灰字。

总结下,大概就这么点意思:

  • IntentService是一个继承并处理异步请求的类
  • 他的内部有一个工作线程来处理耗时操作

扒一段源码看看

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

一看就明白了,底层还是Thread写的,但是对Thread做了处理。
点开HandlerThread,直接看重点:

public class HandlerThread extends Thread {
    ...
    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();//为当前线程创建一个Looper对象,一个线程只能有一个Looper对象
        synchronized (this) {
            mLooper = Looper.myLooper();//获取当前线程的looper对象
            notifyAll();//唤醒线程
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();//空方法,可重写,在队列循环之前执行
        Looper.loop();//消息队列开始循环
        mTid = -1;
    }
    ...
}

thread.start()代表着线程开启,随后通过mServiceLooper = thread.getLooper()获取Looper,mServiceHandler = new ServiceHandler(mServiceLooper)并将looper放到Handler的构造函数中。

我们都知道Handler,Looper都是属于Android消息机制中特有的类。

IntentService的本质是自动新建一个线程,并为之创建一个Looper(Android只有主线程自带Looper,其他线程不带Looper,必须自己创建)。并通过Looper向Handler传递消息,完成异步操作。
最后当Looper队列中的消息全部传达完之后,IntentService会自动销毁。

方便的不要不要的啊,把异步操作扔给IntentService,这位老哥把活干完向主线程报告了以后还会自杀,简直是根本不要操心,一条龙给你服务到位。

再看一眼onStart方法:

    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);//一般override这个方法,并将
            stopSelf(msg.arg1);
        }
    }

我们可以看到,IntentService是在onStart方法里向Handler发送消息的。

咱都清楚bindService是不跑onStart方法的。所以注意,IntentService必须使用startService。若使用bindServiceonHandleIntent方法就会失效,那就和普通Service没区别了。

  1. 启动服务绑定服务先后次序问题

无非分为两种情况:

  • 先绑定服务后开启服务
    此时就算Activity已经被销毁了,服务依旧会继续执行。

  • 先开启服务后绑定服务
    此时解绑服务也不会使服务销毁,服务会继续运行,直到停止服务。

由此可见,启动服务的优先级一直是高于绑定服务的。

这个感兴趣可以用我的demo试下:https://github.com/CocoYuki/AndroidPractice/tree/master/servicetest

  1. 远程服务AIDL

好了,讲远程服务之前我们先看下序列化。
为什么突然就扯到序列化了呢?因为接下来要总结下远程服务,用远程服务传递序列化消息也是个很常见的场景。

Q1:什么是序列化?

表示将一个对象转换成可存储或可传输的状态。

Q2:做什么用?

为了数据的持久化和可传递化。简而言之,就是对象不好操作 ,我们就把他转成流。反序列化,就是将这个流程颠倒过来,将流转成对象。

看下两种序列化的区别:

  • Parcelable
  1. google专门为安卓写的序列化接口
  2. 性能好,内存开销小,效率高,写起来复杂
  3. 缺点是各个机型可能有差异,parcelable使用会产生差异,所以通讯组件之间(AIDL,INTENT)的数据传递,可以使用Parcelable,写入存储设备推荐使用Serializable
  • Serializable
  1. java自带的序列化接口
  2. 他其实是一个空接口,使用简单,是一个标识,会给类一个序列化UID
  3. 缺点,因为使用反射,所以性能差,内存开销大

Serializable没什么好说的,非常简单,是一个空接口。主要还是看下Parcelable,他咋用。
打开源码一看,哇塞这也太贴心了吧,加点小注释顺便学习下:

 * <pre>
 * public class MyParcelable implements Parcelable {
 *     private int mData;//参数
 *      
 *     public int describeContents() {//类描述,一般不管他
 *         return 0;
 *     }
 *
 *     public void writeToParcel(Parcel out, int flags) {//序列化 :out写入参数,要注明参数类型 flag一般默认是0,1代表对象需要返回,不回收
 *         out.writeInt(mData);
 *     }
 *     
 *     public static final Parcelable.Creator&lt;MyParcelable&gt; CREATOR//反序列化操作
 *             = new Parcelable.Creator&lt;MyParcelable&gt;() {
 *         public MyParcelable createFromParcel(Parcel in) {
 *             return new MyParcelable(in);
 *         }
 *
 *         public MyParcelable[] newArray(int size) {
 *             return new MyParcelable[size];
 *         }
 *     };
 *     
 *     private MyParcelable(Parcel in) {
 *         mData = in.readInt();
 *     }
 * }</pre>

google官方也是贴心的小棉袄啊,直接把怎么用放在源码的注释里了。

但是笔者最近在学习Kotlin的啊,有更加high的办法。至于怎么high,可以看下我的kotlin小笔记,方法还是很简单的!Ctrl+f关键词 序列化(虽然文章很短,但是万一以后很长呢!)https://www.jianshu.com/p/9efe3f7a1771

OKOK,知道怎么用了,我们来看一下什么是远程服务。

他是一门接口定义语言,是 Android 提供的一种进程间通信 (IPC) 机制

其实就是用来跨进程通信的,一般都会有一个服务端提供一个服务,而让客户端去bind这个服务,而为了实现这个过程,必须使用aidl接口。

相关文章

网友评论

      本文标题:Service的生命周期

      本文链接:https://www.haomeiwen.com/subject/qaqiwctx.html