当前位置:   article > 正文

Android - Kotlin Service

kotlin service

一、基础Service 

onCreate()方法是在Service第一次创建的时候调用的,而onStartCommand()方法则 在每次启动Service的时候都会调用。

第一次点击“Start Service”按钮, Service此时还未创建过,所以两个方法都会执行,之后如果你再连续多点击几次“Start Service”按钮,你就会发现只有onStartCommand()方法可以得到执行了。

  1. class MyService : Service() {
  2. ...
  3. override fun onCreate() {
  4. super.onCreate()
  5. }
  6. override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
  7. return super.onStartCommand(intent, flags, startId)
  8. }
  9. override fun onDestroy() {
  10. super.onDestroy()
  11. }
  12. }

二、启动、停止

构建了一个Intent对象,并调用 startService()方法来启动MyService。

在“Stop Service”按钮的点击事件里,我们同样构 建了一个Intent对象,并调用stopService()方法来停止MyService。

startService()和 stopService()方法都是定义在Context类中的,所以我们在Activity里可以直接调用这两个 方法。

另外,Service也可以自我停止运行,只需要在Service内部调用stopSelf()方法即 可。

  1. class MainActivity : AppCompatActivity() {
  2. override fun onCreate(savedInstanceState: Bundle?) {
  3. super.onCreate(savedInstanceState)
  4. setContentView(R.layout.activity_main)
  5. startServiceBtn.setOnClickListener {
  6. val intent = Intent(this, MyService::class.java)
  7. startService(intent) // 启动Service
  8. }
  9. stopServiceBtn.setOnClickListener {
  10. val intent = Intent(this, MyService::class.java)
  11. stopService(intent) // 停止Service
  12. }
  13. }
  14. }

三、Activity和Service进行通信

我们新建了一个DownloadBinder类,并让它继承自Binder,然后在它的内 部提供了开始下载以及查看下载进度的方法。当然这只是两个模拟方法,并没有实现真正的功 能,我们在这两个方法中分别打印了一行日志。 接着,在MyService中创建了DownloadBinder的实例,然后在onBind()方法里返回了这个 实例,这样MyService中的工作就全部完成了。

  1. class MyService : Service() {
  2. private val mBinder = DownloadBinder()
  3. class DownloadBinder : Binder() {
  4. fun startDownload() {
  5. Log.d("MyService", "startDownload executed")
  6. }
  7. fun getProgress(): Int {
  8. Log.d("MyService", "getProgress executed")
  9. return 0
  10. }
  11. }
  12. override fun onBind(intent: Intent): IBinder {
  13. return mBinder
  14. }
  15. ...
  16. }

两个按钮分别是用于绑定和取消绑定Service的,那到底谁需要和Service绑定呢?当然就是 Activity了。当一个Activity和Service绑定了之后,就可以调用该Service里的Binder提供的 方法了。修改MainActivity中的代码

  1. class MainActivity : AppCompatActivity() {
  2. lateinit var downloadBinder: MyService.DownloadBinder
  3. private val connection = object : ServiceConnection {
  4. override fun onServiceConnected(name: ComponentName, service: IBinder) {
  5. downloadBinder = service as MyService.DownloadBinder
  6. downloadBinder.startDownload()
  7. downloadBinder.getProgress()
  8. }
  9. override fun onServiceDisconnected(name: ComponentName) {
  10. }
  11. }
  12. override fun onCreate(savedInstanceState: Bundle?) {
  13. ...
  14. bindServiceBtn.setOnClickListener {
  15. val intent = Intent(this, MyService::class.java)
  16. bindService(intent, connection, Context.BIND_AUTO_CREATE) // 绑定Service
  17. }
  18. unbindServiceBtn.setOnClickListener {
  19. unbindService(connection) // 解绑Service
  20. }
  21. }
  22. }

我们首先创建了一个ServiceConnection的匿名类实现,并在里面重写了 onServiceConnected()方法和onServiceDisconnected()方法。

onServiceConnected()方法方法会在Activity与Service成功绑定的时候调用,而 onServiceDisconnected()方法只有在Service的创建进程崩溃或者被杀掉的时候才会调 用,这个方法不太常用。那么在onServiceConnected()方法中,我们又通过向下转型得到 了DownloadBinder的实例,有了这个实例,Activity和Service之间的关系就变得非常紧密 了。现在我们可以在Activity中根据具体的场景来调用DownloadBinder中的任何public方 法,即实现了指挥Service干什么Service就去干什么的功能。

