导读
学习了几天kotlin,想着实践下试试手,于是乎就想起了aidl,好吧,就拿它练练
1.服务的两种开启方式
2.使用AIDL调用远程服务
ps:AndroidStudio还没配置好Kotlin开发环境的童鞋,可以先移步 AndroidStudio使用kotlin入门
Android进程间通讯
进程间通讯,可以理解为两个不同进程间进行数据交互的一个行为,AIDL是android特有的一种调用远程服务方式
一、先复习下服务的两种开启方式
服务的开启方式有两种,一种是直接startService,另一种是bindServeice;两者的区别呢?
前者:服务长期后台运行,不可以调用服务里面的方法
后者:可以调用服务的方法,但是不能长期后台运行
因为我们是需要进行进程间通讯,所有需要使用到服务里面的方法,这里主要是回顾下绑定服务,除了以下代码外,别忘了service是需要注册清单文件哦
1-1、Deservice里面的代码
import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.IBinder
import android.util.Log
class DemoService : Service() {
val TAG :String = "DemoService";
override fun onBind(intent: Intent?): IBinder {
Log.v(TAG,"服务绑定成功");
return DemoBinder();
}
class DemoBinder : Binder() {
fun callService(a:Int,b:Int): String? {
var result :String? = null;
result = "服务端收到,这是给你的回复 a+b= ${a+b}"
return result;
}
}
}
1-2、MainActivity里面的代码
import android.content.ComponentName
import android.content.Intent
import android.content.ServiceConnection
import android.os.Bundle
import android.os.IBinder
import android.support.annotation.IntegerRes
import android.support.v7.app.AppCompatActivity
import android.text.TextUtils
import android.util.Log
import android.view.View
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity(), View.OnClickListener,ServiceConnection {
private val TAG = "MainActivity"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btn_bind.setOnClickListener(this)
btn_unbind.setOnClickListener(this)
}
override fun onClick(v: View?) {
when(v?.id){
R.id.btn_bind -> {
if (et1.text.toString().isEmpty()||et2.text.toString().isEmpty()){
Toast.makeText(this,"请输入内容哦",Toast.LENGTH_SHORT).show()
return
}
val intent = Intent(this, DemoService::class.java)
bindService(intent,this,BIND_AUTO_CREATE)
}
}
}
//当服务失去连接时调用
override fun onServiceDisconnected(name: ComponentName?) {
}
//当服务被成功连接的时候调用的方法
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
var binder : DemoService.DemoBinder = service as DemoService.DemoBinder;
val serviceInfo:String = binder.callService(a = parseInt(et1.text.toString())!!, b = parseInt(et2.text.toString())!!)!!;
if(!TextUtils.isEmpty(serviceInfo)){
Toast.makeText(this,serviceInfo,Toast.LENGTH_SHORT).show();
}
}
fun parseInt(s: String): Int? {
if(s == null || s == "")
return null;
return Integer.parseInt(s);
}
override fun onDestroy() {
super.onDestroy()
unbindService(connection);
}
}
1-3.activity_main.xml
二.使用AIDL调用远程服务
还记得Java中我们是如何使用AIDL的吗?
1.服务端,创建aidl接口文件,暴露需要让客户端调用的方法
2.服务端,创建好服务类,并且在清单文件中配置好服务的action
3.服务端,实现aidl接口类,以*****.Stub()
的方式,重写需要暴露给客户端调用的方法
4.客户端,复制服务端aidl文件到项目中,必须包名一致
5.客户端,bind方式开启远程服务,用*****.Stub.asInterface(service)
方法获取aidl接口类的实例
6.客户端,使用获取到的aidl接口类实例调用远程服务方法
7.客户端,onDestory方法中,解除注册绑定服务
1.服务端,创建AIDL文件,这里需要注意下,使用AS提供的方式去创建,不要手动自己创建,否则后面会问有题,这点和之前eclipse有点不一样
1-1.aidl接口类的代码
// IMyAidlInterface.aidl
package com.example.myapplication.aidl;
interface IMyAidlInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
String callService(int a,int b);
}
2.服务端,Service代码
package com.example.myapplication
import android.app.Service
import android.content.Intent
import android.os.IBinder
import android.util.Log
import com.example.myapplication.aidl.IMyAidlInterface
class DemoService : Service() {
val TAG :String = "DemoService";
override fun onBind(intent: Intent?): IBinder {
Log.v(TAG,"服务绑定成功");
return DemoBinder();
}
class DemoBinder : IMyAidlInterface.Stub() {
override fun callService(a:Int,b:Int): String? {
var result :String? = null;
result = "服务端收到,这是给你的回复 a+b= ${a+b}"
return result;
}
}
}
3.客户端,复制服务的aidl文件,包名必须保持一致
4.客户端Activity代码,activity_main.xml的代码就不贴了,其实就两个Button和两个EditText
class MainActivity : AppCompatActivity(), View.OnClickListener {
private val TAG = "MainActivity"
var iservice : IMyAidlInterface? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btn_bind.setOnClickListener(this)
btn_call.setOnClickListener(this)
}
override fun onClick(v: View?) {
when(v?.id){
R.id.btn_bind -> {
bind();
}
R.id.btn_call ->{
if (et1.text.toString().isEmpty()||et2.text.toString().isEmpty()){
Toast.makeText(this,"请输入内容哦",Toast.LENGTH_SHORT).show()
return
}
callServiceMethod()
}
}
}
/**
* 绑定远程服务
* @param view
*/
fun bind() {
//android5.0以下才能用下面的方式开启远程服务,5.0以上则不支持隐式调用服务,否则会报错
// val service = Intent()
// service.action = "com.example.myapplication"
// bindService(service, this, BIND_AUTO_CREATE)
//5.0以上需要使用下面的代码实现隐式调用
val intent = Intent()
intent.action = "com.example.myapplication"
val eintent = Intent(createExplicitFromImplicitIntent(this, intent))
bindService(eintent, connection, Service.BIND_AUTO_CREATE)
}
fun callServiceMethod(){
val serviceInfo:String = iservice?.callService(parseInt(et1.text.toString())!!, parseInt(et2.text.toString())!!)!!;
if(!TextUtils.isEmpty(serviceInfo)){
Toast.makeText(this,serviceInfo,Toast.LENGTH_SHORT).show();
}
}
fun parseInt(s: String): Int? {
if(s == null || s == "")
return null;
return Integer.parseInt(s);
}
var connection = object :ServiceConnection{
//当服务失去连接时调用
override fun onServiceDisconnected(name: ComponentName?) {
Toast.makeText(this@MainActivity,"解绑服务成功",Toast.LENGTH_SHORT).show()
}
//当服务被成功连接的时候调用的方法
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
iservice = IMyAidlInterface.Stub.asInterface(service);
Toast.makeText(this@MainActivity,"服务绑定成功",Toast.LENGTH_SHORT).show()
}
}
fun createExplicitFromImplicitIntent(context : Context, implicitIntent :Intent ):Intent?{
val pm = context.packageManager
val resolveInfo = pm.queryIntentServices(implicitIntent, 0)
if (resolveInfo == null || resolveInfo.size != 1) {
return null
}
val serviceInfo = resolveInfo[0]
val packageName = serviceInfo.serviceInfo.packageName
val className = serviceInfo.serviceInfo.name
val component = ComponentName(packageName, className)
val explicitIntent = Intent(implicitIntent)
explicitIntent.setComponent(component)
return explicitIntent
}
override fun onDestroy() {
super.onDestroy()
unbindService(connection);
}
}