定义一个service
新建一个ServiceTest项目,右键包名新建Service,将类名定义为MyService。
接下来我们尝试启动和停止Service。修改activity_main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/startServiceBtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Start Service" />
<Button
android:id="@+id/stopServiceBtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Stop Service" />
</LinearLayout>
修改MainActivity:
class MainActivity : AppCompatActivity(), View.OnClickListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val resList = listOf<View>(startServiceBtn, stopServiceBtn)
for (res in resList) {
res.setOnClickListener(this)
}
}
override fun onClick(v: View?) {
when (v?.id) {
R.id.startServiceBtn -> {
//使用intent启动服务
startService(Intent(this, MyService::class.java))
}
R.id.stopServiceBtn -> {
//使用intent停止服务
stopService(Intent(this, MyService::class.java))
}
}
}
}
Activity和Service进行通信
虽然Service是在Activity里启动的,但是在启动了Service之后,Activity与Service基本就没有什么关系了。启动之后service会一直处于运行状态,但运行的是什么逻辑,activity就控制不了了。
此时我们可以借助onBind方法,使得两者之间联系更加紧密。比如说,目前我们希望在MyService里提供一个下载功能,然后在Activity中可以决定何时开始下载,以及随时查看下载进度。
修改MyService:
class MyService : Service() {
//创建DownloadBinder的实例
private val mBinder = DownloadBinder()
//创建类继承Binder,在内部实现开始下载和获取进度的方法
class DownloadBinder : Binder() {
fun startDownload() {
Log.d("MyService", "startDownload executed")
}
fun getProgress(): Int {
Log.d("MyService", "getProgress executed")
return 0
}
}
//service创建时调用
override fun onCreate() {
super.onCreate()
}
//service每次启动时调用
//如果希望service一启动就执行某个方法,将方法放到这里
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return super.onStartCommand(intent, flags, startId)
}
override fun onDestroy() {
super.onDestroy()
}
override fun onBind(intent: Intent?): IBinder? {
//如果禁止绑定,在此处return null
//我们在此处返回了自定义binder的实例,里面包含了我们提供给activity调用的方法
return mBinder
}
}
修改完成之后,我们看看要如何在activity中调用service中的这些方法。首先修改布局文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/startServiceBtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Start Service" />
<Button
android:id="@+id/stopServiceBtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Stop Service" />
<Button
android:id="@+id/bindServiceBtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Bind Service" />
<Button
android:id="@+id/unbindServiceBtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Unbind Service" />
</LinearLayout>
新增了两个分别用于绑定和取消service的按钮,而与service绑定的,自然是activity,绑定之后就可以使用Binder中的方法了。修改MainActivity:
class MainActivity : AppCompatActivity(), View.OnClickListener {
lateinit var downloadBinder: MyService.DownloadBinder
private val connection = object : ServiceConnection {
//进程崩溃或被杀掉时才会调用,不常用
override fun onServiceDisconnected(name: ComponentName?) {
TODO("Not yet implemented")
}
//当activity与service创建连接时,会调用该方法
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
//向下转型,获得DownloadBinder的实例,进而调用里面的方法
downloadBinder = service as MyService.DownloadBinder
downloadBinder.startDownload()
downloadBinder.getProgress()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val resList = listOf<View>(startServiceBtn, stopServiceBtn, bindServiceBtn, unbindServiceBtn)
for (res in resList) {
res.setOnClickListener(this)
}
}
override fun onClick(v: View?) {
when (v?.id) {
R.id.startServiceBtn -> {
startService(Intent(this, MyService::class.java))
}
R.id.stopServiceBtn -> {
stopService(Intent(this, MyService::class.java))
}
R.id.bindServiceBtn -> {
bindService(Intent(this, MyService::class.java), connection, Context.BIND_AUTO_CREATE)
}
R.id.unbindServiceBtn -> {
unbindService(connection)
}
}
}
}