国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android使用Service實現IPC通信的2種方式

2019-12-12 00:16:17
字體:
來源:轉載
供稿:網友

借助AIDL實現IPC通信

一、代碼實操---與遠端進程的Service綁定

上面的代碼都是在當前進程內跟Service通信,現在我們來實現一下,不同進程內Service如何綁定。

AIDL:Android Interface Definition Language,即Android接口定義語言。

Service跨進程傳遞數據需要借助aidl,主要步驟是這樣的:

  1. 編寫aidl文件,AS自動生成的java類實現IPC通信的代理
  2. 繼承自己的aidl類,實現里面的方法
  3. 在onBind()中返回我們的實現類,暴露給外界
  4. 需要跟Service通信的對象通過bindService與Service綁定,并在ServiceConnection接收數據。

我們通過代碼來實現一下:

1、首先我們需要新建一個Service

public class MyRemoteService extends Service { @Nullable @Override public IBinder onBind(Intent intent) {  Log.e("MyRemoteService", "MyRemoteService thread id = " + Thread.currentThread().getId());  return null; }}

2、在manifest文件中聲明我們的Service同時指定運行的進程名,這里并是不只能寫remote進程名,你想要進程名都可以

<service    android:name=".service.MyRemoteService"    android:process=":remote" />

3、新建一個aidl文件用戶進程間傳遞數據。

AIDL支持的類型:八大基本數據類型、String類型、CharSequence、List、Map、自定義類型。List、Map、自定義類型放到下文講解。

里面會有一個默認的實現方法,刪除即可,這里我們新建的文件如下:

package xxxx;//aidl所在的包名//interface之前不能有修飾符interface IProcessInfo { //你想要的通信用的方法都可以在這里添加 int getProcessId();}

4、實現我們的aidl類

public class IProcessInfoImpl extends IProcessInfo.Stub { @Override public int getProcessId() throws RemoteException {  return android.os.Process.myPid(); }}

5、在Service的onBind()中返回

public class MyRemoteService extends Service { IProcessInfoImpl mProcessInfo = new IProcessInfoImpl(); @Nullable @Override public IBinder onBind(Intent intent) {  Log.e("MyRemoteService", "MyRemoteService thread id = " + Thread.currentThread().getId());  return mProcessInfo; }}

