赞
踩
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
- }
- }
- }
我们新建了一个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()方法不会执行。
从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>
- 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>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。