http://blog.csdn.net/guolin_blog/article/details/9797169java
http://www.jianshu.com/p/eeb2bd59853fandroid
將一個普通的Service轉換成遠程Service其實很是簡單,只須要在註冊Service的時候將它的android:process屬性指定成:remote就能夠了,代碼以下所示:app
<service android:name=".AIDLService"
android:process=":remote"></service>
遠程service可讓service在另外一個進程運行,因此能夠執行阻塞進程的操做ide
遠程Service這麼好用,乾脆之後咱們把全部的Service都轉換成遠程Service吧,還免得再開啓線程了。其實否則,遠程Service非但很差用,甚至能夠稱得上是較爲難用。通常狀況下若是能夠不使用遠程Service,就儘可能不要使用它。ui
下面就來看一下它的弊端吧,首先將MyService的onCreate()方法中讓線程睡眠的代碼去除掉,而後從新運行程序,並點擊一下Bind Service按鈕,你會發現程序崩潰了!爲何點擊Start Service按鈕程序就不會崩潰,而點擊Bind Service按鈕就會崩潰呢?這是因爲在Bind Service按鈕的點擊事件裏面咱們會讓MainActivity和MyService創建關聯,可是目前MyService已是一個遠程Service了,Activity和Service運行在兩個不一樣的進程當中,這時就不能再使用傳統的創建關聯的方式,程序也就崩潰了。this
那麼如何才能讓Activity與一個遠程Service創建關聯呢?這就要使用AIDL來進行跨進程通訊了(IPC)。spa
調用者和Service若是不在一個進程內, 就須要使用android中的遠程Service調用機制.
android使用AIDL定義進程間的通訊接口. AIDL的語法與java接口相似, 須要注意如下幾點:.net
AIDL實現
1.首先我創建2個app工程,經過aidl實現一個app調用另外一個app的service
目錄結構以下:
service提供端app線程
利用aidl調用service的appcode
2.在兩個app中都創建一個文件 IPerson.aidl注意 包名 要相同
IPerson.aidl只是一個接口文件,用來aidl交互的,創建好以後在Studio中點Build-->Rebuild會自動建立須要的java文件。
IPerson.aidl代碼
package mangues.com.aidl; interface IPerson { String greet(String someone); }
3.在aidl_service 中創建AIDLService
這個IPerson.Stub 就是經過IPerson.aidl 自動生成的binder 文件,你實現下,而後在onBind()中 return出去就行了,就和Android Service實現和activity交互同樣。
代碼:
public class AIDLService extends Service { private static final String TAG = "AIDLService"; IPerson.Stub stub = new IPerson.Stub() { @Override public String greet(String someone) throws RemoteException { Log.i(TAG, "greet() called"); return "hello, " + someone; } }; @Override public void onCreate() { super.onCreate(); Log.i(TAG, "onCreate() called"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG, "onBind() onStartCommand"); return super.onStartCommand(intent, flags, startId); } @Override public IBinder onBind(Intent intent) { Log.i(TAG, "onBind() called"); return stub; } @Override public boolean onUnbind(Intent intent) { Log.i(TAG, "onUnbind() called"); return true; } @Override public void onDestroy() { super.onDestroy(); Log.i(TAG, "onDestroy() called"); } }
這裏爲何能夠這樣寫呢?由於Stub其實就是Binder的子類,因此在onBind()方法中能夠直接返回Stub的實現。
4.aidl_service MainActivity 中啓動這個service
簡單點就不寫關閉什麼的了;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent startIntent = new Intent(this, AIDLService.class); startService(startIntent); }
在AndroidManifest.xml註冊
<service android:name=".AIDLService"
android:process=":remote">
<intent-filter>
<action android:name="android.intent.action.AIDLService" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
做用就是把這個service暴露出去,讓別的APP能夠利用
android.intent.action.AIDLService 字段隱形綁定這個service,獲取數據。
5.aidl_client 中綁定aidl_service service 獲取數據
代碼:
public class MainActivity extends AppCompatActivity { private IPerson person; private ServiceConnection conn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.i("ServiceConnection", "onServiceConnected() called"); person = IPerson.Stub.asInterface(service); String retVal = null; try { retVal = person.greet("scott"); } catch (RemoteException e) { e.printStackTrace(); } Toast.makeText(MainActivity.this, retVal, Toast.LENGTH_SHORT).show(); } @Override public void onServiceDisconnected(ComponentName name) { //This is called when the connection with the service has been unexpectedly disconnected, //that is, its process crashed. Because it is running in our same process, we should never see this happen. Log.i("ServiceConnection", "onServiceDisconnected() called"); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent mIntent = new Intent(); mIntent.setAction("android.intent.action.AIDLService"); Intent eintent = new Intent(getExplicitIntent(this,mIntent)); bindService(eintent, conn, Context.BIND_AUTO_CREATE); } public static Intent getExplicitIntent(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; } }
在上一篇文章中咱們已經知道,若是想要讓Activity與Service之間創建關聯,須要調用bindService()方法,並將Intent做爲參數傳遞進去,在Intent裏指定好要綁定的Service,示例代碼以下:
Intent bindIntent = new Intent(this, MyService.class); bindService(bindIntent, connection, BIND_AUTO_CREATE);
這裏在構建Intent的時候是使用MyService.class來指定要綁定哪個Service的,可是在另外一個應用程序中去綁定Service的時候並無MyService這個類,這時就必須使用到隱式Intent了
<intent-filter> <action android:name="com.example.servicetest.MyAIDLService"/> </intent-filter>
這就說明,MyService能夠響應帶有com.example.servicetest.MyAIDLService這個action的Intent。