IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 三 、 service生命周期 启动方式 Android 8.0后台service -> 正文阅读

[移动开发]三 、 service生命周期 启动方式 Android 8.0后台service

**Service服务:**不需要和用户交互,且需要长期运行任务的解决方案。负责后台任务,比如播放音乐,socket长连接

Service启动后默认是运行在主线程中,在执行具体耗时任务过程中要手动开启子线程,应用程序进程被杀死,所有依赖该进程的Service服务也会停止运行。

图片和部分文字转载于https://www.songyubao.com/book/primary/activity/service.html

Servcie必知必会

1.Service启动方式与生命周期

Service启动方式分为两种,普通启动startService绑定启动bindService

service

1.1 普通启动startService()

一般用于创建一个长时间持续运行的后台任务的时候才会使用,比如说socket,文件上传下载服务

普通启动startService(),它的生命周期和应用程序的生命周期一样长,只要应用程序不被杀死,服务就会一直运行 ,除非我们使用stopService()

首次启动会创建一个Service实例,依次调用onCreate()和onStartCommand()方法,此时Service 进入运行状态

如果再次调用StartService启动Service,将不会再创建新的Service对象, 系统会直接复用前面创建的Service对象,调用它的onStartCommand()方法!

这样的Service与它的调用者无必然的联系,就是说当调用者结束了自己的生命周期, 但是只要不调用stopService,那么Service还是会继续运行的!

无论启动了多少次Service,只需调用一次StopService即可停掉Service

定义Service服务

class TestService1 : Service(){

    private var TAG = "TestService1"

    override fun onCreate() {
        super.onCreate()
        Log.e(TAG,"onCreate")
    }

    override fun onBind(p0: Intent?): IBinder? {
        Log.e(TAG,"onBind")
        return null
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        Log.e(TAG,"onStartCommand")
        return super.onStartCommand(intent, flags, startId)
    }

    override fun onDestroy() {
        Log.e(TAG,"onDestroy")
        super.onDestroy()
    }
}

AndroidManifest.xml完成Service注册

<application>
	<service android:name=".TestService1"/>
</application>

在Avtivity中StartService启动服务 (要在AndroidManifest注册)

private lateinit var binding : ActivityTestServiceBinding

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    binding = ActivityTestServiceBinding.inflate(layoutInflater)
    setContentView(binding.root)

    //启动服务
    binding.startService.setOnClickListener {
        val intent = Intent(this , TestService1::class.java)
        startService(intent)
    }
    //停止服务
    binding.stopService.setOnClickListener {
        val intent = Intent(this , TestService1::class.java)
        stopService(intent)
    }
}

日志输出与结果分析

对于使用startService的方式而言,onStartCommand就是我们用于做后台任务的地方,如果我们多次点击startService按钮,会直接调onStartCommand,而不再回调onCreate

//第一次点击startService
2021-11-11 22:37:16.274 6417-6417/com.example.componentlearn E/TestService1: onCreate
2021-11-11 22:37:16.275 6417-6417/com.example.componentlearn E/TestService1: onStartCommand

//第二次点击startService
2021-11-11 22:37:20.167 6417-6417/com.example.componentlearn E/TestService1: onStartCommand

//第三次点击startService
2021-11-11 22:37:21.579 6417-6417/com.example.componentlearn E/TestService1: onStartCommand

//点击stopSevice
2021-11-11 22:37:22.612 6417-6417/com.example.componentlearn E/TestService1: onDestroy

//第四次点击startService
2021-11-11 22:37:24.957 6417-6417/com.example.componentlearn E/TestService1: onCreate
2021-11-11 22:37:24.959 6417-6417/com.example.componentlearn E/TestService1: onStartCommand

1.2绑定启动bindService()

运行一些和Activity生命周期相等的后台任务,如跨进程的通信

当首次使用bindService()启动一个Service时,系统会实例化一个Service实例,并调用其**onCreate()onBind()**方法,然后调用者就可以通过返回的IBinder对象和Service进行交互了,此后如果我们再次使用bindService绑定Service,系统不会创建新的Sevice实例,也不会再调用onBind()方法,只会直接把IBinder对象返回给调用方

如果我们解除与服务的绑定,只需调用unbindService(),此时onUnbind和onDestory方法将会被调用

bindService启动的Service服务是与调用者(Activity)相互关联的,可以理解为 “一条绳子上的蚂蚱”,要死一起死,在bindService后,一旦调用者(Activity)销毁,那么Service也立即终止

定义Service服务

class TestService2 : Service(){

    private var TAG = "TestService2"
    private var count = 0
    private var quit = false //标记位 线程退出

    override fun onCreate() {
        super.onCreate()
        Log.e(TAG,"onCreate")

        //线程开启
        Thread(Runnable {
            while(true){
                if(quit)
                    break
                Thread.sleep(1000)
                count++
            }
        }).start()
    }

    private val binder = MyBinder()

    //内部类 继承Binder类 ,Binder类实现IBinder
    inner class MyBinder : Binder(){
        fun getCount() : Int{
            return count
        }

    }

    override fun onBind(p0: Intent?): IBinder? {
        Log.e(TAG,"onBind")
        return binder
    }

