Binder的使用以及核心机制分析,跨进程的实现原理

Binder可以提供系统中任何程序都可以访问的全局服务。这个功能当然是任何系统都应该提供的
Android Binder框架分为服务器接口、Binder驱动、以及客户端接口;简单想一下,需要提供一个全局服务,那么全局服务那端即是服务器接口,任何程序即客户端接口,它们之间通过一个Binder驱动访问。
Binder框架原理分析
1、ISettingToServer.aidl文件生成的Java文件

public interface ISettingToServer extends android.os.IInterface
{
  /** Default implementation for ISettingToServer. */
  public static class Default implements com.wq.qcsettings.ISettingToServer
  {
    @Override public void setMobileDataEnabled(boolean enabled) throws android.os.RemoteException
    {
    }
    @Override public boolean isMobileDataEnabled() throws android.os.RemoteException
    {
      return false;
    }
    @Override public void setGpsEnabled(boolean enabled) throws android.os.RemoteException
    {
    }
    @Override public boolean isGpsEnabled() throws android.os.RemoteException
    {
      return false;
    }
  
    @Override
    public android.os.IBinder asBinder() {
      return null;
    }
  }
  /** Local-side IPC implementation stub class. */
  public static abstract class Stub extends android.os.Binder implements com.wq.qcsettings.ISettingToServer
  {
    private static final java.lang.String DESCRIPTOR = "com.zqc.qcsettings.ISettingToServer";
    /** Construct the stub at attach it to the interface. */
    public Stub()
    {
      this.attachInterface(this, DESCRIPTOR);
    }
    /**
     * Cast an IBinder object into an com.zqc.qcsettings.ISettingToServer interface,
     * generating a proxy if needed.
     */
    public static com.wq.qcsettings.ISettingToServer asInterface(android.os.IBinder obj)
    {
      if ((obj==null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin!=null)&&(iin instanceof com.zqc.qcsettings.ISettingToServer))) {
        return ((com.wq.qcsettings.ISettingToServer)iin);
      }
      return new com.wq.qcsettings.ISettingToServer.Stub.Proxy(obj);
    }
    @Override public android.os.IBinder asBinder()
    {
      return this;
    }
    @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
    {
      java.lang.String descriptor = DESCRIPTOR;
      switch (code)
      {
        case INTERFACE_TRANSACTION:
        {
          reply.writeString(descriptor);
          return true;
        }
        case TRANSACTION_setMobileDataEnabled:
        {
          data.enforceInterface(descriptor);
          boolean _arg0;
          _arg0 = (0!=data.readInt());
          this.setMobileDataEnabled(_arg0);
          reply.writeNoException();
          return true;
        }
        case TRANSACTION_isMobileDataEnabled:
        {
          data.enforceInterface(descriptor);
          boolean _result = this.isMobileDataEnabled();
          reply.writeNoException();
          reply.writeInt(((_result)?(1):(0)));
          return true;
        }
        case TRANSACTION_setGpsEnabled:
        {
          data.enforceInterface(descriptor);
          boolean _arg0;
          _arg0 = (0!=data.readInt());
          this.setGpsEnabled(_arg0);
          reply.writeNoException();
          return true;
        }
        case TRANSACTION_isGpsEnabled:
        {
          data.enforceInterface(descriptor);
          boolean _result = this.isGpsEnabled();
          reply.writeNoException();
          reply.writeInt(((_result)?(1):(0)));
          return true;
        }      
        default:
        {
          return super.onTransact(code, data, reply, flags);
        }
      }
    }
    private static class Proxy implements com.wq.qcsettings.ISettingToServer
    {
      private android.os.IBinder mRemote;
      Proxy(android.os.IBinder remote)
      {
        mRemote = remote;
      }
      @Override public android.os.IBinder asBinder()
      {
        return mRemote;
      }
      public java.lang.String getInterfaceDescriptor()
      {
        return DESCRIPTOR;
      }
      @Override public void setMobileDataEnabled(boolean enabled) throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          _data.writeInt(((enabled)?(1):(0)));
          boolean _status = mRemote.transact(Stub.TRANSACTION_setMobileDataEnabled, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().setMobileDataEnabled(enabled);
            return;
          }
          _reply.readException();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }
      @Override public boolean isMobileDataEnabled() throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        boolean _result;
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          boolean _status = mRemote.transact(Stub.TRANSACTION_isMobileDataEnabled, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            return getDefaultImpl().isMobileDataEnabled();
          }
          _reply.readException();
          _result = (0!=_reply.readInt());
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
        return _result;
      }
      @Override public void setGpsEnabled(boolean enabled) throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          _data.writeInt(((enabled)?(1):(0)));
          boolean _status = mRemote.transact(Stub.TRANSACTION_setGpsEnabled, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().setGpsEnabled(enabled);
            return;
          }
          _reply.readException();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }
      @Override public boolean isGpsEnabled() throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        boolean _result;
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          boolean _status = mRemote.transact(Stub.TRANSACTION_isGpsEnabled, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            return getDefaultImpl().isGpsEnabled();
          }
          _reply.readException();
          _result = (0!=_reply.readInt());
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
        return _result;
      }
  
      public static com.wq.qcsettings.ISettingToServer sDefaultImpl;
    }
    static final int TRANSACTION_setMobileDataEnabled = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int TRANSACTION_isMobileDataEnabled = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    static final int TRANSACTION_setGpsEnabled = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
    static final int TRANSACTION_isGpsEnabled = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);   
    public static boolean setDefaultImpl(com.wq.qcsettings.ISettingToServer impl) {
      if (Stub.Proxy.sDefaultImpl == null && impl != null) {
        Stub.Proxy.sDefaultImpl = impl;
        return true;
      }
      return false;
    }
    public static com.wq.qcsettings.ISettingToServer getDefaultImpl() {
      return Stub.Proxy.sDefaultImpl;
    }
  }
  public void setMobileDataEnabled(boolean enabled) throws android.os.RemoteException;
  public boolean isMobileDataEnabled() throws android.os.RemoteException;
  public void setGpsEnabled(boolean enabled) throws android.os.RemoteException;
  public boolean isGpsEnabled() throws android.os.RemoteException;
}

