標籤:查看 creat hat androi 返回 implicit bin 技術 auto
跨進程通訊可以用AIDL語言
這裡講述下如何使用AIDL語言進行跨進程通訊
文章參考 《設計模式》一書
demo結構參考
主要的檔案類有:IBankAidl.aidl
java檔案:AidlBankBinder,BackActivity(應該是BankActivity寫錯了),BankService(繼承自Service,服務類)
IBankAidl.aidl檔案 這裡AIdl的使用對包位置有要求,所以我就把包名放出來了
package finishdemo.arcturis.binderandserviceandaidl.binder;// Declare any non-default types here with import statementsinterface IBankAidl { /** * 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); /** * 開戶 * @param name 戶主名 * @param password 密碼 * @return 開戶資訊 */ String openAccount(String name,String password); /** * 存錢 * @param money * @param account * @return */ String saveMoney(int money,String account); /** * 取錢 * @param money * @param account * @param password * @return */ String takeMoney(int money,String account,String password); /** * 銷戶 * @param account * @param password * @return */ String closeAccount(String account,String password);}
AidlBankBinder檔案 繼承自IBankAidl的Stub類,然後重寫並實現Aidl內的方法,這裡是類比一個銀行的操作
public class AidlBankBinder extends IBankAidl.Stub { @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { } @Override public String openAccount(String name, String password) { return name+"開戶成功!帳號為:"+ UUID.randomUUID().toString(); } @Override public String saveMoney(int money, String account) { return "賬戶:"+account + "存入"+ money + "單位:人民幣"; } @Override public String takeMoney(int money, String account, String password) { return "賬戶:"+account + "支取"+ money + "單位:人民幣"; } @Override public String closeAccount(String account, String password) { return account + "銷戶成功"; }}
BankService檔案 返回一個AidlBankBinder
public class BankService extends Service { @Nullable @Override public IBinder onBind(Intent intent) { //單進程寫法// return new BankBinder(); //不同進程AIDL 通訊寫法 return new AidlBankBinder(); }}
接下來在Activity中使用 BackActivity方法
public class BackActivity extends AppCompatActivity implements View.OnClickListener {// private BankBinder mBankBinder; private IBankAidl mBankBinder; private TextView tvMsg; private Context context; private ServiceConnection conn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { //同一進程寫法// mBankBinder = (BankBinder) service; //不同進程寫法 mBankBinder = IBankAidl.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { } }; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); context = this; tvMsg = (TextView) findViewById(R.id.tv_msg); Intent intent = new Intent(); intent.setAction("actionname.aidl.bank.BankService"); //這裡遇到一個問題,如果你直接使用intent 這個意圖去開啟服務的話就會報 //Android Service Intent must be explicit 意思是服務必須要顯示的調用,這個是5.0之後新的規定 //這個 createExplicitFromImplicitIntent 可以將隱性調用變成顯性調用 Intent intent1 = new Intent(createExplicitFromImplicitIntent(context,intent)); bindService(intent1,conn,BIND_AUTO_CREATE); initBtn(R.id.btn_aidl_bank_close); initBtn(R.id.btn_aidl_bank_open); initBtn(R.id.btn_aidl_bank_save); initBtn(R.id.btn_aidl_bank_take); } @Override protected void onDestroy() { super.onDestroy(); unbindService(conn); } private void initBtn(int resID){ Button b = (Button) findViewById(resID); b.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()){ case R.id.btn_aidl_bank_open: //這個RemoteException 是 AIDL跨進程通訊的用法必須加上的異常捕獲 try { tvMsg.setText(mBankBinder.openAccount("BigAss","123456")); }catch (RemoteException e){ e.printStackTrace(); } break; case R.id.btn_aidl_bank_save: try { tvMsg.setText(mBankBinder.saveMoney(8888888,"bigAss123")); }catch (RemoteException e){ e.printStackTrace(); } break; case R.id.btn_aidl_bank_take: try { tvMsg.setText(mBankBinder.takeMoney(520,"bigAss123","123456")); }catch (RemoteException e){ e.printStackTrace(); } break; case R.id.btn_aidl_bank_close: try { tvMsg.setText(mBankBinder.closeAccount("bigAss123","123456")); }catch (RemoteException e){ e.printStackTrace(); } break; } } /*** * Android L (lollipop, API 21) introduced a new problem when trying to invoke implicit intent, * "java.lang.IllegalArgumentException: Service Intent must be explicit" * * If you are using an implicit intent, and know only 1 target would answer this intent, * This method will help you turn the implicit intent into the explicit form. * * Inspired from SO answer: http://stackoverflow.com/a/26318757/1446466 * @param context * @param implicitIntent - The original implicit intent * @return Explicit Intent created from the implicit original intent */ public static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) { // Retrieve all services that can match the given intent PackageManager pm = context.getPackageManager(); List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0); // Make sure only one match was found if (resolveInfo == null || resolveInfo.size() != 1) { return null; } // Get component info and create ComponentName ResolveInfo serviceInfo = resolveInfo.get(0); String packageName = serviceInfo.serviceInfo.packageName; String className = serviceInfo.serviceInfo.name; ComponentName component = new ComponentName(packageName, className); // Create a new intent. Use the old one for extras and such reuse Intent explicitIntent = new Intent(implicitIntent); // Set the component to be explicit explicitIntent.setComponent(component); return explicitIntent; }}
主要思路是用隱式的方法啟動一個服務,然後調用Aidl執行個體類的方法即可,具體的Aidl語言在BuildApp之後在
這裡即可查看 內部是他實現進程間資料轉送所做的轉化代碼,有興趣可以看下
android AIDL 語言用法