在写此篇前,笔者已经对消息机制有个大概的了解。但是此篇中又出现Messenger,Message,Binder,handle,bundle的一大堆错综复杂的关系,所以暂不对他们关系进行解释,只是简单得描述步骤。
至于Messenger,大家可以理解成轻量级的AIDL的通信手段。
要进行IPC,我们这可以分成两种情况
服务和客户端(界面)在同一个应用不同进程
如何让两者同在一个应用不同进程,可以参考Service的xml属性解析,指定process属性即可。
服务的代码编写
指定属性
<service android:name=".MyService"
android:process=":myremote"></service>
public class MyService extends Service {
private static final String TAG = "yjm";
private static class abchandle extends Handler{
@Override
public void handleMessage(Message msg) {
if(msg.what==1){
Log.e(TAG,msg.getData().getString("msg"));
}
super.handleMessage(msg);
}
}
private Messenger messenger=new Messenger(new abchandle());
@Nullable
@Override
public IBinder onBind(Intent intent) {
return messenger.getBinder();
}
}
客户端的代码编写
public class MainActivity extends AppCompatActivity {
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Messenger messenger = new Messenger(iBinder);
Message message = Message.obtain(null, 1);
Bundle bundle = new Bundle();
bundle.putString("msg","msgisme");
message.setData(bundle);
try {
messenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(MainActivity.this, MyService.class);
bindService(intent,mConnection,BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
unbindService(mConnection);
super.onDestroy();
}
}
服务和客户端(界面)不在同一个应用
服务的代码编写
(要进行IPC前提,让服务可以被找到,设置下面属性)
<service android:name=".MyService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.kt.abc"></action>
<category android:name="android.intent.category.DEFAULT"></category>
</intent-filter>
</service>
public class MyService extends Service {
public MyService() {
}
@Override
public void onCreate() {
super.onCreate();
}
private static class Abchandle extends Handler{
@Override
public void handleMessage(Message msg) {
if(msg.what==1){
Bundle bundles = msg.getData();
//1.这句话至关重要,如果你传的是基础类型那不提了,如果是自定义对象,就要序列化
//还要加上这句话,不然会显示类找不到的错误,,至于为什么 ,看最后抄来的
//2.自定义类的包名,要和服务端的类高度一致,特别是包名!不然即使加上下面的话也没用
bundles.setClassLoader(Thread.currentThread().getContextClassLoader());
Book msg1 = bundles.getParcelable("msg");
Log.e("yjm", msg1.toString());
}
super.handleMessage(msg);
}
}
private Messenger messenger=new Messenger(new Abchandle());
@Nullable
@Override
public IBinder onBind(Intent intent) {
return messenger.getBinder();
}
}
客户端(界面)的代码编写
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//这里的绑定方式稍微有点不同
Intent intent = new Intent();
intent.setPackage("com.kt.ktservice");
intent.setAction("com.kt.abc");
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Messenger messenger = new Messenger(service);
Message msg = Message.obtain(null, 1);
Bundle bundle = new Bundle();
bundle.putParcelable("msg",new Book("haha2"));
msg.setData(bundle);
try {
messenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
}
前面的示例都是客户端想服务端发送消息,如果服务端想客户端发送消息,则做法如下(这里以同一个应用不同进程举例)。客服端在向服务端发送消息时,顺便发送一个Messenger过去,到时候服务端就拿这个发送消息。
客户端的代码编写
public class MainActivity extends AppCompatActivity {
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Messenger messenger = new Messenger(iBinder);
Message message = Message.obtain(null, 1);
Bundle bundle = new Bundle();
bundle.putString("msg","msgisme");
message.setData(bundle);
//顺便发送一个Messenger过去,但是服务端就拿这个发送
message.replyTo=reMessenger;
try {
messenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
private static class recevierHandle extends Handler{
@Override
public void handleMessage(Message msg) {
if(msg.what==2){
Log.e("yjm",msg.getData().getString("re"));
}
super.handleMessage(msg);
}
}
private Messenger reMessenger=new Messenger(new recevierHandle());
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(MainActivity.this, MyService.class);
bindService(intent,mConnection,BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
unbindService(mConnection);
super.onDestroy();
}
}
服务的代码编写
public class MyService extends Service {
private static final String TAG = "yjm";
private static class abchandle extends Handler{
@Override
public void handleMessage(Message msg) {
if(msg.what==1){
Log.e(TAG,msg.getData().getString("msg"));
//使用客户端发送过来的Messenger发送消息
Messenger replyTo = msg.replyTo;
Message remessage = Message.obtain(null, 2);
Bundle bundle = new Bundle();
bundle.putString("re","reply");
remessage.setData(bundle);
try {
replyTo.send(remessage);
} catch (RemoteException e) {
e.printStackTrace();
}
}
super.handleMessage(msg);
}
}
private Messenger messenger=new Messenger(new abchandle());
@Nullable
@Override
public IBinder onBind(Intent intent) {
return messenger.getBinder();
}
}
最后
笔者自己标注:使用AIDL进行IPC的那一篇文章只试过不同应用的通信,还没验证过同个应用不同进程,但是应该一样,主要就是改下绑定方式,服务属性,而自定义类和AIDL接口文件在同一个应用中就都不用改了
bundles.setClassLoader(Thread.currentThread().getContextClassLoader());
这段话用于获取客户端发送过来的Book信息,难点在于bundles为什么要设置当前环境的类的加载器,前面说过,Messenger远程通信,归根到底是Parcel在起作用,因此传递的对象必须是实现了Parcelable接口的对象,而ClassLoader类并没有实现,因此在传递过程中会丢失,所以需要重新加载当前环境的类的加载器去寻找User类别进行实例化。如果不设置,会报ClassNotFoundException错误。如果我们把上面的Log语句的注释去掉,系统会报空指针异常,很好的证明了ClassLoader类的消息并不能跨进程传输。
网友评论