ISettingToServer .java文件包含两个静态内部类—Stub和Proxy(其中Proxy是Stub的内部类)
静态内部Stub 类分析

public static abstract class Stub extends android.os.Binder implements com.zqc.qcsettings.ISettingToServer

其中Stub是个抽象类,它继承了Binder,并实现了ISettingToServer接口。Stub提供了几个方法:asInterface、asBinder、onTransact,但并没有实现ISettingToServer接口的方法,所以需要交给Stub的实现类Proxy去实现。

public static com.wq.qcsettings.ISettingToServer asInterface(android.os.IBinder obj)
{
  if ((obj==null)) {
    return null;
  }
  android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
  if (((iin!=null)&&(iin instanceof com.wq.qcsettings.ISettingToServer))) {
    return ((com.wq.qcsettings.ISettingToServer)iin);
  }
  return new com.wq.qcsettings.ISettingToServer.Stub.Proxy(obj);
}

静态内部Proxy 类分析

private static class Proxy implements com.zqc.qcsettings.ISettingToServer

Proxy是Stub的内部类,也实现了ISettingToServer 接口。并提供了几个方法:asBinder、getInterfaceDescriptor,并实现了ISettingToServer 接口的方法setMobileDataEnabled()、isMobileDataEnabled()、setGpsEnabled()、isGpsEnabled()。