这里仍然只是做了个简单的测 试,在onServiceConnected()方法中调用了DownloadBinder的startDownload()和 getProgress()方法。 当然,现在Activity和Service其实还没进行绑定呢,这个功能是在“Bind Service”按钮的点击 事件里完成的。可以看到,这里我们仍然构建了一个Intent对象,然后调用bindService()方 法将MainActivity和MyService进行绑定。bindService()方法接收3个参数,第一个参数就 是刚刚构建出的Intent对象,第二个参数是前面创建出的ServiceConnection的实例,第三 个参数则是一个标志位,这里传入BIND_AUTO_CREATE表示在Activity和Service进行绑定后 自动创建Service。这会使得MyService中的onCreate()方法得到执行,但 onStartCommand()方法不会执行。

四、前台Service

从Android 8.0系统开始,只有当应用保持在前台可见状态的情况下,Service 才能保证稳定运行,一旦应用进入后台之后,Service随时都有可能被系统回收。而如果你希望 Service能够一直保持运行状态,就可以考虑使用前台Service。前台Service和普通Service最 大的区别就在于,它一直会有一个正在运行的图标在系统的状态栏显示,下拉状态栏后可以看 到更加详细的信息,非常类似于通知的效果

  1. class MyService : Service() {
  2. ...
  3. override fun onCreate() {
  4. super.onCreate()
  5. Log.d("MyService", "onCreate executed")
  6. val manager = getSystemService(Context.NOTIFICATION_SERVICE) as
  7. NotificationManager
  8. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
  9. val channel = NotificationChannel("my_service", "前台Service通知",
  10. NotificationManager.IMPORTANCE_DEFAULT)
  11. manager.createNotificationChannel(channel)
  12. }
  13. val intent = Intent(this, MainActivity::class.java)
  14. val pi = PendingIntent.getActivity(this, 0, intent, 0)
  15. val notification = NotificationCompat.Builder(this, "my_service")
  16. .setContentTitle("This is content title")
  17. .setContentText("This is content text")
  18. .setSmallIcon(R.drawable.small_icon)
  19. .setLargeIcon(BitmapFactory.decodeResource(resources, R.drawable.large_icon))
  20. .setContentIntent(pi)
  21. .build()
  22. startForeground(1, notification)
  23. }
  24. ...
  25. }
  26. //权限
  27. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  28. package="com.example.servicetest">
  29. <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
  30. ...
  31. </manifest>

五、IntentService

  1. class MyIntentService : IntentService("MyIntentService") {
  2. override fun onHandleIntent(intent: Intent?) {
  3. // 打印当前线程的id
  4. Log.d("MyIntentService", "Thread id is ${Thread.currentThread().name}")
  5. }
  6. override fun onDestroy() {
  7. super.onDestroy()
  8. Log.d("MyIntentService", "onDestroy executed")
  9. }
  10. }

这里首先要求必须先调用父类的构造函数,并传入一个字符串,这个字符串可以随意指定,只 在调试的时候有用。然后要在子类中实现onHandleIntent()这个抽象方法,这个方法中可以 处理一些耗时的逻辑,而不用担心ANR的问题

启动

  1. class MainActivity : AppCompatActivity() {
  2. ...
  3. override fun onCreate(savedInstanceState: Bundle?) {
  4. ...
  5. startIntentServiceBtn.setOnClickListener {
  6. // 打印主线程的id
  7. Log.d("MainActivity", "Thread id is ${Thread.currentThread().name}")
  8. val intent = Intent(this, MyIntentService::class.java)
  9. startService(intent)
  10. }
  11. }
  12. }

注册

  1. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  2. package="com.example.servicetest">
  3. <application
  4. android:allowBackup="true"
  5. android:icon="@mipmap/ic_launcher"
  6. android:roundIcon="@mipmap/ic_launcher_round"
  7. android:label="@string/app_name"
  8. android:supportsRtl="true"
  9. android:theme="@style/AppTheme">
  10. ...
  11. <service
  12. android:name=".MyIntentService"
  13. android:enabled="true"
  14. android:exported="true"/>
  15. </application>
  16. </manifest>

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号