一)跨应用启动Service
有时候我们需要在一个程序里面启动另一个程序的服务,在Android5.0之前可以跟跨应用启动Activity的方法相似,使用action的隐式Intent来启动,但是现在5.0之后必须用显示Intent来启动,那么怎么显式启动一个跨程序的Service呢?
答案是通过Intent的setComponent(),传入的ComponetName()第一个参数是要启动的Service所在的程序包名,第二个通过全路径名字传入Service。这样就是显示使用Intent.
serviceIntent = new Intent();
serviceIntent.setComponent(new ComponentName("demo.com.servicetest",
"demo.com.servicetest.MyService"));
然后在按钮里就可以直接启动
btn_start.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startService(serviceIntent);
}
});
btn_stop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
stopService(serviceIntent);
}
});
二)跨应用绑定Service
先在Service里面新建一个AIDL文件,系统会自动的实现一些抽象类,然后我们可以在onBind()里返回这个AIDL文件的类型
return new IMyAidlInterface.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
};
}
如果系统没有找到这个AIDL名字,我们需要在build选项里选择ReBuild Project.
然后在另一个程序里启动Service
serviceIntent=new Intent();
serviceIntent.setComponent(new ComponentName("demo.com.servicetest","demo.com.servicetest.MyService"));
bindService= (Button) findViewById(R.id.btn_bindService);
bindService .setOnClickListener(this);
unbindService= (Button) findViewById(R.id.btn_unbindService);
unbindService.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_bindService:
bindService(serviceIntent, this, Context.BIND_AUTO_CREATE);
break;
case R.id.btn_unbindService:
unbindService(this);
}
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
System.out.println("Bind Service");
System.out.println(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
bindService()传入的三个参数,第一个是Intent,第二个是ServiceConnection,传入this需要重写它的两个方法
onServiceConnected
还有
onServiceDisconnected
第三个参数是绑定的类型
然后unbindService()传入的参数也是Service Connection.
这样就实现跨程序绑定服务了。
三)跨程序绑定Service并且通信
绑定服务的目的就是为了通信,那么如何在另一个程序里实现跨程序通信呢?答案仍然是AIDL机制。
比如我们在某个Service里打印数据出来,在已经绑定此服务的另一个程序里面进行改变数据,使Service输出的数据发生改变。
首先在AIDL文件里定义一个设置数据方法setData()
// IMyAidlInterface.aidl
package demo.com.servicetest;
// Declare any non-default types here with import statements
interface IMyAidlInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
setData(String data);
然后ReBuild Project会报错,因为在Service里面没有这个方法,我们需要在Service里声明setData(),在这个方法里实现改变数据的功能。
@Override
public IBinder onBind(Intent intent) {
return new IMyAidlInterface.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public void setData(String data) throws RemoteException {
MyService.this.data=data;
}
};
}
在Service的onCreate()里开一个线程,每隔一秒钟打印一次data,方便我们观察结果
@Override
public void onCreate() {
super.onCreate();
System.out.println("create service");
new Thread(){
@Override
public void run() {
super.run();
runing=true;
while (runing){
System.out.println(data);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
@Override
public void onDestroy() {
super.onDestroy();
System.out.println("destory service");
runing=false;
}
然后要在另一个程序里绑定Service,并且改变data的值,绑定Service的方法本文第二条刚刚写过,那么如何进行通信呢?
我们需要新建AIDL文件,并且包名要和Service所在程序的AIDL文件所在的包名一样,然后将AIDL文件复制到这个包下面即可。
然后定义AIDL对象binder,设置为null,注意在onSerivceConnected()里给binder实例化,不能直接把service赋值给它强制类型转换,因为AIDL是在两个不同的程序声明的,虽然内容一样,但是内存不一样,不是同一个,不能直接强制转换类型。
private IMyAidlInterface binder=null;
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
System.out.println("Bind Service");
System.out.println(service);
binder=IMyAidlInterface.Stub.asInterface(service);
}
在按钮的点击事件里将EditText的内容传给AIDL的setData()
注意setData要进行捕获异常,如果在Android Studio里面,alt+enter可以方便的进行捕获异常
case R.id.btn_sync:
if (binder!=null){
try {
binder.setData(et.getText().toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
这个时候编译运行程序,点击btn_sync的话,Service所在的程序就会输出我们传进去的值,而原来的值被改变,这也就是实现了跨程序绑定服务的通信功能,主要运用了安卓的AIDL机制,注意AIDL的使用方法。