private static class Proxy implements com.zqc.qcsettings.ISettingToServer
    {
      private android.os.IBinder mRemote;
      Proxy(android.os.IBinder remote)
      {
        mRemote = remote;
      }
      @Override public android.os.IBinder asBinder()
      {
        return mRemote;
      }
      public java.lang.String getInterfaceDescriptor()
      {
        return DESCRIPTOR;
      }
      @Override public void setMobileDataEnabled(boolean enabled) throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          _data.writeInt(((enabled)?(1):(0)));
          boolean _status = mRemote.transact(Stub.TRANSACTION_setMobileDataEnabled, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().setMobileDataEnabled(enabled);
            return;
          }
          _reply.readException();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }
      @Override public boolean isMobileDataEnabled() throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        boolean _result;
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          boolean _status = mRemote.transact(Stub.TRANSACTION_isMobileDataEnabled, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            return getDefaultImpl().isMobileDataEnabled();
          }
          _reply.readException();
          _result = (0!=_reply.readInt());
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
        return _result;
      }
      @Override public void setGpsEnabled(boolean enabled) throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          _data.writeInt(((enabled)?(1):(0)));
          boolean _status = mRemote.transact(Stub.TRANSACTION_setGpsEnabled, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().setGpsEnabled(enabled);
            return;
          }
          _reply.readException();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }
      @Override public boolean isGpsEnabled() throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        boolean _result;
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          boolean _status = mRemote.transact(Stub.TRANSACTION_isGpsEnabled, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            return getDefaultImpl().isGpsEnabled();
          }
          _reply.readException();
          _result = (0!=_reply.readInt());
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
        return _result;
      }
  
      public static com.zqc.qcsettings.ISettingToServer sDefaultImpl;
    }

可以看到我们服务端提供的服务是由ISettingToServer .Stub来执行的,上面分析过,Stub这个类是Binder的子类,是不是符合我们文章开头所说的服务端其实是一个Binder类的实例。而且mBinder实现了ISettingToServer 接口的方法。
接下来看Stub的onTransact()方法:

@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
    {
      java.lang.String descriptor = DESCRIPTOR;
      switch (code)
      {
        case INTERFACE_TRANSACTION:
        {
          reply.writeString(descriptor);
          return true;
        }
        case TRANSACTION_setMobileDataEnabled:
        {
          data.enforceInterface(descriptor);
          boolean _arg0;
          _arg0 = (0!=data.readInt());
          this.setMobileDataEnabled(_arg0);
          reply.writeNoException();
          return true;
        }
        case TRANSACTION_isMobileDataEnabled:
        {
          data.enforceInterface(descriptor);
          boolean _result = this.isMobileDataEnabled();
          reply.writeNoException();
          reply.writeInt(((_result)?(1):(0)));
          return true;
        }
        case TRANSACTION_setGpsEnabled:
        {
          data.enforceInterface(descriptor);
          boolean _arg0;
          _arg0 = (0!=data.readInt());
          this.setGpsEnabled(_arg0);
          reply.writeNoException();
          return true;
        }
        case TRANSACTION_isGpsEnabled:
        {
          data.enforceInterface(descriptor);
          boolean _result = this.isGpsEnabled();
          reply.writeNoException();
          reply.writeInt(((_result)?(1):(0)));
          return true;
        }      
        default:
        {
          return super.onTransact(code, data, reply, flags);
        }
      }
    }

服务端的Binder实例会根据客户端依靠Binder驱动发来的消息,执行onTransact方法,然后由其参数决定执行服务端的代码。
可以看到onTransact有四个参数:code , data ,replay , flags
code:是一个整形的唯一标识,用于区分执行哪个方法,客户端会传递此参数,告诉服务端执行哪个方法
data:客户端传递过来的参数
reply:服务器返回回去的值
flags:标明是否有返回值,0为有(双向),1为没有(单向)

private static final java.lang.String DESCRIPTOR = "com.zqc.qcsettings.ISettingToServer";
java.lang.String descriptor = DESCRIPTOR;
case TRANSACTION_setMobileDataEnabled:
{
  data.enforceInterface(descriptor);
  boolean _arg0;
  _arg0 = (0!=data.readInt());
  this.setMobileDataEnabled(_arg0);
  reply.writeNoException();
  return true;
}

