Service是安卓四大組件之一,先前講到了Service的生命周期,以及非綁定類型的生命周期的例子,這次來分享一下綁定形式的。
應用組件(客戶端)可以調用bindService()綁定到一個service。Android系統之後調用service的onBind()方法,它返回一個用來與service交互的IBinder。
綁定是異步的,bindService()會立即返回,它不會返回IBinder給客戶端。要接收IBinder,客戶端必須創建一個ServiceConnection的實例並傳給bindService()。ServiceConnection包含一個回調方法,系統調用這個方法來傳遞要返回的IBinder。
實現ServiceConnection
實現必須重寫兩個回調方法:
onServiceConnected()
系統調用這個來傳送在service的onBind()中返回的IBinder。
OnServiceDisconnected()
Android系統在同service的連接意外丟失時調用這個.比如當service崩潰了或被強殺了.當客戶端解除綁定時,這個方法不會被調用。
調用bindService(),傳給它ServiceConnection的實現。
當系統調用你的onServiceConnected()方法時,你就可以使用接口定義的方法們開始調用service了。
要與service斷開連接,調用unbindService()。
程序
復制代碼
public class MainActivity extends Activity {
private Button btn_start;
private Button btn_stop;
private Button btn_change;
private Button btn_bind;
private Button btn_unbind;
private MyConn myConn;
private IService myBinder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_start = (Button) findViewById(R.id.btn_start);
btn_stop = (Button) findViewById(R.id.btn_stop);
btn_change = (Button) findViewById(R.id.btn_change);
btn_bind = (Button) findViewById(R.id.btn_bind);
btn_unbind = (Button) findViewById(R.id.btn_unbind);
buttonListener bl = new buttonListener();
btn_change.setOnClickListener(bl);
btn_start.setOnClickListener(bl);
btn_stop.setOnClickListener(bl);
btn_bind.setOnClickListener(bl);
btn_unbind.setOnClickListener(bl);
}
class buttonListener implements OnClickListener
{
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_start:
Intent intent_start = new Intent(getApplicationContext(),BindService.class);
startService(intent_start);
break;
case R.id.btn_stop:
Intent intent_stop = new Intent(getApplicationContext(),BindService.class);
stopService(intent_stop);
break;
case R.id.btn_change:
if(myBinder != null)
myBinder.doChange("啦啦啦");
break;
case R.id.btn_bind:
if(myConn == null)
{
myConn = new MyConn();
Intent intent_bind = new Intent(getApplicationContext(),BindService.class);
bindService(intent_bind, myConn, BIND_AUTO_CREATE);
}
break;
case R.id.btn_unbind:
Intent intent_unbind = new Intent(getApplicationContext(),BindService.class);
if(myConn != null && myBinder != null)
{
unbindService(myConn);
myConn = null;
myBinder = null;
}
break;
default:
break;
}
}
}
private class MyConn implements ServiceConnection
{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
System.out.println("代理人返回回來了,onServiceConnected");
myBinder = (IService) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
System.out.println("接觸綁定了,onServiceDisconnected");
}
}
}
復制代碼
Service類:
復制代碼
public class BindService extends Service {
@Override
public IBinder onBind(Intent intent) {
System.out.println("Service綁定成功,onBind");
//返回自定義的代理對象
return new MyBinder();//這裡的返回是返回到MainActivity裡面的綁定myConn
}
@Override
public boolean onUnbind(Intent intent) {
System.out.println("Service解綁成功,onUnbind");
return super.onUnbind(intent);
}
public class MyBinder extends Binder implements IService
{
//間接的利用代理人調用了changeServiceThing的方法
public void doChange(String what)
{
changeServiceThing(what);
}
}
@Override
public void onCreate() {
System.out.println("Service開啟,onCreate");
super.onCreate();
}
@Override
public void onDestroy() {
System.out.println("Service關閉,onDestroy");
super.onDestroy();
}
public void changeServiceThing(String what)
{
Toast.makeText(getApplicationContext(), what+"變換了,changeServiceThing", Toast.LENGTH_LONG).show();
}
}
復制代碼
IService:
public interface IService {
public void doChange(String what);
}
結果
點擊“開啟服務”之後,再“綁定服務”,這樣執行之後直接點“關閉服務”是沒用的,要先“解除服務”,再“關閉服務”。如果直接“綁定服務”,那麼點擊“關閉服務”沒有用,需要點擊“解綁服務”。
aidl
進程間通信->調用者和Service如果不在一個進程內,就需要使用android中的遠程Service調用機制。
android使用AIDL定義進程間的通信接口。AIDL的語法與java接口類似,需要注意以下幾點:
AIDL文件必須以.aidl作為後綴名。
AIDL接口中用到的數據類型, 除了基本類型, String, List, Map, CharSequence之外, 其他類型都需要導包, 即使兩種在同一個包內. List和Map中的元素類型必須是AIDL支持的類型。
接口名需要和文件名相同。
方法的參數或返回值是自定義類型時, 該自定義的類型必須實現了Parcelable接口。
所有非java基本類型參數都需要加上in, out, inout標記, 以表明參數是輸入參數, 輸出參數, 還是輸入輸出參數。
接口和方法前不能使用訪問修飾符和static, final等修飾。
進程間通信需要創建aidl文件,IService.aidl:
public interface IService {
public void doChange(String what);
}
接口中有一個static的抽象內部類Stub,Stub類繼承了Binder類並實現了IRemoteService接口。
復制代碼
public class MainActivity extends Activity {
private Intent intent;
private IService iService;
private ServiceConnection myConn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void bind(View view) {
intent = new Intent();
intent.setAction("com.yydcdut.alipay");
myConn = new MyConn();
boolean flag = bindService(intent, myConn, BIND_AUTO_CREATE);
System.out.println("flag------>" + flag);
}
private class MyConn implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iService = IService.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
public void method(View view) {
try {
iService.callMethodInService();
} catch (RemoteException e) {
// TODO 自動生成的 catch 塊
e.printStackTrace();
}
}
}