    override fun onUnbind(intent: Intent?): Boolean {
        Log.e(TAG,"onUnbind")
        quit = true
        return super.onUnbind(intent)
    }

    override fun onDestroy() {
        Log.e(TAG,"onDestroy")
        super.onDestroy()
    }
}

AndroidManifest.xml中注册服务

<application>
	<service android:name=".TestService2"/>
</application>

在Activity中bindService启动服务

class TestServiceActivity : Activity(){

    private lateinit var binding : ActivityTestServiceBinding
    private var connection: ServiceConnection?=null
    private var myBinder: TestService2.MyBinder? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivityTestServiceBinding.inflate(layoutInflater)
        setContentView(binding.root)

        connection = object:ServiceConnection{
            //Activity与Service连接成功时回调该方法
            override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
                Log.e("TestService2","--------------Service  Connected--------------")
                myBinder = service as TestService2.MyBinder
            }

            override fun onServiceDisconnected(p0: ComponentName?) {
                //Activity与Service断开连接时回调该方法
                Log.e("TestService2","--------------Service  Disconnected--------------")
            }

        }

        //绑定service
        val intent = Intent(this , TestService2::class.java)
        bindService(intent , connection!! , Context.BIND_AUTO_CREATE)

        //启动服务
        binding.startService.setOnClickListener {
/*            val intent = Intent(this , TestService1::class.java)
            startService(intent)*/

            Log.e("TestService2","*********** getCount:=${myBinder?.getCount()} ***********")
        }
        //停止服务
        binding.stopService.setOnClickListener {
            //普通启动starService()
/*            val intent = Intent(this , TestService1::class.java)
            stopService(intent)*/

            //绑定启动bindService()
            unbindService(connection!!)

        }
    }

    //否则Activity会发生内存泄露
    override fun onDestroy() {
        super.onDestroy()
        unbindService(connection!!)
    }
}

日志输出与结果分析

可以在onCreate(),onBind() 开启耗时任务如线程

2021-11-13 11:25:33.264 5247-5247/com.example.componentlearn E/TestService2: onCreate
2021-11-13 11:25:33.266 5247-5247/com.example.componentlearn E/TestService2: onBind
2021-11-13 11:25:34.069 5247-5247/com.example.componentlearn E/TestService2: --------------Service  Connected--------------
2021-11-13 11:25:34.976 5247-5247/com.example.componentlearn E/TestService2: *********** getCount:=1 ***********
2021-11-13 11:25:36.415 5247-5247/com.example.componentlearn E/TestService2: *********** getCount:=3 ***********
2021-11-13 11:25:37.134 5247-5247/com.example.componentlearn E/TestService2: *********** getCount:=3 ***********
2021-11-13 11:25:38.562 5247-5247/com.example.componentlearn E/TestService2: *********** getCount:=5 ***********
2021-11-13 11:25:43.267 5247-5247/com.example.componentlearn E/TestService2: onUnbind
2021-11-13 11:25:43.267 5247-5247/com.example.componentlearn E/TestService2: onDestroy

使用BindService绑定Service,依次调用onCreate(),onBind()方法, 我们可以在onBind()方法中返回自定义的IBinder对象;再接着调用的是 ServiceConnection的onServiceConnected()方法该方法中可以获得 IBinder对象,从而进行相关操作;当Service解除绑定后会自动调用 onUnbind和onDestroyed方法,当然绑定多客户端情况需要解除所有 的绑定才会调用onDestoryed方法进行销毁哦

2.Android 8.0及以上不允许后台启动Service服务

Android 8.0 还对特定函数做出了以下变更:

  • 如果针对 Android 8.0 的应用尝试在不允许其创建后台服务的情况下使用 startService() 函数,则该函数将引发一个 IllegalStateException
  • 新的 Context.startForegroundService() 函数将启动一个前台服务。现在,即使应用在后台运行,系统也允许其调用 Context.startForegroundService()。不过,应用必须在创建服务后的五秒内调用该服务的 startForeground() 函数。

软件不可见后台超过60s不可启动service

2021-11-14 14:24:34.213 3846-3846/com.example.componentlearn E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.componentlearn, PID: 3846
    java.lang.IllegalStateException: Not allowed to start service Intent { cmp=com.example.componentlearn/.TestService2 }: app is in background uid UidRecord{89692e9 u0a121 LAST bg:+1m7s709ms idle change:cached procs:1 seq(0,0,0)}
        at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1715)

AndroidManifest.xml声明权限

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

服务启动兼容写法

TestServiceActivity 的 onCreate()

if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
    //安卓版本高于8.0   26或者Build.VERSION_CODES.O
    startForegroundService(intent)
}else{
    startService(intent)
}

TestService2中的onCreate

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    val notification = Notification.Builder(applicationContext, "channel_id").build()
    startForeground(1,notification)
}

Bug记录

  1. 跳转intent的class写成service 应该是activity的class
  2. bindService()无法绑定上服务。 原因:TestService2的onBind()返回的是null应该是binder
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-11-15 15:59:21  更:2021-11-15 16:00:37 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 3:33:15-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码