1.Android中的IPC方式
(1)使用Bunder
四大组件中的三大组件(Activity、Service、Receiver)都支持在Intent中传递Bundle数据的,由于Bundle实现了Parcelable接口,所以它可以在不同进程间传输。
(2)使用文件共享
文件共享也是一种不错的进程间通信方式,两个进程通过读/写一个文件来交换数据,A进程把数据写入文件,B进程读取文件获取数据。
MainActivity和SecondActivity属于不同的进程
在MainActivity写入数据,在SecondActivity读取数据
首先,在清单文件中加入sd卡读写的权限
<!-- 在SDCard中创建与删除文件权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<!-- 往SDCard写入数据权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
实现Serializable接口的Java类
package com.zhoujian.ipc.bean;
import java.io.Serializable;
/**
* Created by zhoujian on 2017/2/24.
*/
public class User implements Serializable{
private static final long serialVersionUID = 1L;
private int userId;
private String userName;
private boolean isMale;
public User(boolean isMale, int userId, String userName) {
this.isMale = isMale;
this.userId = userId;
this.userName = userName;
}
public boolean isMale() {
return isMale;
}
public void setMale(boolean male) {
isMale = male;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
@Override
public String toString() {
return "User{" +
"isMale=" + isMale +
", userId=" + userId +
", userName='" + userName + '\'' +
'}';
}
}
在MainActivity中写入数据
private void saveData()
{
new Thread(new Runnable()
{
@Override
public void run()
{
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
File file = Environment.getExternalStorageDirectory();
File saveFile = new File(file,"zhoujian.txt");
ObjectOutputStream outputStream = null;
try {
User use = new User(true,1,"周建");
outputStream = new ObjectOutputStream(new FileOutputStream(saveFile));
outputStream.writeObject(use);
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();
}
在SecondActivity中读取数据
private void readData()
{
new Thread()
{
@Override
public void run()
{
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
File file = Environment.getExternalStorageDirectory();
File files = new File(file,"zhoujian.txt");
ObjectInputStream in = null;
try
{
in = new ObjectInputStream(new FileInputStream(files));
User usr = (User)in.readObject();
Log.d(TAG, "获取数据成功:"+ usr.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}.start();
}
注意:SharedPreferences是Android中提供的轻量级存储方案,它通过键值对来存储数据,在底层是采用XML来存储键值对,每个应用的SharedPreferences文件都可以在当前包所在的data目录下查看到。一般位于/data/data/package name/shared_prefs目录下,由于系统对SharedPreferences的读写有一定的缓存策略,即在内存中会有一份SharedPreferences文件的缓存,因此在多进程模式下,系统对它的读写就变得不可靠
(3)使用Messenger
Messenger:信使,通过它可以在不同进程中传递Message对象,Messenger是一种轻量级的IPC,底层实现是AIDL
我们从Messenger的构造方法可以看出
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
Messenger对AIDL进行了封装,Messenger一次处理一个请求,因此服务端不用考虑线程同步的问题,这是因为服务端中不存在并发执行的情形。
下面以一个具体的实例,来说明Messenger如何实现进程间通信
服务端:MessengerService,服务端与客户端位于不同的进程
MessengerService.java
package com.zhoujian.ipc.service;
import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
/**
* Created by zhoujian on 2017/2/28.
*/
public class MessengerService extends Service{
public static final String TAG = "MessengerService";
public static final int MSG_FROM_CLIENT = 1;
public static final int MSG_FROM_SERVICE = 2;
class mHandler extends Handler
{
@Override
public void handleMessage(Message msg)
{
switch (msg.what)
{
case MSG_FROM_CLIENT:
String message = msg.getData().getString("msg");
Log.d(TAG, "消息来自客户端:"+message);
//接受到客户端的消息后,给客户端回复消息
Messenger mMessenger = msg.replyTo;
//创建消息
Message mMessage = Message.obtain(null,MSG_FROM_SERVICE);
Bundle mBundle = new Bundle();
mBundle.putString("message","您好客户端!你的消息我已经收到");
mMessage.setData(mBundle);
try {
//使用信使Messenger发送消息
mMessenger.send(mMessage);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
default:
super.handleMessage(msg);
}
}
}
//创建信使Messenger,传入Handler
Messenger mMessenger = new Messenger(new mHandler());
@Override
public IBinder onBind(Intent intent)
{
//返回Messenger的getBinder对象
return mMessenger.getBinder();
}
}
客户端:MessengerActivity.java
package com.zhoujian.ipc.activity;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
import com.zhoujian.ipc.R;
import com.zhoujian.ipc.service.MessengerService;
/**
* Created by zhoujian on 2017/2/28.
*/
public class MessengerActivity extends Activity
{
public static final String TAG = "MessengerActivity";
public static final int MSG_FROM_CLIENT = 1;
public static final int MSG_FROM_SERVICE = 2;
//接受服务端发送过来的消息
Messenger mMsg = new Messenger(new Handler(){
private String mMessage;
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_FROM_SERVICE:
mMessage = msg.getData().getString("message");
Log.d(TAG, "消息来自服务端:"+mMessage);
break;
default:
super.handleMessage(msg);
}
}
});
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_messenger);
Intent intent = new Intent(MessengerActivity.this, MessengerService.class);
//绑定服务
bindService(intent, comm, Context.BIND_AUTO_CREATE);
}
ServiceConnection comm = new ServiceConnection()
{
private Messenger mMessenger;
@Override
public void onServiceConnected(ComponentName name, IBinder service)
{
//创建信使
mMessenger = new Messenger(service);
//创建消息
Message message = Message.obtain(null,MSG_FROM_CLIENT);
//创建Bundle,存入消息
Bundle bundle = new Bundle();
bundle.putString("msg","你好!我是客户端");
message.setData(bundle);
//重要
message.replyTo= mMsg;
try
{
//使用信使发送消息
mMessenger.send(message);
}
catch (RemoteException e)
{
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name)
{
}
};
}
(4)使用AIDL
Messenger是以串行的方式处理客户端发来的消息,如果大量的消息同时发送到服务端,服务端也只能一个一个处理,如果有大量的并发请求,Messenger就不合适了。
AIDL进行进程间通信
服务端
服务端首先要创建一个Service来监听客户端的连接请求,然后创建一个AIDL文件,将暴露给客户端的接口在这个AIDL文件中声明,最后在Service中实现这个AIDL接口
客户端
客户端要绑定服务端的Service,绑定成功后,将服务端返回的Binder对象转成AIDL接口所属的类型,接着就可以调用AIDL中的方法了。
AIDL接口的创建
IBookManager.aidl
import com.zhoujian.ipc.aidl.Book;
// Declare any non-default types here with import statements
interface IBookManager {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
List<Book> getBookList();
void addBook(in Book book);
}
AIDL文件中,并不是所有的数据类型都是可以使用的,AIDL支持的数据类型
- 基本数据类型
- String和CharSequence
- List,只支持ArrayList,里面的每一个元素都必须能够被AIDL支持
- Map,只支持HashMap,里面的每一个元素都必须能够被AIDL支持,包括key和value
- Parcelable:所有实现Parcelable接口的对象
- AIDL:所有的AIDL接口本身也可以在AIDL文件中使用
以上6种数据类型就是AIDL所支持的所有类型,其中自定义Parcelable对象和AIDL对象必须显示import进来。
注意:如果AIDL文件中使用到了自定义的Parcelable对象,那么必须新建一个和它同名的AIDL文件,并在其中声明Parcelable类型。在上面的IBookManager.aidl中,我们用到了Book这个类,所以我们必须创建Book.aidl
Book.aidl
// Book.aidl
package com.zhoujian.ipc.aidl;
// Declare any non-default types here with import statements
parcelable Book;
注意:AIDL中每个实现了Parcelable接口的类都需要按照上面方式去创建相应的AIDL文件并声明那个类为parcelable。除此之外,AIDL中除了基本数据类型,其他类型的参数必须标上方向:in、out或者inout。in表示输入型参数,out表示输出型参数,inout表示输入输出型参数。AIDL接口只支持方法,不支持声明静态常量。
远程服务端的实现,服务端和客户端位于不同进程
<service
android:name=".service.BookManagerService"
android:process=":romote"/>
BookManagerService.java
package com.zhoujian.ipc.service;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import com.zhoujian.ipc.aidl.Book;
import com.zhoujian.ipc.aidl.IBookManager;
import com.zhoujian.ipc.aidl.INewBookArrivedListener;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Created by zhoujian on 2017/2/28.
*/
public class BookManagerService extends Service {
private AtomicBoolean mBoolean = new AtomicBoolean(false);
public static final String TAG = "BookManagerService";
//CopyOnWriteArrayList支持并发的读写
CopyOnWriteArrayList<Book> bookList= new CopyOnWriteArrayList<Book>();
RemoteCallbackList<INewBookArrivedListener> listeners = new RemoteCallbackList<>();
private int mInt;
@Override
public void onCreate() {
super.onCreate();
// AtomicBoolean
//添加两本书
bookList.add(new Book(1,"安卓书籍一"));
bookList.add(new Book(2,"安卓书籍二"));
//开启一个线程,每隔5秒向书库中增加一本书,并通知感兴趣的用户
new Thread(new ServiceWork()).start();
}
class ServiceWork implements Runnable
{
@Override
public void run()
{
while (! mBoolean.get())
{
try
{
Thread.sleep(5000);
} catch (InterruptedException e)
{
e.printStackTrace();
}
int bookId = bookList.size()+1;
Book newBook = new Book(bookId,"安卓书籍"+bookId);
//有新的书籍到了
onNewBookArrived(newBook);
}
}
}
private void onNewBookArrived(Book book)
{
bookList.add(book);
mInt = listeners.beginBroadcast();
for (int i = 0; i <mInt; i++)
{
INewBookArrivedListener listener = listeners.getBroadcastItem(i);
if (listener != null)
{
try {
listener.onNewBookArrived(book);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
listeners.finishBroadcast();
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
//IBookManager类是AIDL文件对应的生成的java类
Binder mBinder = new IBookManager.Stub() {
@Override
public List<Book> getBookList() throws RemoteException
{
return bookList;
}
@Override
public void addBook(Book book) throws RemoteException {
bookList.add(book);
}
@Override
public void registListenner(INewBookArrivedListener listener) throws RemoteException
{
listeners.register(listener);
}
@Override
public void unregistListenner(INewBookArrivedListener listener) throws RemoteException
{
listeners.unregister(listener);
}
};
}
BookManagerActivity.java
package com.zhoujian.ipc.activity;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
import com.zhoujian.ipc.R;
import com.zhoujian.ipc.aidl.Book;
import com.zhoujian.ipc.aidl.IBookManager;
import com.zhoujian.ipc.aidl.INewBookArrivedListener;
import com.zhoujian.ipc.service.BookManagerService;
import java.util.List;
/**
*
* Created by zhoujian on 2017/2/28.
*/
public class BookManagerActivity extends Activity
{
public static final String TAG = "BookManagerActivity";
public static final int NEW_BOOK_ARRIVED= 0;
private IBookManager mIBookManager;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case NEW_BOOK_ARRIVED:
Log.e(TAG, "receive new book:"+(Book)msg.obj);
}
}
};
private INewBookArrivedListener listenner = new INewBookArrivedListener.Stub()
{
@Override
public void onNewBookArrived(Book newBook) throws RemoteException
{
mHandler.obtainMessage(NEW_BOOK_ARRIVED,newBook).sendToTarget();
}
};
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_book_manager);
Intent intent = new Intent(BookManagerActivity.this, BookManagerService.class);
bindService(intent,comm, Context.BIND_AUTO_CREATE);
}
ServiceConnection comm = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//获取IBookManager.aidl 文件
IBookManager bookManager = IBookManager.Stub.asInterface(service);
try
{
mIBookManager =bookManager;
//在客户端调用方法获取书籍
List<Book> bookList = bookManager.getBookList();
// Log.e(TAG, "查询的书籍为"+bookList.toString());
//在客户端再添加一本书
Book book = new Book(3,"安卓开发三");
bookManager.addBook(book);
Log.e(TAG, "新添加的书籍为:"+book.toString());
//再次获取所有书籍
List<Book> bookLists = bookManager.getBookList();
Log.e(TAG, "查询的书籍为"+bookLists.toString());
bookManager.registListenner(listenner);
}
catch (RemoteException e)
{
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onDestroy() {
super.onDestroy();
if(mIBookManager!=null && mIBookManager.asBinder().isBinderAlive()){
try {
mIBookManager.unregistListenner(listenner);
} catch (RemoteException e) {
e.printStackTrace();
}
}
unbindService(comm);
}
}
(5)使用ContentPrivider
请阅读我的另一篇博客:
ContentPrivider实现IPC:http://blog.csdn.net/u014005316/article/details/53407674
(6)使用Socket
请阅读我的另一篇博客:
Socket实现进程间通信:http://blog.csdn.net/u014005316/article/details/53419839