Android 跨进程通讯的方式
我已知Android 的跨进程通信方式有6种,分别为:访问他应用的Activity、接收其他应用的广播、访问其它应用的
开放数据、AIDL、Messenger和socket的跨进程通信。
(1)访问他应用的Activity
举一个简单的例子:
这个就是调用系统打电话的代码。这就是一个简单的Activity的跨进程通信。
private void test_1(){Intent callIntent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:123654789")); startActivity(callIntent); }
那么Activity跨进程是怎么实现的呢?
服务端:(注:服务端和客户端是不同应用)
<activityandroid:name="xyzefg.xxx.yyyy.cccc.ServiceActivity" ><intent-filter><action android:name="com.service.activity" /><category android:name="android.intent.category.DEFAULT" /><data android:scheme="service" /></intent-filter></activity>
public class ServiceActivity extends Activity{TextView tv ;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.service);if (getIntent().getData() != null) {String host = getIntent().getData().getHost();Bundle bundle = getIntent().getExtras();String value = bundle .getString("value");tv = (TextView) findViewById(R.id.tv);tv.setText(host+":"+value);}}
}
客户端:
private void test_2(){ Intent callIntent = new Intent("com.service.activity", Uri .parse("service://跨进程请求Activity" )); Bundle extras = new Bundle(); extras.putString("value", "我可是跨进程的"); callIntent.putExtras(extras); startActivity(callIntent); }
服务端主要实现分为三步:
1,设置启动的action <action/>
2,定义一个访问协议 <data/>
3,设置默认分类 <category/>
客户端:只要按照对应的action和协议就能请求到服务端的Activity
(2)接收其他应用的广播
举个简单的例子:
动态注册监听系统没分钟变化的广播。
private void registerTimeReceiver(){IntentFilter intentFilter = new IntentFilter();intentFilter.addAction(Intent.ACTION_TIME_CHANGED);intentFilter.addAction(Intent.ACTION_TIME_TICK);registerReceiver(myReceive, intentFilter);}BroadcastReceiver myReceive = new BroadcastReceiver(){@Overridepublic void onReceive(Context arg0, Intent arg1) {Log.d("TAG","触发了");}};
那么广播的跨进程是怎么实现的呢?
发送者:(注:发送者和接受者是不同的应用)
private void test_3(){Intent intent = new Intent("com.my.receiver");intent.putExtra("value", "我可是跨进程的");sendBroadcast(intent);}
接收者:
public class MyReceiver extends BroadcastReceiver{public final static String ACTION = "com.my.receiver";@Overridepublic void onReceive(Context arg0, Intent arg1) {if (arg1.getAction() == ACTION) {Log.d("TAG", arg1.getStringExtra("value"));}}
}
注册广播:
①动态注册:
private void registerTimeReceiver(){IntentFilter intentFilter = new IntentFilter();intentFilter.addAction(MyReceiver.ACTION);registerReceiver(myReceiver, intentFilter);}
② 静态 注册:
<receiver android:name="xyzefg.xxx.yyyy.cccc.MyReceiver" ><intent-filter><action android:name="com.my.receiver" /></intent-filter>
</receiver>
定义一个广播接收需要继承BroadcastReceiver 并从写里面的onReceiver 方法,并且不要忘记注册广播,并且指定广
播接收的Action。发送广播只需要定义一个意图对象的action指向接收的Receiver,然后调用sendBroadcast(Intent)。
(3)访问其它应用的开放数据
举一个简单的例子:
查询手机联系人。
private void test_4(){ContentResolver contentResolver = getContentResolver();Cursor cursor = contentResolver.query(android.provider.Contacts.Phones.CONTENT_URI, null, null, null, null);while (cursor.moveToNext()) {String name = cursor.getString(cursor.getColumnIndex(android.provider.Contacts.Phones.NAME));String num = cursor.getString(cursor.getColumnIndex(android.provider.Contacts.Phones.NUMBER));Log.d("TAG", "name:"+name+"\nPhoneNum:"+num);}}
相比上面2个ContentProvider相对来说是麻烦多了。
服务端:(注:服务端和客户端不是同一个应用)
Andriod:
package com.example.hellojni;import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;@DatabaseTable(tableName = "android")
public class Android {@DatabaseField(columnName="_id",generatedId = true)private Integer id;@DatabaseField(columnName = "name")private String name;@DatabaseField(columnName = "version")private String version;public Android() {}public Android(String name,String version){this.name = name;this.version = version;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getVersion() {return version;}public void setVersion(String version) {this.version = version;} }
DataBaseHelper:
package com.example.hellojni;import java.sql.SQLException;import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.table.TableUtils;public class DataBaseHelper extends OrmLiteSqliteOpenHelper{private final static String TABLENAME = "android";private static DataBaseHelper instance;private static Dao<Android, Integer> androidDao;private DataBaseHelper(Context context) {super(context, TABLENAME, null, 1);}public static synchronized DataBaseHelper getHelper(Context context) { if (instance == null) { synchronized (DataBaseHelper.class) { if (instance == null) instance = new DataBaseHelper(context.getApplicationContext()); } } return instance; } @Overridepublic void onCreate(SQLiteDatabase arg0, ConnectionSource arg1) {try {TableUtils.createTable(arg1, Android.class);} catch (SQLException e) {e.printStackTrace();}}@Overridepublic void onUpgrade(SQLiteDatabase arg0, ConnectionSource arg1, int arg2, int arg3) {try {TableUtils.dropTable(arg1, Android.class, true);onCreate(arg0, arg1);} catch (SQLException e) {e.printStackTrace();}}public Dao<Android, Integer> getAndroidDao(){if (androidDao == null) {try {androidDao = super.getDao(Android.class);} catch (SQLException e) {e.printStackTrace();}}return androidDao;}@Overridepublic void close() {super.close();if (androidDao !=null) {androidDao = null;}}}
ContentProvider:
package com.example.hellojni;import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;public class MyContentProvider extends ContentProvider{private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);private static final int CODE_NOPARAM = 1;private static final int CODE_PARAM = 2;private static final String AUTHORITIES = "cn.siy.provider.database";private static final String PATH_1 = "android";private static final String PATH_2 = "android/#";//集合类型,返回值前面一般是固定的,后面的值是自己添加的,也可以加上包路径 private static final String TYPE_ANDROIDS = "vnd.android.cursor.dir/" + "android"; //非集合类型数据,返回值前面一般是固定的,后面的值是自己添加的,也可以加上包路径 private static final String TYPE_ANDROID = "vnd.android.cursor.item/" + "android"; /*** content://cn.siy.provider.database/android/1/name* * 其中content://是scheme Android规定必须是content* cn.siy.provider.database 是Authority ContentProvider的唯一标示* /android/1/name 是path 指定对什么数据进行操作(对android表的id为1的name字段操作)*/DataBaseHelper helper;static{matcher.addURI(AUTHORITIES, PATH_1, CODE_NOPARAM);matcher.addURI(AUTHORITIES, PATH_2, CODE_PARAM);}@Overridepublic boolean onCreate() {helper = DataBaseHelper.getHelper(getContext());return true;}@Overridepublic int delete(Uri uri, String selection, String[] selectionArgs) {SQLiteDatabase sqLiteDatabase = helper.getWritableDatabase();int count =-1;switch (matcher.match(uri)) {case CODE_NOPARAM:count = sqLiteDatabase.delete(PATH_1, selection, selectionArgs);break;case CODE_PARAM:long id = ContentUris.parseId(uri);String where = "_id = " + id;if (null != selection && !"".equals(selection.trim())){where += " and " + selection;}count = sqLiteDatabase.delete(PATH_1, where, selectionArgs);break;default:break;}getContext().getContentResolver().notifyChange(uri, null);return count;}@Overridepublic String getType(Uri arg0) {switch (matcher.match(arg0)) {case CODE_NOPARAM:return TYPE_ANDROIDS;case CODE_PARAM:return TYPE_ANDROID;default:break;}return null;}@Overridepublic Uri insert(Uri url, ContentValues values) {SQLiteDatabase db = helper.getWritableDatabase();long id = -1;switch (matcher.match(url)){case CODE_NOPARAM:// 若主键值是自增长的id值则返回值为主键值,否则为行号,但行号并不是RecNo列id = db.insert(PATH_1, "name", values); break;default:break;}if (id>0) {Uri insertUri = ContentUris.withAppendedId(url, id); getContext().getContentResolver().notifyChange(insertUri, null);return insertUri;}return null;}@Overridepublic Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {SQLiteDatabase sqLiteDatabase = helper.getReadableDatabase();Cursor cursor = null;switch (matcher.match(uri)) {case CODE_NOPARAM:cursor = sqLiteDatabase.query(PATH_1, projection, selection, selectionArgs, null, null, sortOrder);break;case CODE_PARAM:long id = ContentUris.parseId(uri); // 取得跟在URI后面的数字String where = "_id = " + id;if (null != selection && !"".equals(selection.trim())){where += " and " + selection;}cursor = sqLiteDatabase.query(PATH_1, projection, where, selectionArgs, null, null, sortOrder);break;default:break;}cursor.setNotificationUri(getContext().getContentResolver(), uri);return cursor;}@Overridepublic int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {SQLiteDatabase sqLiteDatabase = helper.getWritableDatabase();int count = 0;switch (matcher.match(uri)) {case CODE_NOPARAM:count = sqLiteDatabase.update(PATH_1, values, selection, selectionArgs);break;case CODE_PARAM:long id = ContentUris.parseId(uri);String where = "_id = " + id;if (null != selection && !"".equals(selection.trim())){where += " and " + selection;}count = sqLiteDatabase.update(PATH_1, values, where, selectionArgs);default:break;}getContext().getContentResolver().notifyChange(uri, null);return count;}}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.testndk"android:versionCode="1"android:versionName="1.0" ><uses-sdkandroid:minSdkVersion="8"android:targetSdkVersion="18" /><uses-permission android:name="android.permission.INTERNET"/><uses-permission android:name="android.permission.CALL_PHONE"/><uses-permission android:name="android.permission.READ_CONTACTS" /><applicationandroid:allowBackup="true"android:icon="@drawable/ic_launcher"android:label="@string/app_name"android:theme="@style/AppTheme" ><activityandroid:name="com.example.hellojni.SiyActivity"android:label="@string/app_name" ><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><provider android:exported="true"android:name="com.example.hellojni.MyContentProvider"android:authorities="cn.siy.provider.database"></provider></application></manifest>
数据库的操作使用了ormlite框架。
首先我对ContentProvider中增删改查几个方法的参数解释一下吧,因为一开始我自己也是糊涂,这里记录一下防止下
次自己又忘记了。
1)delete(Uri uri, String selection, String[] selectionArgs);
第一个参数 uri:uri怎么解释呢?恩!就是每个内容提供者的唯一标示,用指定你访问的是哪一个内容提供者。
第二个参数 selecttion:他可以单独使用也可以和selectionArgs配合使用。先解释它怎么单独使用例如:
contentResolver.delete(Uri.parse("content://cn.siy.provider.database/android"), "_id in (14,13,12)", null);
上面语句的意思就是删除_id是12,13,14的记录,执行之后的结果
单独使用的时候他就相当于条件语句,放在where 之后。也可以传null表示删除所有。再看看它怎么和selectionArgs配合使用:
contentResolver.delete(Uri.parse("content://cn.siy.provider.database/android"), "_id in(?,?,?)", new String[]{"14","13","12"});
执行结果和上面的结果一样。selecttion你面有多少个“?”,selectionArgs里面就要有多少个数据进行相应的替换,特别注意顺序额!
第三个参数selectionArgs:他就是配合selecttion的,如果selecttion是空的,它也可以传null。
2)insert(Uri uri, ContentValues values)
第一个参数uri:同上不做解释。
第二个参数 values:他是一个类似map的数据结构,可以put进键值对,key是表结构的列名,value是列名对应的值,具体用法如:
ContentValues contentValues = new ContentValues();
contentValues.put("name", "Android-N");
contentValues.put("version", "7.0");
contentResolver.insert(Uri.parse("content://cn.siy.provider.database/android"), contentValues);
3)query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
第一个参数uri:同上不做解释。
第二个参数projection:它表示查询后要显示的列名,可以传null表示查询显示所有,类似如sql语句的“*”。
第三个参数selection:同上不解释。
第四个参数selectionArgs:同上不解释。
第五参数sortOrder:它是指按照什么顺序排序,相当于sql的order by。具体用法如:
Cursor cursor = contentResolver.query(Uri.parse("content://cn.siy.provider.database/android"), null, null, null, "_id desc");
4)update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
参数的意思都能在上面找到我就不说了。
要编写ContentProvider:
1,要继承要写一个类继承ContentProvider然后重写里面的方法,一般会有onCreate(),getType(),delete(),insert(),query(),update()。
2,指定一个唯一标示当前provider的uri。provider的uri的规则content://+Authority+path。content://是Android规定的不允许更改的,Authority自己指定作为provider的唯一标示,最好两级以上,何为两级以上呢?自己领悟!path是标示
操作对象一般表名什么。
举个例子吧:
content://cn.siy.provider.database/android/1/name
其中content://是scheme Android规定必须是content
cn.siy.provider.database 是Authority ContentProvider的唯一标示
/android/1/name 是path 指定对什么数据进行操作(对android表的id为1的name字段操作)
3,既然uri里面包含这么多信息,那么provider怎么知道呢?Android为我们提供UriMatcher这个类,它允许我们将定
义好的uri添加到其中。
private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);static{matcher.addURI(AUTHORITIES, PATH_1, CODE_NOPARAM);matcher.addURI(AUTHORITIES, PATH_2, CODE_PARAM);}
UriMatcher.NO_MATCH是匹配失败返回的值为-1。CODE_NOPARAM表示匹配path_1返回的值,CODE_PARAM表
示path_2返回的值。其中“匹配”动作可以通过matcher.match(uri)方法实现,这样就可以通过不同的返回值来进行不同的操作了。
4,既然provider是的四大组件之一(Activity,receiver,service,provider),那么它也是要在AndroidManifest.xml注册的。
<provider android:exported="true"android:name="com.example.hellojni.MyContentProvider"android:authorities="cn.siy.provider.database">
</provider>
authorities就是上面说的uri中的authorities,name就是ContentProvider的全类名,exported为true表示它对其他应用可
见。
要使用provider:
1,首先你得有ContentResolver,这个你一调用Activity的getContentResolver()得到。
2, 然后通过ContentResolver的增删改查方法就可以调用provider的增删改查方法了,参数名的意思上面有说。
3,Uri.parse("content://cn.siy.provider.database/android")把字符串编程uri
到此provider的简单实用就解释完了,不说了。
(4)AIDL
例子不知道怎么举了,那就直接上代码吧!
服务端:(注:服务端和客户端不是同一个应用)
IService.aidl
package com.example.mytest.zoomInImanage;import com.example.mytest.zoomInImanage.Android;interface IService{/** 八种基本类型 shot 会报错额**/String input1(byte arg1,/**shot arg2,**/int arg3,char arg4,boolean arg5,float arg6,double arg7,long arg8);String input2(String arg1,CharSequence arg2);/** 需要使用in、out或inout修饰。其中in表示这个值被客户端设置;out表示这个值被服务端设置;inout表示这个值既被客户端设置,又被服务端设置。 **/Android input3(in List<String> arg1,in Map arg2);/** 必须要导包 **/String input4(in Android arg1);
}
Android.java(其实就是上面的Android类实现了Parcelable,哈哈...)
package com.example.mytest.zoomInImanage;import android.os.Parcel;
import android.os.Parcelable;import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;@DatabaseTable(tableName = "android")
public class Android implements Parcelable {@DatabaseField(columnName = "_id", generatedId = true)private Integer id;@DatabaseField(columnName = "name")private String name;@DatabaseField(columnName = "version")private String version;public Android() {}public Android(String name, String version) {this.name = name;this.version = version;}public Android(Integer id,String name, String version) {this.id = id;this.name = name;this.version = version;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getVersion() {return version;}public void setVersion(String version) {this.version = version;}@Overridepublic int describeContents() {return 0;}@Overridepublic void writeToParcel(Parcel arg0, int arg1) {// 注:Parcel中的数据是按顺序写入和读取的,即先被写入的就会先被读取出来 arg0.writeInt(id);arg0.writeString(name);arg0.writeString(version);}//该静态域是必须要有的,而且名字必须是CREATOR,否则会出错 public static final Parcelable.Creator<Android> CREATOR = new Creator<Android>() {@Overridepublic Android[] newArray(int arg0) {return new Android[arg0];}@Overridepublic Android createFromParcel(Parcel arg0) {//从Parcel读取通过writeToParcel方法写入的Person的相关成员信息 return new Android(arg0.readInt(), arg0.readString(), arg0.readString());}};}
Android.aidl(aidl传输的Parcelable对象,必须顶一个相应的aidl文件)
parcelable Android;
Myservice.java
package com.example.mytest.zoomInImanage;import java.util.List;
import java.util.Map;import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;public class MyService extends Service{class MyBinder extends IService.Stub{@Overridepublic String input1(byte arg1, int arg3, char arg4, boolean arg5, float arg6, double arg7, long arg8)throws RemoteException {return arg1+"-"+arg3+"-"+arg4+"-"+arg5+"-"+arg6+"-"+arg7+"-"+arg8+"-over";}@Overridepublic String input2(String arg1, CharSequence arg2) throws RemoteException {return arg1+"-"+arg2+"-over";}@Overridepublic Android input3(List<String> arg1, Map arg2) throws RemoteException {if (arg2.containsKey(1)) {if (arg2.get(1) instanceof Android) {return (Android)arg2.get(1);}}return null;}@Overridepublic String input4(Android arg1) throws RemoteException {return arg1.getName();}}private MyBinder mybinder;@Overridepublic void onCreate() {super.onCreate();Log.d("TAG", "onCreate");mybinder = new MyBinder();}@Overridepublic IBinder onBind(Intent arg0) {Log.d("TAG", "onBind");return mybinder;}}
AndroidManifest.xml
<service android:name="com.example.mytest.zoomInImanage.MyService"android:exported="true"><intent-filter><!-- 指定调用AIDL服务的ID --> <action android:name="com.siy.servicer" /></intent-filter></service>
客户端:
Intent intent = new Intent("com.siy.servicer");
IService iservice;
bindService(intent, conn, Context.BIND_AUTO_CREATE);ServiceConnection conn = new ServiceConnection() {@Overridepublic void onServiceDisconnected(ComponentName arg0) {}@Overridepublic void onServiceConnected(ComponentName arg0, IBinder arg1) {Log.d("TAG", arg0+"");iservice = IService.Stub.asInterface(arg1);}};
使用AIDL:
1,首先呢得写一个服务的aidl文件,里面定义一些需要实现的方法。
2,关于方法的参数:
①支持除了shot类型以为的基本类型(byte,char,int,boolean,float,long,double)
②支持String,CharSequence类型
③支持实现Parcelable序列化的类型
④支持List,Map,但是里面传输的类型必须是以上4种
3,如果传输Parcelable序列化的对象,必须定义相应的aidl文件,并且不要忘记在服务的aidl文件中导包
4,实现的服务类,必须在onBind返回服务的aidl的实现类的桩对象(也有人说是句柄对象,随便你叫什么),就是那个
继承.Stub的对象。
5,在AndroidManifest.xml中注册。
6,在客户端绑定服务,用iservice = IService.Stub.asInterface(arg1)获取远程服务对象。注意哈,你的服务端的
.aidl文件都要拷一份给
客户端并且包名不能变。
(5)Messenger
例子不举了吧!
我还是看代码吧!我觉得代码最能让人理解。
MessageService:
public class MessageService extends Service{public static final int FROMCLIENT = 123;private Messenger service = new Messenger(new Handler(){@Overridepublic void handleMessage(Message msg) {Message serviceMessage = Message.obtain();switch (msg.what) {case FROMCLIENT:serviceMessage.what = FROMCLIENT;Android an = (Android)(msg.obj);
// serviceMessage.obj = an.getName();
// serviceMessage.arg1 = msg.arg1;Bundle bundle = msg.getData();Android andriod_1 = (Android) bundle.getSerializable("android_1");Android android_2 = (Android) bundle.getSerializable("android_2");Android android = new Android(andriod_1.getId() + android_2.getId(), andriod_1.getName() +android_2.getName(), andriod_1.getVersion() + android_2.getVersion());Bundle bundle_1 = new Bundle();bundle_1.putSerializable("android", android);serviceMessage.setData(bundle_1);try {msg.replyTo.send(serviceMessage);} catch (RemoteException e) {e.printStackTrace();}break;default:break;}super.handleMessage(msg);};});@Overridepublic IBinder onBind(Intent arg0) {return service.getBinder();}}
AndroidManifest.xml
<service android:name="com.example.mytest.photowall.MessageService"android:exported="true"><intent-filter ><action android:name="com.siy.messageservice"/></intent-filter>
</service>
client:
private static final int FROMCLIENT = 123;private Messenger mServiceMessage;private ServiceConnection messageConn = new ServiceConnection() {@Overridepublic void onServiceDisconnected(ComponentName name) {mServiceMessage = null;}@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {mServiceMessage = new Messenger(service);Log.d("TAG", "连上了");}};private Messenger client = new Messenger(new Handler(){@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case FROMCLIENT:Bundle bundle = msg.getData();Android android = (Android) bundle.getSerializable("android");Log.d("TAG", "messenger:"+android);break;default:break;}super.handleMessage(msg);}});private void test_7(){Message clientMessage = Message.obtain();clientMessage.what = FROMCLIENT;
// clientMessage.obj = new Android(1, "andorid-n", "7.0");
// clientMessage.arg1 = 1;Bundle bundle = new Bundle();bundle.putSerializable("android_1", new Android(1,"andriod-1", "1.0"));bundle.putSerializable("android_2", new Android(2,"android-2", "2.0"));clientMessage.setData(bundle);clientMessage.replyTo = client;try {mServiceMessage.send(clientMessage);} catch (RemoteException e) {e.printStackTrace();}}
使用messenger:
1,在服务器定一个Messenger 并以Handler为参数实例化它。
2,在AndroidManifest.xml注册它
3,在客户端也是用一个Messenger并以Handler参数实例化它进行通信的。
其实messenger的使用非常简单。但是他们通信所传递的对象如果是int型直接用户message.arg1 和message.arg2
就行了,如果是自定义对象不能用message.obj,而要使用message.setData(),而且我发现不能使用Parcelable对象
要使用Serializable,不知道是不是我的使用方式不对,反正我使用Parcelable老是报错的。
(6)Socket:
例子不举了吧!
我还是看代码吧!我觉得代码最能让人理解。
SocketServicer:
public class SocketServicer extends Service{private boolean mIsServideDestoryed = false;private String[] mDefinedMessages = new String[]{"你好啊,哈哈","请问你叫什么名字?","今天深圳的天气不太好诶","你知道吗,我是可以同时和很多人聊天额","给你讲一个笑话吧,一二三,笑话"};@Nullable@Overridepublic IBinder onBind(Intent intent) {return null;}@Overridepublic void onCreate() {new Thread(new TcpService()).start();System.out.println("servicer启动了");super.onCreate();}@Overridepublic void onDestroy() {mIsServideDestoryed=true;super.onDestroy();}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {return super.onStartCommand(intent, flags, startId);}private class TcpService implements Runnable{@Overridepublic void run() {ServerSocket serverSocket = null;//监听本地8688端口try {serverSocket = new ServerSocket(8688);}catch (IOException e){e.printStackTrace();return;}while(!mIsServideDestoryed){try {//接受客户端的请求final Socket client = serverSocket.accept();System.out.println("客户端已经连上了");System.out.println("client_1"+client);new Thread(){@Overridepublic void run() {try{System.out.println("client_2"+client);responseClinet(client);}catch (IOException e){e.printStackTrace();}}}.start();}catch (IOException e){}}}}private void responseClinet(Socket client) throws IOException{//用于接受客户端的消息BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));//用于向客户端发送消息PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream())),true);out.println("欢迎大家了来到聊天室");while(!mIsServideDestoryed){String str = in.readLine();System.out.println("msg form client:"+str);if(str == null){//客户端断开break;}int i = new Random().nextInt(mDefinedMessages.length);String msg = mDefinedMessages[i];out.println(msg);}if(in != null){in.close();}if(out!=null){out.close();}if(client!=null){client.close();}System.out.println("client活着4");}
}
SocketClientTest:
public class SocketClientTest extends Activity {private Socket mclientSocket;private BufferedReader mBufferedReader;private PrintWriter mPrintWriter;private static final int MESAGE_RECEIVE_NEW_MSG = 1;private static final int MESAGE_SOCKET_CONNECTED = 2;private EditText client_1;private TextView service_1;private TextView service_2;private TextView service_3;private Button sendbut;private Handler mhandler = new Handler() {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case MESAGE_SOCKET_CONNECTED:break;case MESAGE_RECEIVE_NEW_MSG:if (TextUtils.isEmpty(service_1.getText())){service_1.setText((String)msg.obj);return;}if (TextUtils.isEmpty(service_2.getText())){service_2.setText((String)msg.obj);return;}if (TextUtils.isEmpty(service_3.getText())){service_3.setText((String)msg.obj);}break;}}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.socket_service_layout);client_1 = (EditText) findViewById(R.id.clinet_1);service_1 = (TextView) findViewById(R.id.servicer_1);service_2 = (TextView) findViewById(R.id.servicer_2);service_3 = (TextView) findViewById(R.id.servicer_3);sendbut = (Button) findViewById(R.id.send);sendbut.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if(!TextUtils.isEmpty(client_1.getText()) && mPrintWriter !=null){mPrintWriter.println(client_1.getText());client_1.setText("");}}});new Thread() {@Overridepublic void run() {connectSocketServier();}}.start();}@Overrideprotected void onDestroy() {try{if(mclientSocket !=null){mclientSocket.shutdownInput();mclientSocket.close();;}}catch (IOException e){e.printStackTrace();}super.onDestroy();}private void connectSocketServier() {Socket client = null;while (client == null) {try {client = new Socket("localhost", 8688);mclientSocket = client;System.out.println("connect service success");} catch (IOException e) {SystemClock.sleep(1000);System.out.println("connect service failed,retry...");}}try {mBufferedReader = new BufferedReader(new InputStreamReader(mclientSocket.getInputStream()));mPrintWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(mclientSocket.getOutputStream())),true);mhandler.sendEmptyMessage(MESAGE_SOCKET_CONNECTED);while (!SocketClientTest.this.isFinishing()) {String msg = mBufferedReader.readLine();System.out.println("service:" + msg);if (msg != null) {mhandler.obtainMessage(MESAGE_RECEIVE_NEW_MSG, msg).sendToTarget();}}if (mBufferedReader != null) {mBufferedReader.close();}if (mPrintWriter != null) {mPrintWriter.close();}if (mclientSocket != null) {mclientSocket.close();}} catch (IOException e) {e.printStackTrace();}}}
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
以上就socket的跨进程通讯的全部代码,其实socket不仅可跨进程通讯,也可以进行网络的通讯,只要ip彼此可见。
名称 | 优点 | 缺点 | 使用场景 |
Bundle | 简单易用 | 名只能传输Bundle支持的类型的数据 | 四大组件间的进程间的通讯 |
AIDL | 功能强大 | 使用稍微有点复杂,需要处理好线程同步 | 一对多通信且有RPC(远程方法调用)需求 |
Messenger | 功能一般,支持一对多串行通信, 支持实时通信 |
不能很好的处理高并发的情形,不支持RPC,数据通过 Message进行传输,因此只能传输Bundle支持的数据 类型 |
低并发的一对多即时通讯,无RPC需求,或则无须 返回结果的RPC通讯 |
ContenProvider |
在数据源访问方面功能强大, 支持一对多并发数 据共享,可通过Call方法扩展其他操作 |
可以理解为受约束的AIDL,主要提供数据源的CRUD 操作 |
一对多的进程间的数据共享 |
Socket |
功能强大,可以通过网络传输字节流,支持一对 多的实时通讯 |
实现细节稍微有点繁琐,不支持RPC | 网络数据交换 |
Android 跨进程通讯的方式相关推荐
- android 跨进程点击方式总结
我们在日常的测试中,经常需要模拟用户点击等操作来实现模拟用户各种输入功能,在这里归纳总结一下几种点击方式,以及它们各自的优缺点,目前实现跨进程点击方式大致会有一下四种方式 一 adb shell 命令 ...
- Android进阶——Android跨进程通讯机制之Binder、IBinder、Parcel、AIDL
前言 Binder机制是Android系统提供的跨进程通讯机制,这篇文章开始会从Linux相关的基础概念知识开始介绍,从基础概念知识中引出Binder机制,归纳Binder机制与Linux系统的跨进程 ...
- Android跨进程通讯机制之Binder、IBinder、Parcel、AIDL
https://blog.csdn.net/qq_30379689/article/details/79451596 前言 Binder机制是Android系统提供的跨进程通讯机制,这篇文章开始会从L ...
- android中跨进程通讯的4种方式
由于android系统中应用程序之间不能共享内存.因此,在不同应用程序之间交互数据(跨进程通讯)就稍微麻烦一些.在android SDK中提供了4种用于跨进程通讯的方式.这4种方式正好对应于andro ...
- android listview 滑动黑屏,Android 跨进程启动Activity黑屏(白屏)的三种解决方案
当Android跨进程启动Activity时,过程界面很黑屏(白屏)短暂时间(几百毫秒?).当然从桌面Lunacher启动一个App时也会出现相同情况,那是因为App冷启动也属于跨进程启动Activi ...
- linux 跨进程读取内存,Android之Linux跨进程通信的方式
As we all know,Android是基于Linux内核开发的,而市面上几乎所有的App都离开跨进程通信.可能你会说Android是通过Binder完成进程之间的通信的.但是Binder是怎么 ...
- Android ContentProvider实现两个程序间数据共享demo,跨进程通讯
1.客户端代码: 先实现服务端 SQL创建: public class DBHelper extends SQLiteOpenHelper {// 数据库名private static final S ...
- Android AILD跨进程通讯 解决bindService无法启动
场景:APP-A 服务端,APP-B 客户端.B启动service,通过IBinder,拿到服务端User列表,并向User表中添加人员信息.从而实现两个APP跨进程通讯 一,服务端APP 步骤:1, ...
- IPCInvoker,Android跨进程调用如此简单
一个APP为什么需要多条进程? 如果一条进程能够拥有足够多的资源,且不会被系统kill掉的话,让程序运行在一条进程上是最好的选择.但是系统资源是按进程来分配的,每条进程资源分配是有个上限的,而且当我们 ...
最新文章
- curl 安装_记一次因curl版本过低导致zabbix server不停重启问题及解决方法
- 如何确定最初克隆本地Git存储库的URL?
- c语言330转化成字符,c/字符串,字符转数字,数字转字符(转)
- nginx配置文件语法高亮的Sublime Text扩展
- Opencv显示创建Mat对象的七种方式
- DataUml Design 介绍8-DataUML 1.2版本正式发布
- mongodb在aggregate lookup 进行分页查询,获得记录总数
- 插入迭代器、流迭代器、反向迭代器、移动迭代器
- 遍历删除_面试难题:List 如何一边遍历,一边删除?
- python获取类的类属性_在python中获取类和实例的属性
- Spring学习手册 1:Spring MVC 返回JSON数据
- 曲则全,枉则直;洼则盈,敝则新;少则得,多则惑。
- linux 测试post接口
- wsdl文件 服务器地址,webservice 的wsdl文件详解
- C语言程序设计题目汇总(不断更新中)
- JavaScript 身份证验证
- word没自动保存?===如何通过asd文件恢复
- 线程池的设计与原理解析(二)之---execute()方法
- font:12px/1.5 tahoma, arial, \5b8b\4f53, sans-serif详解
- SVG不能铺满的问题