当前位置:   article > 正文

Android 跨进程作用,Android中跨进程通讯的4种方式

安卓跨进程通信方式

均属于笔记,仅供个人参考,有问题欢迎指正,整理模式

这4种方式正好对应于android系统中4种应用程序组件:Activity、Content Provider、Broadcast和Service。其中Activity可以跨进程调用其他应用程序的Activity;Content Provider可以跨进程访问其他应用程序中的数据(以Cursor对象形式返回),当然,也可以对其他应用程序的数据进行增、删、改操作;Broadcast可以向android系统中所有应用程序发送广播,而需要跨进程通讯的应用程序可以监听这些广播;Service和Content Provider类似,也可以访问其他应用程序中的数据,但不同的是,Content Provider返回的是Cursor对象,而Service返回的是Java对象,这种可以跨进程通讯的服务叫AIDL服务。

1,访问其他应用程序的Activity

1.1,进程内调用

Activity既可以在进程内(同一个应用程序)访问,也可以跨进程访问。如果想在同一个应用程序中访问Activity,需要指定Context对象和Activity的Class对象,代码如下:

Intent intent = new  Intent(this , Test.class );

startActivity(intent);

1.2,进程间调用

在android系统中有很多应用程序提供了可以跨进程访问的Activity,例如,下面的代码可以直接调用拨打电话的Activity。

Intent callIntent = new  Intent(Intent.ACTION_CALL,Uri.parse("tel://13888888888" );

startActivity(callIntent);

1.3,如何将应用程序的Activity共享出来

1). 在AndroidManifest.xml文件中指定Action。指定Action要使用标签,并在该标签的android:name属性中指定Action

2). 在AndroidManifest.xml文件中指定访问协议。在指定Uri(Intent类的第2个参数)时需要访问协议。访问协议需要使用标签的android:scheme属性来指定。如果该属性的值是“mdm”,那么Uri就应该是“mdm://Uri的主体部分”,也就是说,访问协议是Uri的开头部分。

3). 通过getIntent().getData().getHost()方法获得协议后的Uri的主体部分。这个Host只是个称谓,并不一定是主机名。读者可以将其看成是任意的字符串。

4). 从Bundle对象中获得其他应用程序传递过来的数据。

5). 这一步当然是获得数据后做进一步的处理了。至于如何处理这些数据,就得根据具体的需求决定了。

1.4,注意事项

1)在配置AndroidManifest.xml时要注意,不能在同一个中配置多个动作,否则会覆盖MAIN动作以使该程序无法正常启动(虽然其他应用程序调用Main是正常的).

标签指定了Url的协议,则在调用Main时需要使用如下的URL:

mdm://任意字符串

一般标签的android:name属性值可以设成android.intent.category.DEFAULT,这个必须要设置,不然无法访问到。

2)跨进程访问Activity(访问其他应用程序中的Activity)主要是通过一个Action来完成的,如果要传递数据,还需要指定一个Uri。当然,传递数据也可以通过Intent来完成。传递数据的过程可以是双向的。如果要想从调用的Activity中返回数据,就需要使用startActivityForResult方法来启动Activity了。

2, Content Provider

2.1概述

Android应用程序可以使用文件或SqlLite数据库来存储数据。Content

Provider提供了一种在多个应用程序之间数据共享的方式(跨进程共享数据)。应用程序可以利用Content Provider完成下面的工作.

Android系统本身提供了很多Content

Provider,例如,音频、视频、联系人信息等等。我们可以通过这些Content Provider获得相关信息的列表。这些列表数据将以Cursor对象返回。因此,从Content Provider返回的数据是二维表的形式。

对于访问Content Provider的程序,需要使用ContentResolver对象。该对象需要使用getContentResolver方法获得,代码如下:

ContentResolver cr = getContentResolver();

与Activity一样,Content Provider也需要与一个URI对应。每一个Content Provider可以控制多个数据集,在这种情况下,每一个数据集会对应一个单独的URI。所有的URI必须以“content://”开头。

2.2设置步骤

具体可以参考Android四大组件之Content Provider详解;

2.3注意事项

1,内容提供者中的oncreate方法

@Override

publicboolean onCreate() {

dbHelper= new DBHelper(getContext(), "Provider", null, 1);

returntrue;

}

如果数据库版本为2时,则数据库中的onupdate方法就要重写,并且查询是会更新数据库版本,使数据丢失

2,命名问题

android:name="com.hjt.provide.contentprovider.provider.DatabaseProvider"

android:authorities="com.hjt.provide.provider"

android:exported="true">

在配置文件中注册provider时的android:authorities设置为包明+“.provider”,即和代码中的路径中的权限部分一样;

public static final String AUTHORITY ="com.hjt.provide.provider";

上面两部分是提供者命名时的规则

