Android使用Service实现IPC通信的2种方式

发布时间:2019-08-08 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了Android使用Service实现IPC通信的2种方式脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

借助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、自定义类型放到下文讲解

Android使用Service实现IPC通信的2种方式

里面会有一个默认的实现方法,删除即可,这里我们新建的文件如下:

 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];   } };  @Override public int describeContents() {   return 0; }  @Override public 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) {        }     };   }  
android教程
脚本网站
android studio

脚本宝典总结

以上是脚本宝典为你收集整理的Android使用Service实现IPC通信的2种方式全部内容,希望文章能够帮你解决Android使用Service实现IPC通信的2种方式所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。