7.0 android中Service的基础知识

service的定义:

Service 是一个在后台执行长时间运行操作而不提供用户界面的组件。

允许在用户没有与应用交互时操作,或者执行一些用户交互之外的操作,如音乐播放、文件上传、文件下载等。
Service的使用不影响用户的交互,且由其他组件(如Activity、Fragment等)启动

Service必须在Manifest中进行定义。

service的特点:

  • 适合执行不需要和用户交互而且还要求长期运行的任务
  • 依赖于创建Service时所在的应用程序进程
  • 默认运行在主线程当中的,不能直接执行耗时操作,需要开启子线程

Service 直接启动

启动

通过startService启动Service

停止

通过stopService停止Service
在Service中可以通过stopSelf()停止Service。

示例

下列代码示例中,设置两个按钮执行开始Service和结束Service

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
        }
    }

}

Service 绑定启动

假设执行一个后台下载的功能

定义Service

  • 在service中设置一个继承Binder()的类,并在Service中创建变量mBinder为其实例。

  • 在Service中的方法onBind中返回mBinder,用于Activity与Service之间绑定。

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
    }
    ...
}

绑定

在Activity中,设置Service中定义的Binder类,并通过匿名类ServiceConnection中的onServiceConnected,设置为绑定运行的Service。

启动

在Activty中通过bindService进行绑定启动Service,

停止

通过unbindService进行解绑停止Service的操作。

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
        }
    }

}

注意

虽然每调用一次startService()方法,onStartCommand()就会执行一次,但实际上每个Service只会存在一个实例。所以不管你调用了多少次startService()方法,只需调用一次stopService()或stopSelf()方法,Service就会停止。

在同一个Activity中,如果同时通过startService、bindService启动同一个Service,停止Service的话,需要同时通过unbindService和stopService对Service进行解绑和停止的操作。

生命周期

对于Service的生命周期,
方法onCreate只在第一次创建时调用;

方法onStartCommand在使用startService启动Service都会调用;

方法onBind在使用bindService启动ServiceService都会调用。

也就是说,使用不同的方法启动Service,调用Service的生命周期的方法是不一样的,如果需要在Service每次启动时执行一定操作,要注意方法是否调用正确。

前台service

从Android 8.0系统开始,只有当应用保持在前台可见状态的情况下,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)
    }
    ...
}

IntentService

Service中的代码都是默认运行在主线程当中的,如果直接在Service里处理一些耗时的逻辑,就很容易出现ANR(Application Not Responding)的情况。
为了可以简单地创建一个异步的、会自动停止的Service,Android专门提供了一个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")
    }

}

实际其相对于如下代码:

class MyService : Service() {
    ...
    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        thread {
            // 处理具体的逻辑
            stopSelf()
        }
        return super.onStartCommand(intent, flags, startId)
    }
}

步骤

①先调用父类的构造函数
②在子类中实现onHandleIntent()这个抽象方法,这个方法中可以处理一些耗时的逻辑,而不用担心ANR的问题,因为这个方法已经是在子线程中运行的了

  • 25
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值