Android
遠程服務的製做與測試運行,AIDL服務。Android API = 29
即 Android 10
,開發IDE是 Android Studio
網上搜了N多文章,要麼年代久遠,要麼開發IDE不一樣操做不懂(小白搞不懂。。),本文以最詳細的步驟實現最簡的 AIDL 遠程服務的製做和調用。java
在 Android Studio
中建立了空的工程(其實後來沒用到,不過爲了配合源碼仍是要說下),建立模塊 rsserver
- 因爲 Android Studio
和 IDEA
一個德行的,這裏只能叫它模塊了 - 英文名是 module
嗎。本模塊用來製做一個服務能夠在本模塊的 activity
中調用,能夠提供給其餘 app
或者模塊使用,再建立一個客戶端模塊 rsclient
- 這裏的 rs
表示 remote service
。那麼最終造成的結構以下圖:
android
後面的步驟爲先製做服務端模塊中的服務而且測試經過後再製做客戶端模塊,讓咱們開始吧。git
製做 AIDL
接口文件,在服務端模塊的根節點上經過右鍵菜單建立一個AIDL
文件
將其命名爲 IProcessInfo
,其中只要定義一個方法不用實現,所有代碼以下(建立完畢後會有一個默認的方法,將其刪除掉,而後追加一個咱們本身的方法)github
// IProcessInfo.aidl package com.ccsoft.rsserver; // Declare any non-default types here with import statements interface IProcessInfo { int getProcessId(); }
保存後 AS
會自動建立同名的接口文件,以後建立服務的時候要用到
app
實現 AIDL
文件中定義的方法
在項目包 com.ccsoft.rsserver
下建立包 service
再在其下建立服務 IProcessInfoImpl
繼承自 IProcessInfo.Stub
,其所有代碼以下ide
package com.ccsoft.rsserver.service; import android.os.RemoteException; import com.ccsoft.rsserver.IProcessInfo; public class IProcessInfoImpl extends IProcessInfo.Stub { @Override public int getProcessId() throws RemoteException { return android.os.Process.myPid(); } }
調用本方法會打印進程ID,最終造成的結構以下圖
佈局
建立服務,用來返回實現接口的類的實例,其所有代碼以下:測試
package com.ccsoft.rsserver.service; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.util.Log; import androidx.annotation.Nullable; public class MyRemoteService extends Service { private static final String TAG = "chanchaw"; IProcessInfoImpl mProcessInfo = new IProcessInfoImpl(); @Nullable @Override public IBinder onBind(Intent intent) { Log.e(TAG, "MyRemoteService thread id = " + Thread.currentThread().getId()); return mProcessInfo; } }
最終實現的結構以下
this
接下來爲服務端建立一個 Activity
用來測試服務是否可用,先建立佈局文件 activity_main
,其所有代碼以下:spa
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="綁定本地服務" android:onClick="bindLocalService" /> </LinearLayout>
最終造成的結構以下圖
建立一個 Activity
顯示該佈局而且測試服務,命名爲 MainActivity
,其所有代碼以下:
package com.ccsoft.rsserver; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import android.view.View; import androidx.annotation.Nullable; import com.ccsoft.rsserver.service.MyRemoteService; public class MainActivity extends Activity { // 打印日誌時用來過濾,快速找到調試信息 private static final String TAG = "chanchaw"; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 關聯到 res/layout/activity_main.xml,會顯示其中定義的控件 setContentView(R.layout.activity_main); } // 建立 ServiceConnection 類型的對象實例,在後面綁定服務時會用到 ServiceConnection myServiceConnection = new ServiceConnection() { /** * 服務綁定成功後會調用本方法 * @param name
*/ @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.i(TAG, "MyRemoteService onServiceConnected"); // 經過aidl取出數據 IProcessInfo processInfo = IProcessInfo.Stub.asInterface(service); try { Log.i(TAG, "MyRemoteService process id = " + processInfo.getProcessId()); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { Log.i(TAG, "MyRemoteService onServiceDisconnected"); } }; public void bindLocalService(View v){ Intent intent = new Intent(this, MyRemoteService.class); bindService(intent, myServiceConnection, Context.BIND_AUTO_CREATE); } @Override protected void onDestroy() { super.onDestroy(); unbindService(myServiceConnection); }
}
最終造成的結構以下 ![](https://user-images.githubusercontent.com/29369287/66197772-ac01e400-e6cd-11e9-84c5-815d5764feec.png) - 在模塊清單文件 ``AndroidManifest.xml`` 中註冊``Activity`` 和服務,其所有代碼以下:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ccsoft.rsserver"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name=".service.MyRemoteService" android:process=":remote"> <intent-filter> <action android:name="com.jxx.server.service.bind" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </service> </application>
</manifest>
- 在服務端測試上面製做的服務,成功的話則完成了所有工做的70%,效果以下圖 ![](https://user-images.githubusercontent.com/29369287/66197771-ab694d80-e6cd-11e9-98f6-e614ba7ec6b6.png) - 建立客戶端模塊,而後將服務端模塊中的 ``AIDL`` 連帶其下的文件一塊兒拷貝到客戶端模塊中,以下圖 ![](https://user-images.githubusercontent.com/29369287/66197770-ab694d80-e6cd-11e9-94a8-a1d001c2ff1c.png) - 拷貝過去後切記要使用 ``ctrl + F9`` 構建下客戶端模塊,這樣纔會生成接口文件,以下圖 ![](https://user-images.githubusercontent.com/29369287/66197768-ab694d80-e6cd-11e9-9880-fa361007d38e.png) - 客戶端模塊中建立 ``activity`` 的佈局文件,其所有代碼以下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/rsclient_textview" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="rsclient_textview" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="綁定遠程服務" android:onClick="bindRemoteService" />
</LinearLayout>
造成的結構以下 ![](https://user-images.githubusercontent.com/29369287/66197766-aad0b700-e6cd-11e9-85aa-70bec1af872b.png) - 建立 ``Activity``,所有代碼以下
package com.ccsoft.rsclient;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.Nullable;
import com.ccsoft.rsserver.IProcessInfo;
public class MainActivity extends Activity {
private static final String TAG = "chanchaw"; TextView text = null; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); text = findViewById(R.id.rsclient_textview); } // 綁定遠程服務 public void bindRemoteService(View v){ Intent intent = new Intent(); intent.setAction("com.jxx.server.service.bind");//Service的action intent.setPackage("com.ccsoft.rsserver");//App A的包名 bindService(intent, mServerServiceConnection, BIND_AUTO_CREATE); } ServiceConnection mServerServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.i(TAG, "MyRemoteService onServiceConnected"); // 經過aidl取出數據 IProcessInfo processInfo = IProcessInfo.Stub.asInterface(service); try { Log.i(TAG, "MyRemoteService process id = " + processInfo.getProcessId()); text.setText("綁定成功!"); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { Log.i(TAG, "MyRemoteService onServiceDisconnected"); } };
}
最終造成的結構以下 ![](https://user-images.githubusercontent.com/29369287/66197765-aad0b700-e6cd-11e9-938e-e22917399fab.png) - 清單文件中註冊 ``Activity``,所有代碼以下
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ccsoft.rsclient"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application>
</manifest>
這裏不用註冊遠程的服務,由於是遠程調用的 - 在客戶端模塊中測試調用遠程服務 ![](https://user-images.githubusercontent.com/29369287/66197763-aad0b700-e6cd-11e9-9880-4a4d1a5c2c61.png) #### 結束語