1)直接调用其他进程的Activity。例如调用拨打电话,发短信的服务。
Intent callIntent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:12345678" );
怎么应用到自己的项目中来,如下:
(A)在项目A中新建一个TestActivity来作为实验,重点是配置该Activity的Manifest文件,配置如下:
<activity
android:name=".TestActivity" //该activity的class name
android:exported="true">
<intent-filter>
<action android:name="net.blogjava.mobile.MYACTION"/>
<data android:scheme="info"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
a. android:exported="true" :设置为"True"则表示将该Activity暴露给外部;但在本demo中发现,这个属性可以不用设置,demo也是生效。这是因为:设置了intentFilter之后,exported就默认被设置为true了,除非再强制设为false。
b. <action android:name="net.blogjava.mobile.MYACTION"/> :这里是设置Intent对应的名字,在调用的时候,需要该名字。当然这里也可以为空。(若为空串,调用的时候需要指定调用activity的包名和类名,后文详述)
c. <data android:scheme="info"/> :data元素用于把数据规范添加到一个Intent过滤器中,如果这里定义了info,那在intent中就需要添加uri为“info://”的字样;如果name为空,这里也就不需要设置;
关于data的详细介绍,参考
d. <category android:name="android.intent.category.DEFAULT" /> : 意思是说,每一个通过 startActivity() 方法发出的隐式 Intent 都至少有一个 category,就是 "android.intent.category.DEFAULT",所以只要是想接收一个隐式 Intent 的 Activity 都应该包括 "android.intent.category.DEFAULT" category,不然将导致 Intent 匹配失败。
从上面的论述还可以获得以下信息: 1、一个 Intent 可以有多个 category,但至少会有一个,也是默认的一个 category。 2、只有 Intent 的所有 category 都匹配上,Activity 才会接收这个 Intent。
这四个部分是注册时候的主要动作,但a可以无视,正如前面所说; d是不可缺少的,若少了,则无法调用成功,会提示找不到Activity的错误。
(B)在B项目中启动A项目的TestActivity界面,如下:
Intent i = new Intent("net.blogjava.mobile.MYACTION", Uri.parse("info://111"));
this.startActivity(i);
注意:另外一种方式也可以达到不同应用之间调用Activity,如下:
Mainifest文件配置:
<activity
android:name=".TestActivity"
android:exported="true"
>
B项目调用A项目的界面:
Intent intent = new Intent();
ComponentName cn=new ComponentName("com.mytest.main",
"com.mytest.main.TestActivity");
intent.setComponent(cn);
startActivity(intent);
只需要指定你需要调用的Activity是在哪个包中,以及类名是什么,即格式为:(包名,包名+类名)
而Mainifest配置中,只需要指定该Activity的名字,并将它暴露给外部就行,可以不用设置Intent-filter。同样,如果你没有设置exported属性,会提示错误权限不允许访问SubActivity。也可以用个设置一个空的intent-filter来打开该属性,这也是网上为什么有的例子添加了intent-filter,但只有一个空串action的缘故。
如何传值,在项目B调用项目A的Activity的时候,如下调用:
Intent i = new Intent("net.blogjava.mobile.MYACTION", Uri.parse("info://111"));
i.putExtra("value" , "调用成功" );
MainActivity.this.startActivity(i);
在项目A的TestActivity的onCreate方法里面写如下:
if (getIntent().getData() != null)
{
// 获得Host,也就是info://后面的内容 注意这里!!!!
String host = getIntent().getData().getHost();
Bundle bundle = getIntent().getExtras();
// 其他的应用程序会传递过来一个value值,在该应用程序中需要获得这个值
String value = bundle.getString("value");
// 将Host和Value组合在一下显示在EditText组件中
Toast.makeText(IntentForActivity.this, "值为 : "+value, Toast.LENGTH_SHORT).show();
}
2)利用发广播的形式,其他应用能收到广播,并进行相对应的处理。
3)利用内容提供者,可以访问系统的一些数据,例如联系人
4)利用AIDL的方式来让不同进程的应用进行共享。
AIDL就叫AIDL语言,怎么应用如下:
(A)首先在A应用里面新建一个XXX.aidl文件(例如IPerson.aidl)。内容可以如下:
package com.main.testforaidl;
interface IPerson {
void registerTestCall(String ma);
String invokCallBack();
double add(double a,double b);
}
此时eclipse中会在你的A项目中的gen文件夹下自动生成一个IPerson.java的类文件。
(B)然后在A应用里面新建一个Person.java类,它继承自IPreson。
public class Person extends IPerson.Stub{
private String name;
@Override
public void registerTestCall(String ma) throws RemoteException {
this.name = ma;
}
@Override
public String invokCallBack() throws RemoteException {
return name;
}
@Override
public double add(double a, double b) throws RemoteException {
return a+b;
}
}
(C)这里需要应用到Android中的Service服务,我们在A项目中新建一个服务ServiceC,如下:
把Person类以IBinder的方式返回出去。
public class ServiceC extends Service{
private Stub iPerson = new Person();
@Override
public IBinder onBind(Intent intent) {
return iPerson;
}
}
记得在Manifest文件中给ServiceC注册一下。
<service android:name="com.main.testforaidl.main.ServiceC" >
<intent-filter >
<action android:name="forServiceAidl" > </action>
</intent-filter>
</service>
(D)最后在A项目中新建MainActivity一个Activity类,如下:
public class MainActivity extends Activity {
private Button btn;
private Button btn2;
private IPerson person;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button)findViewById(R.id.btn);
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
//该应用中不需要在manifest中配置RemoteService
bindService(new Intent("forServiceAidl"), conn, Service.BIND_AUTO_CREATE);
}
});
btn2 = (Button)findViewById(R.id.btn2);
btn2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
try {
Toast.makeText(MainActivity.this, "远程进程调用成功!ADD 值为 : "+person.add(5, 2), Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName arg0) {
}
//因为有可能有多个应用同时进行RPC操作,所以同步该方法
@Override
public synchronized void onServiceConnected(ComponentName arg0, IBinder binder) {
//获得IPerson接口
person = IPerson.Stub.asInterface(binder);
if(person != null){
try {
//RPC方法调用
String name = person.invokCallBack();
Toast.makeText(MainActivity.this, "远程进程调用成功!值为 : "+name, Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
Toast.makeText(MainActivity.this, "远程进程调用失败! ", Toast.LENGTH_SHORT).show();
}
}
}
};
}
服务端的代码就差不多了,接下来就建立客户端的代码;
(A)首先在B项目中,建立一个和A项目中相同名称的包:package com.main.testforaidl,再将A项目中的IPerson.aidl文件拷贝到B项目中来,B项目中也会自动生成一个gen文件夹下的IPerson类。
(B)然后在B项目中,新建一个Activity,例如:MainActivity,如下:
public class MainActivity extends Activity {
private Button btn;
private Button btn2;
private IPerson person;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button)findViewById(R.id.btn);
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
//该应用中不需要在manifest中配置RemoteService
bindService(new Intent("forServiceAidl"), conn, Service.BIND_AUTO_CREATE);
}
});
btn2 = (Button)findViewById(R.id.btn2);
btn2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
try {
Toast.makeText(MainActivity.this, "远程进程调用成功!ADD 值为 : "+person.add(5, 2), Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName arg0) {
}
//因为有可能有多个应用同时进行RPC操作,所以同步该方法
@Override
public synchronized void onServiceConnected(ComponentName arg0, IBinder binder) {
//获得IPerson接口
person = IPerson.Stub.asInterface(binder);
if(person != null){
try {
//RPC方法调用
String name = person.invokCallBack();
Toast.makeText(MainActivity.this, "远程进程调用成功!值为 : "+name, Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
Toast.makeText(MainActivity.this, "远程进程调用失败! ", Toast.LENGTH_SHORT).show();
}
}
}
};
}
简单的说就是在服务端的app应用中,开启一个服务,让另一个应用去调用,并在返回的IBinder类中调用服务端应用所写的方法或者常量。