最后读出我们服务端返回的数据,然后return。可以看到Transact和服务端的onTransact基本是一行一行对应的。
当客户端调用transact方法发起RPC(远程过程调用)请求后,当前线程会挂起,等待服务器端的返回结果。所以如果一个远程方法很耗时,那么不能再UI线程中调用此远程方法。
服务端的Binder方法(onTransact)运行在Binder线程池中,所以Binder方法不管是否耗时,都应该采取同步机制,因为它已经运行在一个线程中了。
我们已经通过AIDL生成的代码解释了Android Binder框架的工作原理。Service的作用其实就是为我们创建Binder驱动,即服务端与客户端连接的桥梁。Binder框架原理图如下
在这里插入图片描述代码实例如下
服务端
创建一个SettingsServer.java 类继承Service

ublic class YlfSettingsServer  extends Service {
    private static final String TAG = "SettingsServer";
    private ISettingFunctionIml mISettingFunctionIml;
    private Context mContext;
    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate()");
        mContext = this;
        mISettingFunctionIml = new ISettingFunctionIml(mContext);
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.d(TAG, "onUnbind()");
        return super.onUnbind(intent);

    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy()");
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind()");
        return new YlfSettingsServerIml(mISettingFunctionIml);
    }

}

创建一个SettingsServerIml 继承extends ISettingToServer.Stub

public class SettingsServerIml extends ISettingToServer.Stub{
    private static String TAG = "SettingsServerIml";
    private com.zqc.qcsettings.ISettingFunctionIml mISettingFunctionIml;
    public YlfSettingsServerIml(ISettingFunctionIml mISettingFunctionIml){
        this.mISettingFunctionIml = mISettingFunctionIml;
    }
    @Override
    public void setMobileDataEnabled(boolean enabled) throws RemoteException {
        Log.d(TAG," setMobileDataEnabled " +enabled);
        mISettingFunctionIml.setMobileDataEnabled(enabled);
    }

    @Override
    public boolean isMobileDataEnabled() throws RemoteException {
        Log.d(TAG," isMobileDataEnabled() " );
        return mISettingFunctionIml.isMobileDataEnabled();
    }

    @Override
    public void setGpsEnabled(boolean enabled) throws RemoteException {
        Log.d(TAG," setGpsEnabled()  enabled  " +enabled);
        mISettingFunctionIml.setGpsEnabled(enabled);
    }

    @Override
    public boolean isGpsEnabled() throws RemoteException {
        Log.d(TAG," isGpsEnabled() " );
        return mISettingFunctionIml.isGpsEnabled();
    }

    @Override
    public void setWIFIName(String wifiname) throws RemoteException {
        Log.d(TAG," setWIFIName()   wifiname  " +wifiname);
        mISettingFunctionIml.setWIFIName(wifiname);
    }

    @Override
    public String getWIFIName() throws RemoteException {
        Log.d(TAG," getWIFIName() " );
        return mISettingFunctionIml.getWIFIName();
    }

    @Override
    public void setWIFIPassword(String wifipassword) throws RemoteException {
        Log.d(TAG," setWIFIPassword()  wifipassword  " +wifipassword);
        mISettingFunctionIml.setWIFIPassword(wifipassword);
    }

    @Override
    public String getWIFIPassword() throws RemoteException {
        Log.d(TAG," getWIFIPassword()    " );
        return mISettingFunctionIml.getWIFIPassword();
    }

    @Override
    public void setRecordingEnabled(boolean enabled) throws RemoteException {
        Log.d(TAG," setRecordingEnabled()   enabled " +enabled);
        mISettingFunctionIml.setRecordingEnabled(enabled);
    }

    @Override
    public boolean isRecordingEnabled() throws RemoteException {
        Log.d(TAG," isRecordingEnabled()    " );
        return mISettingFunctionIml.isRecordingEnabled();
    }