在调用方使用

Uri uri1 = Uri.parse("content://com.hjt.provide.provider/Person");

路径为权限+数据表名,权限就是为了区分那个应用,规定写法就是包名+“.provider”.

不管是提供者还是调用者,其中的包名是提供者具体应用的包名,和内容提供者类所在的包名没有关系,毕竟数据库和数据表是对于应用来说的。

3,在配置文件中声明provider时

android:name="com.hjt.provide.contentprovider.provider.DatabaseProvider"

android:authorities="com.hjt.provide.provider"

android:exported="true">

要加上android:exported="true",否则会报java.lang.SecurityException:

Permission Denial: opening provider异常

4, android:exported的作用

在Activity中该属性用来标示:当前Activity是否可以被另一个Application的组件启动:true允许被启动;false不允许被启动。

android:exported 是Android中的四大组件Activity,Service,Provider,Receiver 四大组件中都会有的一个属性。

总体来说它的主要作用是:是否支持其它应用调用当前组件。

3,Broadcast

广播是一种被动跨进程通讯的方式。当某个程序向系统发送广播时,其他的应用程序只能被动地接收广播数据。这就象电台进行广播一样,听众只能被动地收听,而不能主动与电台进行沟通。

在应用程序中发送广播比较简单。只需要调用sendBroadcast方法即可。该方法需要一个Intent对象。通过Intent对象可以发送需要广播的数据。

3.1发送广播

先建一个android工程:sendbroadcast。在XML布局文件中放两个组件:EditText和Button,当单击按钮后,会弹出显示 EditText组件中文本的对话框,关闭对话框后,会使用sendBroadcast方法发送消息,并将EditText组件的文本通过Intent对象发送出去。完整的代码如下:

package net.blogjava.mobile.sendbroadcast;

... ...

public class Main extends Activityimplements OnClickListener{

private EditTexteditText;

@Override

public void onClick(View view){

new AlertDialog.Builder(this).setMessage(editText.getText().toString())

.setPositiveButton("确定",null).show();

//  通过Intent类的构造方法指定广播的ID

Intent intent = newIntent("net.blogjava.mobile.MYBROADCAST");

//  将要广播的数据添加到Intent对象中

intent.putExtra("text", editText.getText().toString());

//  发送广播

sendBroadcast(intent);

}

... ...

}

3.2接受广播

发送广播并不需要在AndroidManifest.xml文件中注册,但接收广播必须在AndroidManifest.xml文件中注册 receiver(静态注册)。下面来编写一个接收广播的应用程序。首先建立一个android工程:receiver。然后编写一个MyReceiver类,该类是 BroadcastReceiver的子类,代码如下:

package net.blogjava.mobile.receiver;

... ...

public class MyReceiver extendsBroadcastReceiver

{

//  当sendbroadcast发送广播时,系统会调用onReceive方法来接收广播

@Override

public void onReceive(Context context, Intent intent)

{

//  判断是否为sendbroadcast发送的广播

if("net.blogjava.mobile.MYBROADCAST".equals(intent.getAction()))

{

Bundle bundle = intent.getExtras();

if (bundle != null)

{

String text =bundle.getString("text");

Toast.makeText(context, "成功接收广播:"+ text, Toast.LENGTH_LONG).show();

}

}

}

}

当应用程序发送广播时,系统会调用onReceive方法来接收广播,并通过intent.getAction()方法返回广播的ID,也就是在发送广播时Intent构造方法指定的字符串。然后就可以从Bundle对象中获得相应的数据了。

最后还需要在AndroidManifest.xml文件中注册receiver,代码如下:

在注册MyReceiver类时需要使用标签,android:name属性指定MyReceiver类,标签的android:name指定了广播的ID。

首先运行receiver程序,然后就可以关闭receiver程序了。接收广播并不依赖于程序的状态。就算程序关闭了,仍然可以接收广播。然后再启动 sendbroadcast程序。并在文本框中输入“android”,然后单击按钮,会弹出一个显示文本框内容的对话框,如图9所示。当关闭对话框后,会显示一个Toast信息提示框,这个信息框是由receiver程序弹出的。

3.3注意事项

1)Calling

startActivity() from outside of an Activity context requires the

FLAG_ACTIVITY_NEW_TASK fla异常

从一个非Activity的Context中要通过intent调出另一个Activity的话,需要使用FLAG_ACTIVITY_NEW_TASK

否则的话,会有force close:

03-01 18:49:37.888 E/AndroidRuntime( 2706):FATAL EXCEPTION: main

03-01 18:49:37.888 E/AndroidRuntime( 2706):android.util.AndroidRuntimeException: Calling startActivity() from outside ofan Activity  context requires theFLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?

FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:

