混合方式启动和销毁service梳理

        正常情况下,启动一个service有两种方式,即startService()或bindService()。但两种方式各有优缺点,看如下表格:

启动方式优点缺点生命周期特点
startService服务可以长期在后台运行

不能进行通讯

(需要借助广播实现通信)

onCreate()------>onStrartCommand() ------>onDestroy()oncreate()方法只会启动一次,如果服务已经启动,onCreate()方法不会再被执行,除非被onDestroy了
bindService可以进行通讯服务无法长期在后台运行,不然会导致context泄漏,如果解绑了服务则停止运行onCreate()------>onBind()------>onUnBind()------>onDestroy该方法下多次绑定会有异常(crash)

        为了结合两种方式的优点,所以还有第三种特殊方式,即混合方式。下面通过代码打log方式来看看混合方式不同的启动顺序和销毁顺序会有什么影响。

一、代码 

        1、TestServiceActivity 共5个按钮,分别是startService、 stopService、 bindService 、 unBindService 和checkServiceLiveState。

class TestServiceActivity : AppCompatActivity() {

    val TAG = TestServiceActivity::class.java.simpleName

    private var binder : Binder? = null;
    private lateinit var conn : ServiceConnection

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_test_service)

        var intent = Intent(this, TestServiceStratMode::class.java)

        start.setOnClickListener {
            startService(intent)
        }

        conn = object : ServiceConnection {
            override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
                binder =  service as TestServiceStratMode.MyBinder
            }

            override fun onServiceDisconnected(name: ComponentName?) {
            }
        }

        bind.setOnClickListener {
            bindService(intent, conn as ServiceConnection, Service.BIND_AUTO_CREATE)
        }

        stop.setOnClickListener {
            stopService(intent)
        }

        unbind.setOnClickListener {
            unbindService(conn)
        }

        checkSerivce.setOnClickListener {
            var exist = isServiceRunning(this, "TestServiceStratMode")
            Log.e(TAG, "isServiceRunning: ${exist}", )
        }

    }

    override fun onDestroy() {
        super.onDestroy()
        Log.e(TAG, "onDestroy: activity被销毁", )
    }


    /**
     * 判断服务是否在运行
     * @param mContext
     * @param className  Service.class.getName();
     * @return
     */
    public  fun isServiceRunning(mContext: Context, className: String): Boolean {
        var isRunning :Boolean = false
        var activityManager = mContext.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
        var seviceList = activityManager.getRunningServices(200)
        if (seviceList.size <= 0) {
            return false
        }
        for (i in seviceList.indices) {
            if (seviceList[i].service.className.contains(className)) {
                Log.e(TAG, "isServiceRunning: ${seviceList[i].service.className}", )
                isRunning = true
                break
            }
        }
        return isRunning
    }
}

   相关布局为:        

      2、TestServiceStratMode 继承Service

        可以看到,service的主要几个生命周期函数都打上了log。

public class TestServiceStratMode extends Service {

    private final String TAG = TestServiceStratMode.class.getSimpleName();
    private MyBinder binder = new MyBinder();

    public class MyBinder extends Binder {

    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e(TAG, "onCreate: ");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e(TAG, "onStartCommand: " );
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "onDestroy: ");
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.e(TAG, "onUnbind: " );
        return super.onUnbind(intent);
    }

    @Override
    public void onRebind(Intent intent) {
        super.onRebind(intent);
        Log.e(TAG, "onRebind: ");
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.e(TAG, "onBind: ");
        return binder;
    }
}

二、混合启动循序和销毁顺序对service的影响

        我主要是想验证混合启动service时先调用startService和后调用startService, 销毁service时的顺序会不会对service有影响。

2.1 先startService,后bindService

情况1:startService->bindService->按back键返回主页面

        1、点击了“启动服务”按钮,然后再点击了”绑定服务“按钮,输入log如下

 E/TestServiceStratMode: onCreate: 
 E/TestServiceStratMode: onStartCommand: 
 E/TestServiceStratMode: onBind: 

        2、点击“检查是否在服务运行”查看service运行状态 ,输入log如下。可以看到service被启动起来了;              

E/TestServiceActivity: isServiceRunning: com.example.helloworld.service.TestServiceStratMode
E/TestServiceActivity: isServiceRunning: true

        3、按返回键退出当前activity回到手机主页面,输入log如下。可以看到离开activity(注意:按返回键退出activity,activity会被系统销毁),service会自动解绑。

E/TestServiceActivity: onDestroy: activity被销毁
E/TestServiceStratMode: onUnbind: 

     停留在主页面大概2分钟,会发现service的onDestroy被调用了,这是因为默认情况下通过返回键方式退出app,activity不久后会被系统自动销毁。所以service也跟着被销毁了。

        这是因为系统检测到service超过1分钟为idle状态,就会把service杀死!可以看我的另外一篇文章,里面有介绍。

