安卓service使用(一)

如题,本文将简述,同一个进程内,service如何创建,绑定等操作。

首先,service是什么?

官方描述:

A Service is an application component representing either an application’s desire to perform a longer-running operation while not interacting with the user or to supply functionality for other applications to use. Each service class must have a corresponding [<service>](https://developer.android.google.cn/reference/android/R.styleable#AndroidManifestService) declaration in its package’s AndroidManifest.xml. Services can be started with [Context.startService()](https://developer.android.google.cn/reference/android/content/Context#startService(android.content.Intent)) and [Context.bindService()](https://developer.android.google.cn/reference/android/content/Context#bindService(android.content.Intent,%20android.content.ServiceConnection,%20int)).

通俗一点,service可以理解为一个摸不着的东西,他区别于界面,运行在后台。

service的主要使用方法

1、startService()–用于启动service
2、stopService()–用于停止service
3、bindService()–绑定service
4、unBindService()–解绑service
要点:
(1)startService()和stopService(),bindService()和unBindService()都是成对出现的。
(2)首次使用startService(),service的onCreate()方法会执行,然后onStartCommand(),若无取消service()操作,后续再多次调用startService()方法时,service只会多次执行onStartCommand()方法。
(3)bindService()用于绑定service,结合ServiceConnection方法,实现绑定并且可以初始化一个绑定后的对象,用于调用binder方法。
(4)如果先调用bindService(),则service的生命周期方法执行顺序为:onCreate()–>onBind()。
(5)如果调用了startService()和bindService()方法,则后续需要同时调用unBindService()和stopService()用于取消绑定和停止service。
(6)注意在service不再使用的时候,及时释放service,避免导致内存泄漏
(7)注意安卓不同版本之间,service的适配
(8)使用service时,注意权限的申请

案例一

使用startService()和stopService()
代码地址
本次案例,主要调用startService()和stopService()两个方法,用于启动和取消service。
首先,看看service的实现:

//
 class FirstService( override val channelName: String =javaClass::class.java.simpleName,override val getChannelId: Int =javaClass.hashCode()) : BaseServiceCompat() { override fun onCreate() {
        super.onCreate()
        KtLogUtil.d("service onCreate")
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        KtLogUtil.d("service onStartCommand")
        return super.onStartCommand(intent, flags, startId)
    }

    override fun onDestroy() {
        KtLogUtil.d("service onDestroy")
        super.onDestroy()
    }

    override fun onBind(intent: Intent): IBinder? {
        KtLogUtil.d("service onBind")
        return null
    }
}
//

该service继承自BaseServiceCompat,父类主要是适配了不同安卓版本启动service的方法,主要核心代码,就是若当前版本大于android.O,启动service的方法为startForegroundService(),并且在创建service的时候,调用startForeground发出一个前台通知。具体实现代码如下:

fun startService(context: Context, intent: Intent?) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                //适配安卓8.0
                context.startForegroundService(intent)
            } else {
                context.startService(intent)
            }
        }
override fun onCreate() {
        super.onCreate()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            try {
                //适配安卓8.0
                val channelId = getChannelId
                val channelName = channelName
                val channel = NotificationChannel(
                    channelId.toString(),
                    channelName,
                    NotificationManager.IMPORTANCE_MIN
                )
                val manager = applicationContext.getSystemService(NOTIFICATION_SERVICE) as NotificationManager
                manager.createNotificationChannel(channel)
                startForeground(channelId, notification)
            } catch (e: Exception) {
            }
        }
    }

而在MainActivity里面,我们直接调用即可:
代码如下图:

private fun initEvent() {
        findViewById<Button>(R.id.start_service).setOnClickListener {

            //显式开启
            val serviceIntent = Intent(this, FirstService::class.java)


//            //隐式开启--区别于显式, 需要在manifest中声明相关action参数
//            val serviceIntent = Intent()
//            serviceIntent.setAction("com.north.light.androidservice.FirstService")
//            serviceIntent.setPackage("com.north.light.androidservice")



            //启动service--android 8.0 service的启动方式有改变,需要适配
            //8.0 ps:在系统创建服务后,应用有五秒的时间来调用该服务的 startForeground() 方法以显示新服务的用户可见通知。
            //使用封装好的base service compat用于启动service
            BaseServiceCompat.startService(this, serviceIntent)
        }

        findViewById<Button>(R.id.stop_service).setOnClickListener {
            val serviceIntent = Intent(this, FirstService::class.java)
            //关闭service
            stopService(serviceIntent)
        }
    }

可以从上图看出,启动service,有两种方法:
第一个就是直接通过Service的对象作为intent初始化传参进行启动(显式调用)
第二个就是指定intent的action和package进行调用(隐式调用)
对于方法二:需要在manifest文件中,声明action

       <service
            android:name=".FirstService"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.north.light.androidservice.FirstService" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </service>

声明以后才可以进行隐式调用。
对于service的参数声明析意如下:

enable:表示是否启用该服务
exported:表示是否允许除了当前程序之外的其他程序访问这个服务
process:是否需要在单独的进程中运行,当设置为android:process=”:remote”时,代表Service在单独的进程中运行。
ps:很重要,它的意思是指要在当前进程名称前面附加上当前的包名,
所以“remote”和”:remote”不是同一个意思,前者的进程名称为:remote,而后者的进程名称为:App-packageName:remote。
对于intent-filter参数,常用于外部调用(隐式调用的情况下声明)

至此,已经完成了service的startService()和stopService()的实现了

##案例二
在案例一的基础上,进行bindservice操作,并且通过binder调用service的方法
代码链接
实际项目中,建议调用的service方法顺序为:
1、startService()
2、bindService()
3、unBindService()
4、stopService()
本次案例调用service的顺序也是如上。
首先,service里面定义一个binder,如下图:

    inner class FirstBinder : Binder() {

        fun getService(): FirstService {
            return this@FirstService
        }

        /**
         * 发送消息
         * */
        fun sendMessage(toString: String) {
            mListener.forEach {
                it.result("收到了,返回给你:${toString}")
            }
        }

        fun setOnListener(listener: FirstServiceListener) {
            mListener.add(listener)
        }

        fun removeListener(listener: FirstServiceListener) {
            mListener.remove(listener)
        }
    }

再在service的onBind()方法中,返回该binder的实例,至此,service的定义基本完成。
下面看看如何实现bindService()的。

        findViewById<Button>(R.id.bind_service).setOnClickListener {
            val serviceIntent = Intent(this, FirstService::class.java)
            //绑定service
            serConnect = object : ServiceConnection {
                override fun onServiceConnected(p0: ComponentName?, p1: IBinder?) {
                    KtLogUtil.d("绑定了 service ")
                    mBinder = (p1 as FirstService.FirstBinder)
                    mBinder?.setOnListener(mBinderListener)
                }

                override fun onServiceDisconnected(p0: ComponentName?) {
                    mBinder = null
                    KtLogUtil.d("解绑了 service ")
                }
            }
            bindService(serviceIntent, serConnect!!, BIND_AUTO_CREATE)
        }

这里直接通过一个ServiceConnect即可实现bind service。里面有连接成功和断开连接的返回,这里只做案例实现,实际中需要在断开连接的时候,加上重连机制。
在onServiceConnected()方法中,能初始化binder,该binder则可以用作后续调用service方法的操作了。

that’s all--------------------------------------------------------------------

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值