首页 / ANDROID / Android:进程间通信交互
Android:进程间通信交互
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了Android:进程间通信交互,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含8508字,纯文字阅读大概需要13分钟。
内容图文
Intent 的 ComponentName
Intent作为我们最常用的数据传输渠道,特别是通过Intent打开一个Activity,想必每个人都不会陌生。通常我们用到的都是通过Intent打开同一个进程(App)内部的Activity,如果想实现跨进程通讯,就需要把Intent对象发送到另一个(App)中,并解析出来,这时就需要ComponentName来为我们做这件事情了。既然可以发送数据到另外的进程,也就可以实现不同进程间的交互了。
注意事项:如果A要打开另一个进程中的B中的Activity,那么要在B项目中的AndroidManifest文件中,把要打开的Activity的exported设置为true ,否则将会报错。
android:exported="true"
我们将要用到ComponentName的构造函数如下:
public
ComponentName(String pkg, String cls) {
if (pkg == null) thrownew NullPointerException("package name is null");
if (cls == null) thrownew NullPointerException("class name is null");
mPackage = pkg;
mClass = cls;
}
它需要两个参数,第一个参数是一个存在的pakage(包),第二个是这个包中你要打开的类的名字(注意是带完整包名的),下面是使用例子:
进程AndroidAIDL(com.example.androidaidl)中的MainActivity
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//接收传过来的Intentif (getIntent() != null){
System.out.println("----------"+getIntent().getIntExtra("id", 0)+"----------");
}
}
另一个进程AndroidTest,在这里的MainActivity中我们写如下代码:
/**指定包名和带包名的Activity的名字*/
ComponentName componentName = new ComponentName("com.example.androidaidl", "com.example.androidaidl.MainActivity");
Intent intent = new Intent();
intent.putExtra("id", 1001);
intent.setComponent(componentName);
startActivity(intent);
运行上面代码后,会看到LogCat中打印出 1001,表示接收AndroidTest进程传来的Intent正常。
注意事项:上面代码中我们传递的是基本的数据类型,对于基本数据类型,比如Int,String等接收时可以像上面那样直接读取,但是如果发送的是复杂的对象,该对象需要实现Serializable或者Parcelable接口。
比如我们定义一个 SendData 对象作为传递对象,它实现 Parcelable 接口:
public
class
SendData
implements
Parcelable{
int id;
String content;
publicintgetId() {
return id;
}
publicvoidsetId(int id) {
this.id = id;
}
public String getContent() {
return content;
}
publicvoidsetContent(String content) {
this.content = content;
}
publicstaticfinal Parcelable.Creator<SendData> CREATOR = new Parcelable.Creator<SendData>() {
@Overridepublic SendData createFromParcel(Parcel source) {
// TODO Auto-generated method stub
SendData data = new SendData();
data.setId(source.readInt());
data.setContent(source.readString());
return data;
}
@Overridepublic SendData[] newArray(int size) {
// TODO Auto-generated method stubreturnnew SendData[size];
}
};
@OverridepublicintdescribeContents() {
// TODO Auto-generated method stubreturn0;
}
@OverridepublicvoidwriteToParcel(Parcel dest, int flags) {
// TODO Auto-generated method stub
dest.writeInt(id);
dest.writeString(content);
}
}
发送代码:
Intent intent =new Intent();
SendData data=new SendData();
data.setId(1001);
data.setContent("hellow world");
//发送序列化对象
intent.putExtra("data", data);
startActivity(intent);
接收代码
protected
void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (getIntent() != null){
if (getIntent().getParcelableExtra("data") == null)
return;
//读取序列化对象,并转化为SendData类型
SendData data = (SendData)getIntent().getParcelableExtra("data");
System.out.println("----------"+data.getContent()+"-----------");
}
}
如果在同一个进程的话,上面的方法没有任何问题,如果在不同进程中,就要注意,SendData 这个bean所在的包名,在各个项目中必须一样,否则接收方,无法解析
广播-BroadcastReceiver
Android的广播是系统级的,只要传递的Action一样(下面的例子中,都使用 Action_Test),就可以接收到其他进程广播的消息,广播中可以通过Intent传递数据。
发送方代码:
Intent intent =new Intent("Action_Test");
SendData data=new SendData();
data.setId(1001);
data.setContent("hellow world");
intent.putExtra("data", data);
intent.putExtra("id", 1001);
getActivity().sendBroadcast(intent);
接收方代码(动态注册广播):
innerReceiver = new InnerReceiver();
IntentFilter filter = new IntentFilter("Action_Test");
registerReceiver(innerReceiver, filter);
classInnerReceiverextendsBroadcastReceiver{
@Override
publicvoid onReceive(Context context, Intent intent) {
// TODO Auto-generated method stubif (intent.getAction().equals("Action_Test")){
SendData data = (SendData)intent.getParcelableExtra("data");
System.out.println("-----------"+data.getContent()+"------------");
}
}
}
因为是通过Intent传递数据,所以对复杂对象的要求和第一种方式一样,要求bean所在的包名一样
ContentProvider
ContentProvider通常用来操作数据集,Android本身就提供了不少的ContentProvider访问,比如联系人、相册等。
访问ContentProvider,需要通过Uri,需要以“content://”开头。下面看看使用方法:
在进程AndroidAIDL(com.example.androidaidl),我们定义一个继承自ContentProvider的类,需要重载它的方法,这里我们以query为例
public
class
ProviderTest
extends
ContentProvider {
private
static
final UriMatcher MATCHER = new UriMatcher(
UriMatcher.NO_MATCH);
static{
//添加访问字符串,对应配置文件中的android:authorities属性
MATCHER.addURI("com.mh.getdata", "stock", 10001);
}
@OverridepublicbooleanonCreate() {
// TODO Auto-generated method stubreturnfalse;
}
@Override/**
* @param uri URI 路径
* @param projection 要保护的列集合,如果传 null,所有列都会被包含进去.
* @param selection 用来过滤数据集的规则,null表示不筛选.
* @param selectionArgs 类似字符串的格式化,selection参数中可以包含 ?s, 这个将被selectionArgs的内容替换
* @param sortOrder 排序.
*/public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// TODO Auto-generated method stub
System.out.println("--------------------query----------------------");
returnnull;
}
@Overridepublic String getType(Uri uri) {
// TODO Auto-generated method stubreturnnull;
}
@Overridepublic Uri insert(Uri uri, ContentValues values) {
// TODO Auto-generated method stubreturnnull;
}
@Overridepublicintdelete(Uri uri, String selection, String[] selectionArgs) {
// TODO Auto-generated method stubreturn0;
}
@Overridepublicintupdate(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
// TODO Auto-generated method stubreturn0;
}
}
定义了这个类后,需要在AndroidManifest对它进行声明,android:exported=true,记得要写,否则会提示权限错误
<providerandroid:name="ProviderTest"android:authorities="com.mh.getdata"android:exported="true">
</provider>
上面的配置有两个属性
android:name就是类名成
android:authorities这个就是前面提到的Uri,外界需要通过这个来访问Provider
下面看看调用者,在另一个进程中,我们有如下代码:
ContentResolver resolver = getActivity().getContentResolver();
/**com.mh.getdata/stock这个要和Provider所在进程中添加的Uri一致*/
Uri uri = Uri.parse("content://com.mh.getdata/stock");
Cursor cursor = resolver.query(uri, null, null, null, null);
调用上面代码后,LogCat中打印出 “query”字样,表名Provider调用成功,我们通过resolver就可以和AndroidAIDL进程中的Provider对象进行交互了。
AIDL
一种接口定义语言,Android会自动生成通讯代码,通过AIDL我们可以在一个进程中,调用另一个进程中的方法,据说一些大公司的杀不死的Service就是通过这个AIDL来保活的,可以好好研究下。个人认为AIDL更适合做插件化系统,或者有多个app共同组成一个系统,比如WebView因为内存泄露比较严重,所以一些公司就单独把WebView封装成一个app,单独调用,这时,我们通过AIDL技术,就可以调用到这个app中的接口,来操作WebView的行为。
下面开始介绍使用方法:
在两个项目中新建普通文件(Eclipse中是:new ->General->File),记得同时写上后缀名(aidl),两个项目中这个文件所在的包名要保持一致,内容也要一样,如图
编译之后, 会在gen目录下,自动产生同名的,后缀为 java 的文件。里面有我们要用到的 Stub类。
public
static
abstract
class
Stub
extends
android.os.Binderimplementscom.example.aidl.AidlFunctions
在接口文件AIDLFunctions.aidl中,我们定义一个方法 show
interface
AidlFunctions{
void show();
}
服务端:
AIDL的使用,需要一个Service配合,所以我们在服务端还要声明一个Service
public
class
AIDLService
extends
Service {
//stub就是系统自动产生的
AidlFunctions.Stub binder;
@OverridepublicvoidonCreate() {
// TODO Auto-generated method stubsuper.onCreate();
}
@Overridepublic IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
binder = new AidlFunctions.Stub() {
@Override//这里是我们在接口中声明的方法的实现publicvoidshow() throws RemoteException {
// TODO Auto-generated method stub
System.out.println("--------------------收到----------------------");
}
};
return binder;
}
}
在AndroidManifest声明Service
<serviceandroid:name="com.example.androidaidl.AIDLService">
<intent-filter>
<actionandroid:name="com.example.androidaidl.AIDLService" />
</intent-filter>
</service>
客户端:
//绑定服务,要用到ServiceConnection
private ServiceConnection serviceConnection;
//自定义的接口,和服务端一样private AidlFunctions aidlFunctions;
serviceConnection = new ServiceConnection() {
@Override
publicvoidonServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
System.out.println("--------------------ServiceDisconnected----------------------");
}
@Override
publicvoidonServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
System.out.println("--------------------ServiceConnected----------------------");
aidlFunctions = AidlFunctions.Stub.asInterface(service);
}
};
Intent intent = new Intent("com.example.androidaidl.AIDLService");
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
//调用show方法try {
aidlFunctions.show();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
原文:http://blog.csdn.net/bdmh/article/details/50206737
内容总结
以上是互联网集市为您收集整理的Android:进程间通信交互全部内容,希望文章能够帮你解决Android:进程间通信交互所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。