    @Override
    public void setRecordingTime(int type) throws RemoteException {
        Log.d(TAG," setRecordingTime()   type  " +type);
        mISettingFunctionIml.setRecordingTime(type);
    }

    @Override
    public int getRecordingTime() throws RemoteException {
        Log.d(TAG," getRecordingTime()" );
        return mISettingFunctionIml.getRecordingTime();
    }

    @Override
    public void setCollisionSensitivity(int type) throws RemoteException {
        Log.d(TAG," setCollisionSensitivity()  type  " +type);
        mISettingFunctionIml.setCollisionSensitivity(type);
    }
    @Override
    public int getCollisionSensitivity() throws RemoteException {
        Log.d(TAG," getCollisionSensitivity()");
        return mISettingFunctionIml.getCollisionSensitivity();
    }
    @Override
    public void setVolumeMute(boolean mute) throws RemoteException {
        Log.d(TAG," setVolumeMute()  mute  " +mute);
        mISettingFunctionIml.setVolumeMute(mute);
    }

    @Override
    public boolean isVolumeMute() throws RemoteException {
        Log.d(TAG," isVolumeMute()    ");
        return mISettingFunctionIml.isVolumeMute();
    }

    @Override
    public void setVolumeLevel(int level) throws RemoteException {
        Log.d(TAG," setVolumeLevel()   level "+level);
        mISettingFunctionIml.setVolumeLevel(level);
    }

    @Override
    public int getVolumeLevel() throws RemoteException {
        Log.d(TAG," getVolumeLevel()   ");
        return mISettingFunctionIml.getVolumeLevel();
    }

    @Override
    public long getStorageTotalSize() throws RemoteException {
        Log.d(TAG," getStorageSize()   ");
        return mISettingFunctionIml.getStorageTotalSize();
    }
    @Override
    public long getStorageRemainingSize() throws RemoteException {
        Log.d(TAG," getStorageRemainingSize()   ");
        return mISettingFunctionIml.getStorageRemainingSize();
    }
    @Override
    public void setFormatStorage(boolean enabled) throws RemoteException {
        Log.d(TAG," setFormatStorage()   enabled  "+enabled);
        mISettingFunctionIml.setFormatStorage(enabled);
    }

    @Override
    public void setSystemUpgrade(boolean enabled) throws RemoteException {
        Log.d(TAG," setSystemUpgrade()   enabled  "+enabled);
        mISettingFunctionIml.setSystemUpgrade(enabled);
    }

    @Override
    public void setApplicationUpgrade(boolean enabled) throws RemoteException {
        Log.d(TAG," setApplicationUpgrade()   enabled  "+enabled);
    }
}
创建一个ISettingToServer.aidl文件
interface ISettingToServer {
     void setMobileDataEnabled(in boolean enabled);
     boolean isMobileDataEnabled();
     void setGpsEnabled(in boolean enabled);
     boolean isGpsEnabled();
     void setWIFIName(String wifiname);
     String getWIFIName();
     void setWIFIPassword(String wifipassword);
     String getWIFIPassword();
     void setRecordingEnabled(in boolean enabled);
     boolean isRecordingEnabled();
     void setRecordingTime(int type);
     int getRecordingTime();
     void setCollisionSensitivity(int type);
     int getCollisionSensitivity();
     void setVolumeMute(in boolean mute);
     boolean isVolumeMute();
     void setVolumeLevel(int level);
     int getVolumeLevel();
     long getStorageTotalSize();
     long getStorageRemainingSize();
     void setFormatStorage(in boolean enabled);
     void setSystemUpgrade(in boolean enabled);
     void setApplicationUpgrade(in boolean enabled);
}

然后在AndroidManifest.xml文件中注册服务

<service android:name="com.zqc.qcsettings.SettingsServer">
            <intent-filter>
                <action android:name="com.zqc.qcsettings.SettingsServer"/>
            </intent-filter>
        </service>

