Android Service

Service和Thread区别

Thread

        进程是系统最小资源分配单位,而线程是则是cpu调度的最小的执行单位,线程必须依赖进程,在android中启动一个app就是一个进程,我们通常所说的UI线程就是app启动后创建的主线程,线程需要的资源通过它所在的进程获取。线程可以理解成是在进程中独立运行的子任务。一旦在android的activity中创建一个线程,那它将与activity独立出来,如果一直执行耗时操作,并且activity已被finish,它还会一直执行。

Service

        android的四大组件之一,需要在清单文件进行配置,它可以理解为一个没有UI界面的Activity,长期运行在后台,和Thread相同的是它的运行也不依附于Activity,也就是说他并没有失去焦点和不可见后这种生命周期,即使应用程序退居后台,它也不会被销毁和停止运行。这就很适合做一些音乐播放和下载网络数据的功能,但是他是在主线程中执行的,在做一些耗时任务时也会造成应用程序的ANR,通常的做法都是在Service中开启子线程执行耗时操作。在用普通方式启动的服务时,当app进程被杀死,它也随之停止运行。(bind方式启动在后面)

三种方式启动服务:

        首先明确:不管是以哪种方式启动服务,同一个服务只能被创建一次,但是可以被启动多次,如果系统发生异常导致服务终止后,如果内存足够,服务所在的进程会重新创建服务。如果是用户主动销毁的,则不会重新创建。

用普通方式启动的服务:

        android这种方式是用startService()进行启动,一旦启动,该Service将不与任何组件相关,启动服务的组件已经被销毁也一直运行在后台
生命周期:onCreate()- >onStartCommand()->onDestroy()

fun test(view: View) {
        startService(Intent(this, MyService::class.java))
        stopService(Intent(this, MyService::class.java))
        startService(Intent(this, MyService::class.java))
        startService(Intent(this, MyService::class.java))
        stopService(Intent(this, MyService::class.java))
    }
class MyService: Service(){
    override fun onBind(intent: Intent?): IBinder? {
        return null
    }

    override fun onCreate() {
        super.onCreate()
        println("Service Create ThreadID:${Thread.currentThread().id}")
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        println("Service startcommand")
        return super.onStartCommand(intent, flags, startId)
    }

    override fun onUnbind(intent: Intent?): Boolean {
        return super.onUnbind(intent)
    }
    override fun onDestroy() {
        println("Service Destroy")
        super.onDestroy()
    }
}

注册:

<service
        android:name="com.example.service.MyService"
        android:enabled="true"
        android:exported="true">
    </service>
    <!--enabled:表示系统是否能够实例化(使用)该组件
    	exported:表示该服务是否能够被其他应用程序组件所调用或者交互-->

结果:

2020-11-26 10:36:19.277 23919-23919/com.example.ha I/System.out: Service Create ThreadID:2
2020-11-26 10:36:19.277 23919-23919/com.example.ha I/System.out: Service startcommand
2020-11-26 10:36:19.278 23919-23919/com.example.ha I/System.out: Service Destroy
2020-11-26 10:36:19.281 23919-23919/com.example.ha I/System.out: Service Create ThreadID:2
2020-11-26 10:36:19.281 23919-23919/com.example.ha I/System.out: Service startcommand
2020-11-26 10:36:19.281 23919-23919/com.example.ha I/System.out: Service startcommand
2020-11-26 10:36:19.282 23919-23919/com.example.ha I/System.out: Service Destroy

绑定方式启动Service

        此种方式使用bindService()启动服务,多个组件可同时绑定同一个Service,当Service没有了绑定者将会自行销毁
使用unbindService()可解除绑定
        以startService方式启动的服务基本与其他组件独立开来,但bindService不同,在 bindService(Intent service, ServiceConnection conn, int flags)方法参数中可以看到第二个参数为接口ServiceConnection, 这是让用户自定义对绑定者和Service连接状态的监听,该接口通常要重写onServiceConnected(ComponentName name,IBinder service)和onServiceDisconnected(ComponentName name)方法,其中的IBinder对象就是自定义Service中onBind函数返回的对象,通过这个对象我们就可以实现与Service之间的通信。
        生命周期:onCreate()->onBind()->onUnbind()->onDestroy()

