中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么在Android中利用Service實現IPC通信

發布時間:2021-04-20 16:57:25 來源:億速云 閱讀:222 作者:Leah 欄目:移動開發

本篇文章給大家分享的是有關怎么在Android中利用Service實現IPC通信,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

Android是什么

Android是一種基于Linux內核的自由及開放源代碼的操作系統,主要使用于移動設備,如智能手機和平板電腦,由美國Google公司和開放手機聯盟領導及開發。

借助AIDL實現IPC通信

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通信

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

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中利用Service實現IPC通信,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

克拉玛依市| 德安县| 新疆| 中西区| 重庆市| 阿鲁科尔沁旗| 若尔盖县| 安泽县| 林芝县| 岱山县| 同江市| 偏关县| 镇远县| 长治市| 桂林市| 台南县| 旌德县| 梧州市| 阿克苏市| 祁阳县| 阳泉市| 大丰市| 诸暨市| 邵阳县| 鹤山市| 通城县| 抚州市| 平阳县| 曲阳县| 嘉义市| 吴堡县| 天柱县| 鹰潭市| 报价| 富宁县| 绥阳县| 泰兴市| 贡嘎县| 吕梁市| 宝丰县| 大理市|