android跨应⽤启动activity
Android跨应⽤启动
前⾔:
相信⼤家,很多时候都是在⾃⼰的应⽤中,启动⾃⼰写的Activity,Service、BroadcastReceiver、contentProvider 。换句话说,这些都只是 * 单个应⽤中 组件间 * 的启动。⽽我们下⾯要谈论的是 两个应⽤间 组件 的启动。即——使⽤ 隐式Intent⽅式 启动应⽤B的某个组件。
⼀、在开始之前,先来梳理⼀下跨应⽤启动的2种⽅式:
第⼀种:在Activity中,启动另⼀个app的组件。
第⼆种:在Service中,启动另⼀个app的组件。
从所周知,Android中有四⼤组件,那么为什么⼩编,只介绍Activity和Service中启动另⼀个应⽤的四⼤组件?
其实,BroadcastReceiver组件也是可以启动 4⼤组件的。这是因为onReceive()⽅法中会要求传⼊context实例,有了context实例,就能使⽤context的⽅法,启动其他组件。
⾄于contentProvider,我想⼤家还没见过,这娃⾃动去⼲过事情吧,都是被动的调⽤。
所以在写代码的时候,我们经常会在Activity或者Service中去启动⼀个组件,BroadcastReceiver很少,⽽contentProvider更是没见过。
另外需要跟⼤家说⼀下,Context类是⼀个抽象类,传⼊的context实例是由其⼦类来实现的,这种——⽤⽗类声明变量,由⼦类来实现的思维⽅式,在Java中是很常见的。特别是接⼝和抽象类,经常⽤到这种⽅式。对于⼩编这种由C转Java的⼈来说,真是⼀⼤坑啊。
为什么Activity和Service都可以直接使⽤图中的四个⽅法呢,这是因为Activity和Service都是继承⾃ContextWrapper,所以⼦类拥有⽗类的⽅法。BroadcastReceiver和contentProvider则不是,具体⼤家可以看官⽅API。
⼆、跨应⽤启动的实战
** 下⾯让我们正式进⼊今天的主题:跨应⽤启动实战**
1:AppA的Activity中,启动AppB的Activity
Android提供了在⼀个App中启动另⼀个App中的Activity的能⼒,这使我们的程序很容易就可以调⽤其
他程序的功能,从⽽就丰富了我们App的功能。⽐如在中发送⼀个位置信息,对⽅可以点击这个位置信息启动腾讯地图并导航。这个场景在现实中作⽤很⼤,尤其是朋友在陌⽣的环境不到对⽅时,这个功能简直就是救星。
本来想把本⽂的名字叫启动另⼀个进程中的Activity,觉得这样才有逼格。因为每个App都会运⾏在⾃⼰的虚拟机中,每个虚拟机跑在⼀个进程中。但仔细⼀想,能够称为⼀个进程,前提是这个App必须要运⾏起来才⾏。⽽Android提供的能⼒,是不需要另⼀个App启动就可以将其特定的Activity启动起来的。
也就是说B应⽤是处理未启动的状态,也就是还没有成为系统的⼀个进程,那么当使⽤A启动B应⽤的某个组件时,请问,B应⽤是否成为系统的进程?答案是yes。怎么看呢,可以从Android Studio 的Android device monito 中结合虚拟机看。
我们有⾄少两种办法达到启动另⼀个App中的Activity。
第⼀种———隐式Intent的action⽅式。
相信这种⽅式,⼤家都不会陌⽣。这⾥就不进⾏过多的解析。这⾥只贴⼀下AppB的manifest(⽂件清单):
从⽂件清单中,我们可以看到,appB中有两个Activity。其中SecondActivity就是要被appA启动的Activity。
那么我们只要在appA的任意⼀个组件(Activity或Service),做如下的调⽤:
1 2Intent intent=new Intent("android.intent.action.SecondActivity"); startActivity(intent);
就可以成功在 A应⽤中 启动B应⽤的 组件。另外还要跟⼤家说⼀点,SecondActivity的category⼀定要在⽂件清单中添加上,否则启动的时候会报错的。
1 2 3 4 5 6 7不知道⼤家有没有思考过这三个事情:
1 、当A应⽤启动 B应⽤的SecondActivity,那么B应⽤的MainActivity会不会被启动呢?正常情况下,我们点击应⽤B,进到的是MainActivity这个活动,那么现在我们是通过跨应⽤启动,会不会要经过B的MainActivity呢?答案是不会。
2 、当我们在SecondActivity中点击Back回退键时,回到的是A应⽤的mainActivity界⾯,这⾥时候⼤家有没有想过。
SecondActivity和appA的mainActivity是不是同处于⼀个栈中呢?这时候就要去打印栈的ID了。
3 、由上⾯的两件事,不知道⼤家想起:Android对于Activity的管理,也就是framework层的ActivityManager。也就是说,你⼿机上的N多应⽤,当你打开某⼀个应⽤是,这个应⽤的Activity都是由ActivityManager这娃来创建和管理的。应⽤本⾝并没有创建Activity的能⼒。当然这其中⼜涉及到了Ibinder的通讯。这⾥暂时不讲。
第⼆种⽤intent设置className或component的办法启动。举例如下。
新建两个项⽬ProjectA和ProjectB,⽤B中的MainActivity启动A的MainActivitity。关键代码如下:ProjectA MainActivity
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27@Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_VIEW);
String packageName = "life.anotherapp";
String className = "life.anotherapp.MainActivity";
intent.setClassName(packageName, className);
//second method
//intent.setComponent(new ComponentName("life.anotherapp","life.anotherapp.MainActivity")); Bundle bundle = new Bundle();
bundle.putString("msg", "this message is from project B ");
intent.putExtras(bundle);
intent.putExtra("pid", android.Pid());
startActivityForResult(intent, 1);
//startActivity(intent);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch(requestCode) {
case1:
if(resultCode == RESULT_OK) {
textView.StringExtra("result"));
}
break;
}
}
ProjectB MainActivity
1 2 3 4@Override
protected void onCreate(Bundle savedInstanceState) { Create(savedInstanceState); setContentView(R.layout.activity_main);
5 6 7 8 9 10 11 12 13 14 15 16 17 18textView = (TextView)findViewById();
Intent intent = getIntent();
if(intent != null) {
textView.StringExtra("msg")); }
}
public void OnClick(View view) {
Intent intent = new Intent();
intent.putExtra("result","OK! from project a."); this.setResult(RESULT_OK,intent);
this.finish();//要清楚这⾥为什么要⽤finish()。}
注意:如果在应⽤B中,是通过按下Back键,回退到应⽤A的MainActivity活动,那么A的onActivityResult()⽅法是不会被回调的,这是因为ProjectB的MainActivity活动只是出栈⽽已,并没有销毁。⽽只有ProjectB的MainActivity活动被销毁的时候,才会回调A 的onActivityResult()⽅法。那如果是按了Back键回退的话怎么处理呢?这时候只要重写appB的onBackPressed()⽅法就好了。
1 2 3 4 5 6 7 8@Override
public void onBackPressed() {
安卓intent用法BackPressed();
Intent intent = new Intent();
intent.putExtra("result","OK! from project a."); this.setResult(RESULT_OK,intent);
this.finish();//要清楚这⾥为什么要⽤finish()。}
⼆:进阶———在A应⽤的Activity中启动(停⽌)——B应⽤的服务应⽤B的manifest
应⽤B的service的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26public class MyService extends Service {
private static final String TAG = "MyService";
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented"); }
@Override
public void onCreate() {
Log.d(TAG, "onCreate: ");
}
@Override
public int onStartCommand(Intent intent,int flags, int startId) { Log.d(TAG, "onStartCommand: ");
if(intent != null) {
Log.d(TAG, "onStartCommand: "+StringExtra("msg"));
}
StartCommand(intent, flags, startId);
27 28 29 30 31 32 33 34}
@Override
public void onDestroy() { Destroy(); Log.d(TAG, "onDestroy: "); }
}
应⽤A的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20@Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_VIEW);
String packageName = "life.anotherapp"; String className = "life.anotherapp.MyService"; intent.setClassName(packageName, className);
Id()) {
case R.id.btn_start:
Bundle bundle = new Bundle();
bundle.putString("msg", "this message is from project B "); intent.putExtras(bundle);
intent.putExtra("pid", android.Pid()); startService(intent);
break;
case R.id.btn_stop:
stopService(intent);
break;
}
}
测试结果:A应⽤直接启动B应⽤的服务,⽽B应⽤并不会打开⾃⼰的Activity。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论