6、綁定Service

 mTvRemoteBind.setOnClickListener(new View.OnClickListener() {    @Override    public void onClick(View v) {      Intent intent = new Intent(MainActivity.this, MyRemoteService.class);      bindService(intent, mRemoteServiceConnection, BIND_AUTO_CREATE);    }  });mRemoteServiceConnection = new ServiceConnection() {    @Override    public void onServiceConnected(ComponentName name, IBinder service) {      Log.e("MainActivity", "MyRemoteService onServiceConnected");  // 通過aidl取出數據      IProcessInfo processInfo = IProcessInfo.Stub.asInterface(service);      try {        Log.e("MainActivity", "MyRemoteService process id = " + processInfo.getProcessId());      } catch (RemoteException e) {        e.printStackTrace();      }    }    @Override    public void onServiceDisconnected(ComponentName name) {      Log.e("MainActivity", "MyRemoteService onServiceDisconnected");    }  };

只要綁定成功就能在有log打印成MyRemoteService所在進程的進程id。這樣我們就完成了跟不同進程的Service通信的過程。

二、代碼實操---調用其他app的Service

跟調同app下不同進程下的Service相比,調用其他的app定義的Service有一些細微的差別

1、由于需要其他app訪問,所以之前的bindService()使用的隱式調用不在合適,需要在Service定義時定義action
我們在定義的線程的App A 中定義如下Service:

<service android:name=".service.ServerService"> <intent-filter> //這里的action自定義   <action android:name="com.jxx.server.service.bind" />   <category android:name="android.intent.category.DEFAULT" />  </intent-filter></service>

2、我們在需要bindService的App B 中需要做這些處理

  • 首先要將A中定義的aidl文件復制到B中,比如我們在上面定義的IProcessInfo.aidl這個文件,包括路徑在內需要原封不動的復制過來。
  • 在B中調用Service通過顯式調用
mTvServerBind.setOnClickListener(new View.OnClickListener() {  @Override  public void onClick(View v) {    Intent intent = new Intent();    intent.setAction("com.jxx.server.service.bind");//Service的action    intent.setPackage("com.jxx.server");//App A的包名    bindService(intent, mServerServiceConnection, BIND_AUTO_CREATE);  }});

aidl中自定義對象的傳遞

主要步驟如下:

  1. 定義自定對象,需要實現Parcelable接口
  2. 新建自定義對象的aidl文件
  3. 在傳遞數據的aidl文件中引用自定義對象
  4. 將自定義對象以及aidl文件拷貝到需要bindService的app中,主要路徑也要原封不動

我們來看一下具體的代碼:

1、定義自定義對象,并實現Parcelable接口

public class ServerInfo implements Parcelable {public ServerInfo() {}String mPackageName;public String getPackageName() {  return mPackageName;}public void setPackageName(String packageName) {  mPackageName = packageName;}protected ServerInfo(Parcel in) {  mPackageName = in.readString();}public static final Creator<ServerInfo> CREATOR = new Creator<ServerInfo>() {  @Override  public ServerInfo createFromParcel(Parcel in) {    return new ServerInfo(in);  }  @Override  public ServerInfo[] newArray(int size) {    return new ServerInfo[size];  }};@Overridepublic int describeContents() {  return 0;}@Overridepublic void writeToParcel(Parcel dest, int flags) {  dest.writeString(mPackageName);}//使用out或者inout修飾時需要自己添加這個方法public void readFromParcel(Parcel dest) {  mPackageName = dest.readString();}}

2、新建自定義對象的aidl文件

package com.jxx.server.aidl;//注意parcelable 是小寫的parcelable ServerInfo;

3、引用自定義對象

package com.jxx.server.aidl;//就算在同一包下,這里也要導包import com.jxx.server.aidl.ServerInfo;interface IServerServiceInfo { ServerInfo getServerInfo(); void setServerInfo(inout ServerInfo serverinfo);}

注意這里的set方法,這里用了inout,一共有3種修飾符
- in:客戶端寫入,服務端的修改不會通知到客戶端
- out:服務端修改同步到客戶端,但是服務端獲取到的對象可能為空
- inout:修改都收同步的

當使用out和inout時,除了要實現Parcelable外還要手動添加readFromParcel(Parcel dest)

4、拷貝自定義對象以及aidl文件到在要引用的App中即可。

5、引用

mServerServiceConnection = new ServiceConnection() {    @Override    public void onServiceConnected(ComponentName name, IBinder service) {      IServerServiceInfo serverServiceInfo = IServerServiceInfo.Stub.asInterface(service);      try {        ServerInfo serviceInfo = serverServiceInfo.getServerInfo();        Log.e("MainActivity", "ServerService packageName = " + serviceInfo.getPackageName());      } catch (RemoteException e) {        e.printStackTrace();      }    }    @Override    public void onServiceDisconnected(ComponentName name) {      Log.e("MainActivity", "ServerService onServiceDisconnected");    }  };

List、Map中引用的對象也應該是符合上面要求的自定義對象,或者其他的幾種數據類型。

使用Messenger實現IPC通信

步驟是這樣的:

  1. 在Server端新建一個Messenger對象,用于響應Client端的注冊操作,并在onBind()中傳遞出去
  2. 在Client端的ServiceConnection中,將Server端傳遞過來的Messenger對象進行保存
  3. 同時Client端也新建一個Messenger對象,通過Server傳遞過來的Messenger注冊到Server端,保持通信用。
  4. 不管是否進行unbindService()操作,只要Client保有Server端的Messenger對象,仍然能和Server端進行通信。

一、Server端代碼

public class MessengerService extends Service {  static final int MSG_REGISTER_CLIENT = 1;  static final int MSG_UNREGISTER_CLIENT = 2;  static final int MSG_SET_VALUE = 3;  //這個是給client端接收參數用的  static final int MSG_CLIENT_SET_VALUE = 4;  static class ServiceHandler extends Handler {    private final List<Messenger> mMessengerList = new ArrayList<>();    @Override    public void handleMessage(Message msg) {      switch (msg.what) {        case MSG_REGISTER_CLIENT:          mMessengerList.add(msg.replyTo);          break;        case MSG_UNREGISTER_CLIENT:          mMessengerList.remove(msg.replyTo);          break;        case MSG_SET_VALUE:          int value = msg.arg1;          for (Messenger messenger : mMessengerList) {            try {              messenger.send(Message.obtain(null, MSG_CLIENT_SET_VALUE, value, 0));            } catch (RemoteException e) {              e.printStackTrace();            }          }          break;        default:          super.handleMessage(msg);      }    }  }  private Messenger mMessenger = new Messenger(new ServiceHandler());  @Nullable  @Override  public IBinder onBind(Intent intent) {    return mMessenger.getBinder();  }}

二、Client端代碼

public class MessengerClientActivity extends AppCompatActivity { //這些類型要和Server端想對應  static final int MSG_REGISTER_CLIENT = 1;  static final int MSG_UNREGISTER_CLIENT = 2;  static final int MSG_SET_VALUE = 3;  static final int MSG_CLIENT_SET_VALUE = 4;  class ClientHandler extends Handler {    @Override    public void handleMessage(Message msg) {      if (msg.what == MSG_CLIENT_SET_VALUE) {        mTvValue.setText(msg.arg1 + "");      } else {        super.handleMessage(msg);      }    }  }  TextView mTvServerBind;  TextView mTvServerUnbind;  TextView mTvValue;  TextView mTvSend;  ServiceConnection mServerServiceConnection;  Messenger mServerMessenger;  @Override  protected void onCreate(@Nullable Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_messenger);    mTvServerBind = findViewById(R.id.tv_server_bind);    mTvServerUnbind = findViewById(R.id.tv_server_unbind);    mTvValue = findViewById(R.id.tv_value);    mTvSend = findViewById(R.id.tv_send);    mTvServerBind.setOnClickListener(new View.OnClickListener() {      @Override      public void onClick(View v) {        Intent intent = new Intent();        intent.setAction("jxx.com.server.service.messenger");        intent.setPackage("jxx.com.server");        bindService(intent, mServerServiceConnection, BIND_AUTO_CREATE);      }    });    mTvServerUnbind.setOnClickListener(new View.OnClickListener() {      @Override      public void onClick(View v) {        //就算這里我們unbindService,只要我們還保留有mServerMessenger對象,        //我們就能繼續與Server通信        unbindService(mServerServiceConnection);      }    });    mTvSend.setOnClickListener(new View.OnClickListener() {      @Override      public void onClick(View v) {        if (mServerMessenger != null) {          try {            //測試一下能否設置數據            Message test = Message.obtain(null, MSG_SET_VALUE, new Random().nextInt(100), 0);            mServerMessenger.send(test);          } catch (RemoteException e) {            e.printStackTrace();          }        }      }    });    mServerServiceConnection = new ServiceConnection() {      @Override      public void onServiceConnected(ComponentName name, IBinder service) {        //服務端的messenger        mServerMessenger = new Messenger(service);        //現在開始構client用來傳遞和接收消息的messenger        Messenger clientMessenger = new Messenger(new ClientHandler());        try {          //將client注冊到server端          Message register = Message.obtain(null, MSG_REGISTER_CLIENT);          register.replyTo = clientMessenger;//這是注冊的操作,我們可以在上面的Server代碼看到這個對象被取出          mServerMessenger.send(register);          Toast.makeText(MessengerClientActivity.this, "綁定成功", Toast.LENGTH_SHORT).show();        } catch (RemoteException e) {          e.printStackTrace();        }      }      @Override      public void onServiceDisconnected(ComponentName name) {      }    };  }

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 屏东县| 九江市| 五家渠市| 海原县| 当阳市| 河南省| 三台县| 周口市| 三河市| 平安县| 名山县| 江源县| 新巴尔虎左旗| 濮阳县| 绵阳市| 进贤县| 乳山市| 土默特右旗| 溧阳市| 南和县| 福泉市| 凉城县| 自治县| 齐河县| 和政县| 丹阳市| 买车| 霍林郭勒市| 左贡县| 博客| 沾益县| 乌兰察布市| 荥经县| 苍溪县| 集安市| 金堂县| 托克逊县| 磐石市| 新密市| 万安县| 普安县|