Android多进程通信:Socket、ContentProvider、AIDL、Messenger
Socket多用于消息之间传递(聊天)
ContentProvider数据库提供共享数据(电话本)
AIDL提供相互认可的编程接口
Messenger是基于AIDL
Socket
多进程Socket.png通过Socket实现两个应用之间的通信,接收消息和发送消息。
因为基于Socket所以需要网络权限
<uses-permission android:name="android.permission.INTERNET" />
service端代码:
public class MyServerSocket implements Runnable {
private static final String TAG = "MyServerSocket";
ServerSocket server;
Socket client;
PrintWriter os;
BufferedReader is;
Handler handler;
public MyServerSocket(Handler handler) {
this.handler = handler;
}
/**
* 需要在自线程中发送消息,这里可以在主线程里调用send
* @param data
*/
@WorkerThread
public void send(final String data) {
new Thread(new Runnable() {
@Override
public void run() {
if (os != null) {
os.println(data);
os.flush();
}
}
}).start();
}
@Override
public void run() {
try {
server = new ServerSocket(8080);
client = server.accept();
InetAddress inetAddress = client.getInetAddress();
String ip = inetAddress.getHostAddress();
Log.d(TAG, "run-ip:" + ip);
os = new PrintWriter(client.getOutputStream());
is = new BufferedReader(new InputStreamReader(client.getInputStream()));
} catch (Exception e) {
e.printStackTrace();
}
String result = "";
while (true) {
try {
result = is.readLine();
Log.d(TAG, "run-result:" + result);
Message msg = handler.obtainMessage();
msg.obj = result;
msg.arg1 = 0x11;
handler.sendMessage(msg);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void close() {
try {
if (os != null) {
os.close();
}
if (is != null) {
is.close();
}
if (client != null) {
client.close();
}
if (server != null) {
server.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
service端连接、发送、关闭连接:
private MyServerSocket server;
private StringBuffer receiveData = new StringBuffer();
private Handler handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
if (msg.arg1 == 0x11) {
receiveData.append(msg.obj);
receiveData.append("\r\n");
Log.d(TAG, "收到client端消息:handleMessage-receiveData:" + receiveData.toString());
}
return false;
}
});
public void link(View view) {
Log.d(TAG,"link");
server = new MyServerSocket(handler);
new Thread(server).start();
}
private int count = 0;
public void send(View view) {
++count;
Log.d(TAG,"send:"+count);
server.send("message:" + count);
}
public void close(View view) {
Log.d(TAG,"close");
server.close();
}
client端代码:
public class MyClientSocket implements Runnable {
private int timeout = 30000;
Socket client;
PrintWriter os;
BufferedReader is;
Handler handler;
public MyClientSocket(Handler handler) {
this.handler = handler;
}
/**
* 需要在自线程中发送消息,这里可以在主线程里调用send
* @param data
*/
@WorkerThread
public void send(final String data) {
new Thread(new Runnable() {
@Override
public void run() {
if (os != null) {
os.println(data);
try {
os.flush();
}catch (Exception e){
e.printStackTrace();
}
}
}
}).start();
}
@Override
public void run() {
try {
client = new Socket("localhost", 8080);
client.setSoTimeout(timeout);
os = new PrintWriter(client.getOutputStream());
is = new BufferedReader(new InputStreamReader(client.getInputStream()));
} catch (Exception e) {
e.printStackTrace();
}
String result = "";
while (true) {
try {
result = is.readLine();
Message msg = handler.obtainMessage();
msg.arg1 = 0x12;
msg.obj = result;
handler.sendMessage(msg);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void close() {
try {
if (os != null) {
os.close();
}
if (is != null) {
is.close();
}
if (client != null) {
client.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
client端连接、发送、关闭操作:
MyClientSocket client;
StringBuffer receiveData = new StringBuffer();
Handler handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
if (msg.arg1 == 0x12) {
receiveData.append(msg.obj);
Log.d(TAG, "收到service端消息receiveData:" + receiveData.toString());
receiveData.append("\r\n");
}
return false;
}
});
public void link(View view) {
Log.d(TAG, "start");
client = new MyClientSocket(handler);
new Thread(client).start();
}
public void close(View view) {
Log.d(TAG, "close");
client.close();
}
int count = 0;
public void send(View view) {
++count;
Log.d(TAG, "send:" + count);
client.send("client send:" + count);
}
ContentProvider
多进程ContentProvider.png不同应用程序之间共享数据,底层Binder实现,为存储和获取数据提供统一接口
Service端代码共享数据库:
public class DbOpenHelper extends SQLiteOpenHelper {
private static final String TAG = "DbOpenHelper";
private static final String DB_NAME = "provider.db";
private static final int DB_VERSION = 1;
public static final String TABLE_TEST = "my_provide";
private String mCreateTable = "create table if not exists "+TABLE_TEST+"(id integer primary key,"+"name TEXT, "+"sex TEXT)";
public DbOpenHelper(Context context) {
super(context,DB_NAME,null,DB_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
Log.d(TAG,"onCreate");
db.execSQL(mCreateTable);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { }
}
public class TestProvider extends ContentProvider {
private static final String TAG = "TestProvider-测试-app2";
public static final String AUTHORITY = "com.example.george.TestProvider";// 提供凭证;用于两个app之间的通信
private static final UriMatcher mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
private SQLiteDatabase mDb;
private Context mContext;
private String mTable;
static {
mUriMatcher.addURI(AUTHORITY, "student", 0);
}
@Override
public boolean onCreate() {
Log.d(TAG, "onCreate");
mTable = DbOpenHelper.TABLE_TEST;
mContext = getContext();//ContentProvider的onCreate执行在Application的onCreate之前
initProvider();
return false;
}
private void initProvider() {
mDb = new DbOpenHelper(mContext).getWritableDatabase();
}
@Override
public Bundle call(String method,
String arg,
Bundle extras) {
Log.d(TAG, "call-method:");
Bundle bundle = new Bundle();
bundle.putString(method, "xiaowang");
return bundle;
}
@Override
public Cursor query(Uri uri,
String[] projection,
String selection,
String[] selectionArgs,
String sortOrder) {
Log.d(TAG, "query-");
String table = DbOpenHelper.TABLE_TEST;
Cursor mCursor = mDb.query(table, projection, selection, selectionArgs, null, sortOrder, null);
return mCursor;
}
@Override
public String getType(Uri uri) {
return null;
}
@Override
public Uri insert(Uri uri,
ContentValues values) {
Log.d(TAG, "insert");
mDb.insert(mTable, null, values);
return null;
}
@Override
public int delete(Uri uri,
String selection,
String[] selectionArgs) {
return 0;
}
@Override
public int update(Uri uri,
ContentValues values,
String selection,
String[] selectionArgs) {
return 0;
}
}
在AndroidManifest.xml中注册
<provider
android:authorities="com.example.george.TestProvider"
android:name=".TestProvider"
android:process=":provider"
android:exported="true"
/>
Client端获取ContentProvider提供的数据
Uri uri = Uri.parse(AUTHORITY);
ContentValues mContentValues = new ContentValues();
mContentValues.put(ID, 34);
mContentValues.put(NAME, "小王");
mContentValues.put(SEX, "男");
getContentResolver().insert(uri, mContentValues);// 根据 凭证 插入到数据库
Cursor cursor = getContentResolver().query(uri, new String[]{NAME, SEX}, null, null, null);// 根据 凭证 获取数据库
while (cursor.moveToNext()) {
Student student = new Student(cursor.getString(0), cursor.getString(1));
Log.d(TAG, "name:" + student.mName + " sex:" + student.mSex);
}
Bundle bundle = getContentResolver().call(uri, METHOD, null, null);
Log.d(TAG, "method:" + bundle.getString(METHOD));
AIDL
多进程AIDL.png两个不同app之间通信
在AndroidStudio中新建Person.aidl。会在main/aidl/xxx.Person.aidl。然后make project生成中间代码。
Service 端代码:
interface Person {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
String getName();
}
在AndroidManifest.xml中注册,由于是两个app通信,则 enabled="true" 可用,android:exported="true"允许外部app访问。
<service android:name="com.example.george.androidutils.MyService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.example.george.action.MyService" />
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>
MyService.java代码如下:
public class MyService extends Service {
private static final String TAG = "MyService-测试-app1";
public MyService() {
Log.d(TAG,"MyService");
}
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG,"IBinder");
return new MyBinder();
}
class MyBinder extends Person.Stub{
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public String getName() throws RemoteException {
Log.d(TAG,"getName");
return "456";
}
}
}
另一个app客户端代码,在api21之后严格要求必须写入类名,否则无法启动另外一个app的service。
Client代码:
intent.setClassName("com.example.george.androidutils","com.example.george.androidutils.MyService");
或者
intent.setComponent(new ComponentName("com.example.george.androidutils", "com.example.george.androidutils.MyService"));
这里采用第二种。
public void connnect(View view) {
Intent intent = new Intent();
// intent.setPackage("com.example.george.androidutils");
// intent.setAction("com.example.george.action.MyService");
// intent.setClassName("com.example.george.androidutils","com.example.george.androidutils.MyService");
intent.setComponent(new ComponentName("com.example.george.androidutils", "com.example.george.androidutils.MyService"));
bindService(intent, new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Person person = Person.Stub.asInterface(service);
Log.d(TAG, "onServiceConnected-componentName:" + name);
try {
Log.d(TAG, "onServiceConnected-person:" + (person == null ? "null" : person.getName()));
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG, "onServiceDisconnected-componentName:" + name);
}
}, BIND_AUTO_CREATE);
}
Messenger
是基于AIDL实现的,服务端(被动)Service处理客户端(主动),用Handler来创建Messenger,在onBinder返回Messenger的binder。双方用Messenger发送数据,用handler(串行)处理数据。多个message排队依次处理。
多进程Messenger.png
在AndroidManifest.xml中注册
<service android:name=".MessengerService"
android:process=":remote"/>
服务端代码:
public class MessengerService extends Service {
private static final String TAG = "MessengerService-测试";
Messenger mMessenger = new Messenger(new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1:
Log.d(TAG, "handleMessage-接收客户端消息");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Messenger messenger = msg.replyTo;
try {
Log.d(TAG, "handleMessage-向客户端发送消息");
messenger.send(Message.obtain(null, 1, 0, 0));
} catch (RemoteException e) {
e.printStackTrace();
}
break;
}
}
});
@Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
}
客户端代码:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity-测试";
private boolean mMessengerIsConnect;
private Messenger mMessenger = new Messenger(new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1:
Log.d(TAG, "handleMessage-客户端收到消息");
break;
}
}
});
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG, "onServiceConnected-建立连接");
mMessengerIsConnect = true;
Messenger messenger = new Messenger(service);
Message message = Message.obtain(null, 1, 0, 0);
message.replyTo = mMessenger;
try {
Log.d(TAG, "onServiceConnected-向服务端发送消息");
messenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {// 连接正常关闭不会被调用。何时调用:系统资源不足,要关闭一些service
mMessengerIsConnect = false;
Log.d(TAG, "onServiceConnected-断开连接");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void link(View view) {
if (!mMessengerIsConnect)
bindService(new Intent(this, MessengerService.class), mConnection, Context.BIND_AUTO_CREATE);
}
public void unLink(View view) {
if (mMessengerIsConnect){
mMessengerIsConnect = false;
unbindService(mConnection);
}
}
}
网友评论