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(); } } }
在實現這個的時候我建立了兩個程序,這樣可以做到進程間通信。附帶了源碼。
我是天王蓋地虎的分割線
源代碼:http://pan.baidu.com/s/1dD1Qx01
service學習2.zip
aidl學習.zip
aidl學習配套2.zip
轉載請注明出處:http://www.cnblogs.com/yydcdut
