一)跨應用啓動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的使用方法。