在mk文件中添加aidl参与编译

LOCAL_SRC_FILES := $(call all-java-files-under, src) \
src/com/zqc/qcsettings/ISettingToServer.aidl

客户端
创建MainActivity.java然后绑定服务

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "";
    private ISettingToServer mISettingToServer;
    public static final String BASE_PATH = "/storage/sdcard0";
    public static final String VIDEO_DIR = "/DCIM/";
    public static final String DIRECTORY_VIDEO = BASE_PATH + VIDEO_DIR;
    private ServiceConnection conn = new ServiceConnection() {
        //服务连接上的时候调用这个方法
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d(TAG, "onServiceConnected()");
            //拿到了远程的服务
            mISettingToServer = ISettingToServer.Stub.asInterface(service);
        }

        //当服务断开的时候调用这个方法
        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.d(TAG, "onServiceDisconnected()");
            //回收资源
            mISettingToServer = null;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //绑定服务
        bindServers();
    }

    //绑定服务
    public void onSetOnclick(View view) {
        try {
            //调用远程aidl服务,这样就可以实现进程间通信了
            if(mISettingToServer!=null){
                mISettingToServer.setVolumeMute(true);
            }

        } catch (RemoteException e) {
            e.printStackTrace();
        }
//        Date date = new Date();
//        String dataForm = new SimpleDateFormat("yyyy-MM-dd").format(date);
//        String path=DIRECTORY_VIDEO+"/"+dataForm;
//        Log.d(TAG, "path=" +path);
//        File f = new File(path);
//        if(!f.exists()){
//            f.mkdirs();
//        }

    }

    public void onGetOnclick(View view) {
        try {
            //调用远程aidl服务,这样就可以实现进程间通信了
            if(mISettingToServer!=null) {
                mISettingToServer.setVolumeMute(false);
            }
        } catch (RemoteException e) {
            e.printStackTrace();
        }

    }
    public void onGetDataclick(View view) {
        try {
            //调用远程aidl服务,这样就可以实现进程间通信了
            if(mISettingToServer!=null) {
                Toast.makeText(this," "+mISettingToServer.isVolumeMute(),Toast.LENGTH_LONG).show();
            }
        } catch (RemoteException e) {
            e.printStackTrace();
        }

    }
    public void bindServers() {
        //获取到服务端
        Intent intent = new Intent();
        intent.setComponent(new ComponentName("com.zqc.camera", "com.zqc.qcsettings.YlfSettingsServer"));
        boolean  isBindService = bindService(intent, conn, Context.BIND_AUTO_CREATE);
        Log.d(TAG, "  isBindService  " +isBindService);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy()");
        //解绑服务
        if (conn != null) {
            unbindService(conn);
            conn = null;

        }
    }
}

把服务中创建的aidl文件也复制到客户端来

interface ISettingToServer {
    void setMobileDataEnabled(in boolean enabled);
    boolean isMobileDataEnabled();
    void setGpsEnabled(in boolean enabled);
    boolean isGpsEnabled();
    void setWIFIName(String wifiname);
    String getWIFIName();
    void setWIFIPassword(String wifipassword);
    String getWIFIPassword();
    void setRecordingEnabled(in boolean enabled);
    boolean isRecordingEnabled();
    void setRecordingTime(int type);
    int getRecordingTime();
    void setCollisionSensitivity(int type);
    int getCollisionSensitivity();
    void setVolumeMute(in boolean mute);
    boolean isVolumeMute();
    void setVolumeLevel(int level);
    int getVolumeLevel();
    int getStorageSize(String totalSize,String remainingSize);
    void setFormatStorage(in boolean enabled);
    void setSystemUpgrade(in boolean enabled);
    void setApplicationUpgrade(in boolean enabled);
}

在这里插入图片描述备注说明:
如果有实体类类型,在服务端添加了,在客户端也要添加,这样要保证同步,最好是添加在一个包中便于后面好维护

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值