Android - Kotlin Service

一、基础Service 

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

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

class MyService : Service() {
 ...
 override fun onCreate() {
 super.onCreate()
 }
 override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
 return super.onStartCommand(intent, flags, startId)
 }
 override fun onDestroy() {
 super.onDestroy()
 }
}

二、启动、停止

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

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

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

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

class MainActivity : AppCompatActivity() {
 override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_main)
 startServiceBtn.setOnClickListener {
 val intent = Intent(this, MyService::class.java)
 startService(intent) // 启动Service
 }
 stopServiceBtn.setOnClickListener {
 val intent = Intent(this, MyService::class.java)
 stopService(intent) // 停止Service
 }
 }
}

三、Activity和Service进行通信

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

class MyService : Service() {
 private val mBinder = DownloadBinder()
 class DownloadBinder : Binder() {
 fun startDownload() {
 Log.d("MyService", "startDownload executed")
 }
 fun getProgress(): Int {
 Log.d("MyService", "getProgress executed")
 return 0
 }
 }
 override fun onBind(intent: Intent): IBinder {
 return mBinder
 }
 ...
}

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

class MainActivity : AppCompatActivity() {
 lateinit var downloadBinder: MyService.DownloadBinder
 private val connection = object : ServiceConnection {
 override fun onServiceConnected(name: ComponentName, service: IBinder) {
 downloadBinder = service as MyService.DownloadBinder
 downloadBinder.startDownload()
 downloadBinder.getProgress()
 }
 override fun onServiceDisconnected(name: ComponentName) {
 }
 }
 override fun onCreate(savedInstanceState: Bundle?) {
 ...
 bindServiceBtn.setOnClickListener {
 val intent = Intent(this, MyService::class.java)
 bindService(intent, connection, Context.BIND_AUTO_CREATE) // 绑定Service
 }
 unbindServiceBtn.setOnClickListener {
 unbindService(connection) // 解绑Service
 }
 }
}

我们首先创建了一个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最 大的区别就在于,它一直会有一个正在运行的图标在系统的状态栏显示,下拉状态栏后可以看 到更加详细的信息,非常类似于通知的效果

class MyService : Service() {
 ...
 override fun onCreate() {
 super.onCreate()
 Log.d("MyService", "onCreate executed")
 val manager = getSystemService(Context.NOTIFICATION_SERVICE) as
 NotificationManager
 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
 val channel = NotificationChannel("my_service", "前台Service通知",
 NotificationManager.IMPORTANCE_DEFAULT)
 manager.createNotificationChannel(channel)
 }
 val intent = Intent(this, MainActivity::class.java)
 val pi = PendingIntent.getActivity(this, 0, intent, 0)
 val notification = NotificationCompat.Builder(this, "my_service")
 .setContentTitle("This is content title")
 .setContentText("This is content text")
 .setSmallIcon(R.drawable.small_icon)
 .setLargeIcon(BitmapFactory.decodeResource(resources, R.drawable.large_icon))
 .setContentIntent(pi)
 .build()
 startForeground(1, notification)
 }
 ...
}

//权限
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 package="com.example.servicetest">
 <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
 ...
</manifest>

五、IntentService

class MyIntentService : IntentService("MyIntentService") {
 override fun onHandleIntent(intent: Intent?) {
 // 打印当前线程的id
 Log.d("MyIntentService", "Thread id is ${Thread.currentThread().name}")
 }
 override fun onDestroy() {
 super.onDestroy()
 Log.d("MyIntentService", "onDestroy executed")
 }
}

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

启动

class MainActivity : AppCompatActivity() {
 ...
 override fun onCreate(savedInstanceState: Bundle?) {
 ...
 startIntentServiceBtn.setOnClickListener {
 // 打印主线程的id
 Log.d("MainActivity", "Thread id is ${Thread.currentThread().name}")
 val intent = Intent(this, MyIntentService::class.java)
 startService(intent)
 }
 }
}

注册

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 package="com.example.servicetest">
 <application
 android:allowBackup="true"
 android:icon="@mipmap/ic_launcher"
 android:roundIcon="@mipmap/ic_launcher_round"
 android:label="@string/app_name"
 android:supportsRtl="true"
 android:theme="@style/AppTheme">
 ...
 <service
 android:name=".MyIntentService"
 android:enabled="true"
 android:exported="true"/>
 </application>
</manifest>

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值