fun test(view: View) {
        bindService(Intent(this, MyService::class.java),object :ServiceConnection{
            override fun onServiceDisconnected(name: ComponentName?) {

            }

            override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
                Toast.makeText(this@MainActivity, "连接成功", Toast.LENGTH_SHORT).show()
                val myBinder = service as MyService.MyBinder
                myBinder.test("可以")
            }

        }, Context.BIND_AUTO_CREATE) //Context.BIND_AUTO_CREATE指绑定时自动创建Service
    }
class MyService: Service(){
    val binder = MyBinder()
    override fun onBind(intent: Intent?): IBinder? {
        println("Service onBind")
        return binder
    }

    override fun onCreate() {
        super.onCreate()
        println("Service Create ThreadID:${Thread.currentThread().id}")
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {

        println("Service startcommand")
        return super.onStartCommand(intent, flags, startId)
    }

    override fun onUnbind(intent: Intent?): Boolean {
        return super.onUnbind(intent)
    }
    override fun onDestroy() {
        println("Service Destroy")
        super.onDestroy()
    }
    class MyBinder : Binder() {
        fun test(str:String){
            Log.i("Service:", str)
        }
    }
}
2020-11-26 14:06:05.905 30065-30065/com.example.ha I/System.out: Service Create ThreadID:2
2020-11-26 14:06:05.906 30065-30065/com.example.ha I/System.out: Service onBind
2020-11-26 14:06:09.311 30065-30065/com.example.ha I/System.out: Service onUnBind
2020-11-26 14:06:09.312 30065-30065/com.example.ha I/System.out: Service Destroy

混合调用

可以先startService再bindService这样就走onStartCommand()方法了
同时保证服务在后台长期运行还可进行通信,结束后应先解绑在停止服务

2020-11-26 14:08:00.294 30734-30734/com.example.ha I/System.out: Service Create ThreadID:2
2020-11-26 14:08:00.294 30734-30734/com.example.ha I/System.out: Service startcommand
2020-11-26 14:08:00.295 30734-30734/com.example.ha I/System.out: Service onBind
2020-11-26 14:08:00.875 30734-30734/com.example.ha I/System.out: Service onUnBind
2020-11-26 14:08:00.875 30734-30734/com.example.ha I/System.out: Service Destroy

Android 中进程的级别以及 Service 的优先级

  • 前台进程
    杀死前台进程需要用户交互,因为前台进程的优先级是最高的。
  • 可见进程.
    如果一个进程不含有任何前台的组件,但仍可被用户在屏幕上所见。
  • 服务进程
    进程中运行着一个service,这个service是通过 startService() 开启的,并且不属于上面两种较高优先级的情况,这个进程就是一个服务进程。
  • 后台进程
    如果进程不属于上面三种情况,但是进程持有一个用户不可见的activity
  • 空进程
    如果一个进程不包含任何活跃的应用组件,则认为是空进程。当系统进程空间紧张时,会依照优先级自动进行进程的回收。
  1. 若直接在Activity中新开一条线程来做耗时操作,当该Activity退出到桌面或其他情况时将成为一个后台进程。
  2. 若在Service中新启动线程,则此时Android会依据进程中当前活跃组件重要程度,将其判断为服务进程,优先级比(1)高。
  3. Activity中启动service,然后在Service中新启动线程,当activity退出时Service继续持有线程对象,只需重新绑定即可拿到线程对象,而不会丢失线程对象

保证Service不死常用技巧

  • 提升优先级,在清单文件的过滤器中添加属性android:priority=“1000”
  • 在onStartCommand()里面调用startForeground()把Service提升为前台进程,然后在相应地方调用stopForeground()
  • onStartCommand方法,返回START_STICKY。
    onStartCommand()方法,返回的是一个int整形。
    这个整形可以有以下四个取值:
  1. :START_STICKY:如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到service,那么参数Intent将为null。
  2. START_NOT_STICKY:“非粘性的”。如果返回START_NOT_STICKY,表示当Service运行的进程被Android系统强制杀掉之后,不会重新创建该Service。
  3. START_REDELIVER_INTENT:重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将保存下来的Intent的值传入。
  4. START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保证服务被kill后一定能重启。
  • 在onDestroy方法里发广播重启service。
  • 监听系统广播执行我们自定义的广播接收者判断Service状态
  • 将app变成系统级应用程序 清单文件加上 android:persistent=”true”,将进程设为常驻内存进程,并将APK安装到/system/app
  • 守护服务,当服务A即将死亡时开启服务B,服务B中开启并绑定服务A

Server里发消息给Activity :将Acitivity中持有Handler的对象置为静态变量

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值