E/TestServiceStratMode: onDestroy:
W/ActivityManager: Stopping service due to app idle: u0a162 -1m4s830ms com.example.helloworld/.service.TestServiceStratMode

 4、点击主页面app按钮进入应用,点击“检查是否在服务运行”查看service运行状态,可以看到service已经被销毁了。

E/TestServiceActivity: isServiceRunning: false

情况2:startService->bindService->按home键返回主页面

       按home键退出activity,activity不会被销毁。 log输出如下

E/TestServiceStratMode: onCreate: 
E/TestServiceStratMode: onStartCommand: 
E/TestServiceStratMode: onBind: 

        在主页面等待2分钟左右,查看到系统检测servce空闲超过1分钟,尝试杀死srevice

W/ActivityManager: Stopping service due to app idle: u0a162 -1m4s830ms com.example.helloworld/.service.TestServiceStratMode

        但是却迟迟没有打印service的onDestroy的log

        点击app图标进入app,点击“检查是否在服务运行”查看service运行状态,发现service还在运行,可见activity没有被杀死的情况下,系统是杀不死处于空闲状态的service的。

E/TestServiceActivity: isServiceRunning: com.example.helloworld.service.TestServiceStratMode
E/TestServiceActivity: isServiceRunning: true

情况3:startService->bindService->stopService->unBindService

        1、startService->bindService之后的log还和上面一样,省略;

        2、按下stopService按钮,没有日志输入,说明不会调用service的onDestroy

        3、按下unBindService,输入日志如下,可见service先解绑,然后理解销毁了。

E/TestServiceStratMode: onUnbind: 
E/TestServiceStratMode: onDestroy: service被销毁

        4、如果再按一次unBindService,则app闪退,提示服务还没有注册!异常堆栈如下:

2022-08-07 16:40:12.639 26111-26111/com.example.helloworld E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.helloworld, PID: 26111
    java.lang.IllegalArgumentException: Service not registered: com.example.helloworld.activity.testservice.TestServiceActivity$onCreate$2@1a4e4d3
        at android.app.LoadedApk.forgetServiceDispatcher(LoadedApk.java:1570)
        at android.app.ContextImpl.unbindService(ContextImpl.java:1703)
        at android.content.ContextWrapper.unbindService(ContextWrapper.java:727)
        at android.content.ContextWrapper.unbindService(ContextWrapper.java:727)
        at com.example.helloworld.activity.testservice.TestServiceActivity.onCreate$lambda-3(TestServiceActivity.kt:53)
        at com.example.helloworld.activity.testservice.TestServiceActivity.lambda$m7agMTyK08cETcAMBs4lITGG1bM(Unknown Source:0)
        at com.example.helloworld.activity.testservice.-$$Lambda$TestServiceActivity$m7agMTyK08cETcAMBs4lITGG1bM.onClick(Unknown Source:2)
        at android.view.View.performClick(View.java:6614)
        at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1119)
        at android.view.View.performClickInternal(View.java:6587)
        at android.view.View.access$3100(View.java:787)
        at android.view.View$PerformClick.run(View.java:26122)
        at android.os.Handler.handleCallback(Handler.java:873)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:201)
        at android.app.ActivityThread.main(ActivityThread.java:6820)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:922)

情况4:startService->bindService->unBindService-> stopService

        1、startService->bindService之后的log还和上面一样,省略;

        2、按下unBindService按钮,输入日志如下,可见service被解绑

E/TestServiceStratMode: onUnbind:

        3、按下stopService,输入日志如下,可见service销毁了。

E/TestServiceStratMode: onUnbind:

        4、如果再第二步后又点击unBindService按钮,也会报异常。

综合情况3、4可见 ,混合方式启动的service,销毁时对unBindService和stopService的顺序没有要求。

2.2 先bindService,后startService

情况1:销毁顺为:stopService->unbindService

         1、bindService->startService,输出日志为

E/TestServiceStratMode: onCreate: 
E/TestServiceStratMode: onBind: 
E/TestServiceStratMode: onStartCommand: 

        2、stopService,输出日志为空;

        3、unbindService,输出日志为:

E/TestServiceStratMode: onUnbind: 
E/TestServiceStratMode: onDestroy: service被销毁

情况1:销毁顺为:unbindService->stopService

    1、bindService->startService,输出日志为

E/TestServiceStratMode: onCreate: 
E/TestServiceStratMode: onBind: 
E/TestServiceStratMode: onStartCommand: 

        2、unbindService,输出日志为

E/TestServiceStratMode: onUnbind: 

        3、stopService,输出日志为

E/TestServiceStratMode: onDestroy: service被销毁

三、总结

        综合上面案例,可见其实两种混合启动方式效果都是一样的,两种混合销毁service的效果也都是一样的。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值