如果调出的Activtivity只是一个功能片段,并没有实际的意义,也没有必要出现在长按Home键调出最近使用过的程序类表中,那么使用FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS

Intent intent = new Intent(this,WaitingFallBackDialog.class);

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);

//intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

startActivity(intent);

4,Service

4.1概述

服务(Service)是android系统中非常重要的组件。Service可以脱离应用程序运行。也就是说,应用程序只起到一个启动Service的作用。一但Service被启动,就算应用程序关闭,Service仍然会在后台运行。

android系统中的Service主要有两个作用:后台运行和跨进程通讯。后台运行就不用说了,当Service启动后,就可以在Service对象中运行相应的业务代码,而这一切用户并不会察觉。而跨进程通讯是这一节的主题。如果想让应用程序可以跨进程通讯,就要使用我们这节讲的AIDL服务,AIDL的全称是Android Interface Definition Language,也就是说,AIDL实际上是一种接口定义语言。通过这种语言定义接口后,Eclipse插件(ODT)会自动生成相应的Java代码接口代码。下面来看一下编写一个AIDL服务的基本步骤。

1.  在Eclipse工程的package目录中建立一个扩展名为aidl的文件。package目录就是Java类所在的目录。该文件的语法类似于Java代码。aidl文件中定义的是AIDL服务的接口。这个接口需要在调用AIDL服务的程序中访问。

2.  如果aidl文件的内容是正确的,Eclipse插件会自动生成一个Java接口文件(*.java)。

3.  建立一个服务类(Service的子类)。

4.  实现由aidl文件生成的Java接口。

5.  在AndroidManifest.xml文件中配置AIDL服务,尤其要注意的是,标签的android:name属性值就是客户端要引用该服务的ID,也就是Intent类构造方法的参数值。

4.2 AIDL服务的基本步骤

1.  在Eclipse工程的package目录中建立一个扩展名为aidl的文件。package目录就是Java类所在的目录。该文件的语法类似于Java代码。aidl文件中定义的是AIDL服务的接口。这个接口需要在调用AIDL服务的程序中访问。

2.  如果aidl文件的内容是正确的,Eclipse插件会自动生成一个Java接口文件(*.java)。

3.  建立一个服务类(Service的子类)。

4.  实现由aidl文件生成的Java接口。

5.  在AndroidManifest.xml文件中配置AIDL服务,尤其要注意的是,标签的android:name属性值就是客户端要引用该服务的ID,也就是Intent类构造方法的参数值。

4.3设置自定义权限

Exported service does not require

permission问题。

但是这次遇到的是“外部的service不需要权限”,其意思是:外部的其他service根本不需要添加权限就能够轻易地访问我们编写的这个aidl,或者说这个service。这是出于安全性的考虑而给我们的警告。而不是告诉我们缺少相应的权限。自己傻傻的还想require这个单词是不是还有其他意思,会不会有“需要”的意思,查有道,没有。翻牛津。还是没有。最后甚至想是不是编辑文档的人写错了,把acquire错写成了require?最后才发现只是理解错了,习惯性思维犯的错。

就是说默认值取决于该service是否包含intent过滤器filter。如果没有,那只能通过指定其准确的类名访问。这意味着该service打算只在该应用内部使用(因为其他应用可能根本不知道这个类的名字)。在这种情况下,默认值是“false”,另一方面,当存在至少一个filter时,就表明该service打算供外部来使用,因此默认值是“true”。写到这里相信大家知道问什么了吧。原来api里面写的清清楚楚,看来api文档才是最好的资料这句话一点没错。是真正的宗。

其实还有一种解决的办法。那就是我们在这里自己定义一个权限。既然外部的其他service不需权限就能访问我们的service,那么我们自己定义权限,然后在需要调用该service的应用的配置文件里面声明调用该service的所需要的权限不就可以了吗?代码更改为:

android:permission="com.exmaple.myaidldemo.myaidlservice">

然后在我们需要调用该service的其他应用的配置文件中加入下面这行代码:

4.4注意事项

1. AIDL服务中的onBind方法必须返回AIDL接口对象(MyServiceImpl对象)。该对象也是onServiceConnected事件方法的第2个参数值。

2. bindService方法的第1个参数是Intent对象,该对象构造方法的参数需要指定AIDL服务的ID,也就是在 AndroidManifest.xml文件中标签的子标签的android:name属性的值。

3,引用者中aidl文件和提供者中的aidl文件一样,直接复制提供者中的aidl即可,需要注意的是这里的复制是全路径复制,即报名等都要一致,这样才能访问到该aidl(Service)。

参考:http://www.jianshu.com/p/61f681145cd8  主要是Activity

http://blog.csdn.net/zhuangyalei/article/details/50515039主要是Service的几个示例

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/247565
推荐阅读
相关标签
  

闽ICP备14008679号