Android Activity的启动和跳转
来源:互联网 发布:淘宝网官方网站登入 编辑:程序博客网 时间:2024/05/17 04:59
启动当前app中的Activity
在Android中要跳转到另一个Activity,可以通过在当前Activity中调用startActivity()或startActivityForResult()来实现。
以startActivity()为例,从MainActivity跳转到SecondActivity的示例代码如下。
Intent intent = new Intent(MainActivity.this, SecondActivity.class);startActivity(intent);
或者
Intent intent = new Intent();intent.setClass(MainActivity.this, SecondActivity.class);startActivity(intent);
或者
Intent intent = new Intent();ComponentName componentName = new ComponentName(MainActivity.this, SecondActivity.class);intent.setComponent(componentName);startActivity(intent);
查看Intent类的源码可以发现这三种方式实际上是完全等价的,都是创建了一个ComponentName对象,然后赋值给Intent类的mComponent成员变量。
启动其他app中的Activity
通常我们都是跳转到当前app自身的其他Activity中,但事实上startActivity()或startActivityForResult()还可以启动手机上其他已经安装的app中的Activity。
假设要启动的Activity所在app的package name为com.ccpat.otherapp,类名为com.ccpat.otherapp.MainActivity。启动该Activity可以使用如下方法。
setComponent方法
示例代码如下
ComponentName componetName = new ComponentName("com.ccpat.otherapp", "com.ccpat.otherapp.MainActivity");Intent intent= new Intent();intent.setComponent(componetName);startActivity(intent);
再举个例子,如果我们想要在自己的app中开启微信,可以使用如下代码。
ComponentName componetName = new ComponentName("com.tencent.mm", "com.tencent.mm.ui.LauncherUI");Intent intent= new Intent();// 在LauncherUI的onCreate中会对当前Activity堆栈的baseactivity的包名做校验,// 如果baseactivity的包名不是"com.tencent.mm",则直接finish。// 所以这里启动的时候需要将其放到一个新的Activity堆栈中 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);intent.setComponent(componetName);startActivity(intent);
setClassName方法
代码示例如下:
Intent intent = new Intent();String packageName = "com.ccpat.otherapp";String className = "com.ccpat.otherapp.MainActivity";intent.setClassName(packageName, className);startActivity(intent);
如果要启动的Activity所在的app不存在,或者Activity不存在,则会抛出ActivityNotFoundException异常,如图所示。
setComponent和setClassName方法的统一性
查看Intent类的源码可以发现这种方式和setComponent方式是完全等价的,同样都是创建了一个ComponentName对象,然后赋值给Intent类的mComponent成员变量。附上Activity类中的setClassName()方法的实现及注释。
由于setComponent和setClassName方法本质上是相同的,所以后面会将它们作为一种方法来看待,称为setComponent/setClassName方法。
setComponent/setClassName方法启动Activity的要求
通过这种方法启动的其他app中的Activity,必须是exported。
在AndroidManifest.xml中声明一个Activity时可以为其添加android:exported属性,它的值可以是true或false。如果一个Activity为exported,它才可以被其他应用启动,否则它就只能在当前app中启动。
如果没有显式的指定这个值,则它的默认值取决于该Activity是否有设置intent-filter,如果有设置intent-filter,则默认为true,否则为false。
如下Activity的exported属性为true
<!-- 显式的声明exported为true --> <activity android:name=".MainActivity" android:exported="true" />
<!-- 指定了intent-filter,exported默认为true --> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.net.VpnService" /> </intent-filter></activity>
如下Activity的exported属性为false
<!-- 没有intent-filter,exported默认为false --> <activity android:name=".MainActivity" />
<!-- 显式的声明exported为false,则无论有无intent-filter,exported属性都是false --> <activity android:name=".MainActivity" android:exported="false"> <intent-filter> <action android:name="android.net.VpnService" /> </intent-filter></activity>
如果通过上述方式启动了其他app中一个非exported的Activity,则会抛出SecurityException异常,如图所示。
异常处理
由于无法控制用户手机上是否会安装某个app,也无法决定该app中Activity的类名及exported属性是否会随着版本升级发生改变,所以使用上述方式启动Activity时,通常都需要用try catch来捕获异常。
例如:
try { ComponentName componetName = new ComponentName("com.ccpat.otherapp", "com.ccpat.otherapp.MainActivity"); Intent intent= new Intent(); intent.setComponent(componetName); startActivity(intent);} catch (ActivityNotFoundException e) {} catch (SecurityException e) {}
此外,部分机型的ROM将这种启动其他app中Activity的行为纳入到权限管理中,如果一个app要其启动其他app中的Activity,会弹出一个权限请求的界面,只有用户选择同意后才可以启动。
setComponent/setClassName方法启动当前app中的Activity
setComponent/setClassName方法既可以用来启动其他app中的Activity,也可以用来启动当前app中的Activity,只需要将对应的包名和类名替换为当前app的包名和要启动的Activity类名即可。和启动其他app中Activity唯一的不同是,setComponent/setClassName方法启动当前app中的Activity不需要该Activity的exported属性为true。
显式(explicit)intent启动Activity
查看Intent类的源码可以发现,无论是“启动当前app中的Activity”中介绍的三种方式,还是“启动其他app中的Activity”中介绍的setComponent/setClassName方法,本质上都是相同的。它们都是创建了一个ComponentName对象,然后将其赋值给Intent类的mComponent成员变量。这也是为什么setComponent/setClassName方法也可以用来启动当前app中的Activity。
上述这些启动Activity的方式都称为通过显式(explicit)Intent来启动Activity。这种启动方式的特点是它们都需要明确的知道要启动的Activity所在的app的包名及Activity自身的类名。所以如果同时使用了多种方式,则显然只有最后设置的才会生效。
在下面的例子中通过不同的方式设置了4个要启动的Activity,但最后实际启动的只有”com.ccpat.app2”中的”com.ccpat.app2.MainActivity”。
Intent intent= new Intent(MainActivity.this, SecondActivity.class); // 方式1intent.setClass(MainActivity.this, ThirdActivity.class); // 方式2ComponentName componetName = new ComponentName("com.ccpat.app1", "com.ccpat.app1.MainActivity");intent.setComponent(componetName); // 方式3String packageName = "com.ccpat.app2";String className = "com.ccpat.app2.MainActivity";intent.setClassName(packageName, className); // 方式4startActivity(intent);
通过显式Intent来启动其他app中Activity的方式需要已知目标app的包名和Activity类名。这种方式有一定的局限性,一方面我们想要启动某项功能,但是可能并不知道该功能对应的app包名和Activity的类名,另一方面,应用的包名可能会随着Android系统版本或应用市场的不同而不同,Activity的类名也可能随着版本的更新而改变。在Android中提供了另外一种启动其他应用中Activity的方式,即隐式intent的方式。通过隐式intent方式启动Activity不需要知道Activity的类名及对应的包名。
隐式intent启动Activity
通过隐式intent启动其他app中Activity的示例如下:
Intent intent = new Intent("com.ccpat.ACTION_TEST");startActivity(intent);
或者
Intent intent = new Intent();intent.setAction("com.ccpat.ACTION_TEST");startActivity(intent);
这两种方式同样是完全等价的。
隐式intent方法启动Activity的要求
和显式intent方法启动Activity一样,如果目标Activity不在当前app中,而是在其他app中,则必须是exported,否则会抛出SecurityException。此外,要启动的Activity必须要在intent-filter中声明指定的action。
例如,上述方式启动的action为com.ccpat.ACTION_TEST,则需要将com.ccpat.ACTION_TEST声明在要启动的Activity所在app的AndroidManifest.xml中。
<activity android:name=".MainActivity" > <intent-filter> <action android:name="com.ccpat.ACTION_TEST" /> <category android:name="android.intent.category.DEFAULT" </intent-filter></activity>
由于隐式intent方法启动的Activity必须指定intent-filter,其exported属性默认为true,所以可以不用在AndroidManifest.xml中手动添加这项属性。但是如果只希望在当前app中通过隐式intent启动该Activity,则可以加上android:exported=”false”。
异常处理
和显式Intent一样,通过隐式intent方法启动的Activity时,如果设备中没有找到任何Activity处理该action,则会抛出ActivityNotFoundException的异常。因此,一般来说,通过隐式Intent来启动Activity也应当加上try catch来捕获异常。
隐式intent启动Activity示例
通过隐式intent方式启动Activity只需要知道该Activity所声明的action即可,而action对应的是某项功能,因此只需要知道某项功能对应的action字符串,将其填入intent中。
在Android系统中已经有很多已经定义好action的Activity,它们都可以通过隐式Intent来启动。这里列举了一些常见的ACTION。
// 拨打电话Intent intent = new Intent(Intent.ACTION_CALL);// 打开系统时间设置(在Settings类中还有很多其他定义好的ACTION,对应于其他的设置界面)Intent intent = new Intent(Settings.ACTION_DATE_SETTINGS);// 相机Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);// 文件选择Intent intent = new Intent(Intent.ACTION_PICK);// 系统分享Intent intent = new Intent(Intent.ACTION_SEND);
如果有多个Activity声明了同一个Action,系统会按照一定的规则进行匹配。在隐式intent中可以增加一些额外信息用于匹配过程,额外的信息包括PackageName,Category,data,type,这里不再详述。
intent中显式和隐式一起使用
如果在一个intent中同时使用了显式和隐式两种方式来指定要启动的Activity,则实际启动的Activity以显式Intent指定的为准,和他们使用的先后顺序无关。
例如:
Intent intent = new Intent();String packageName = "com.ccpat.otherapp";String className = "com.ccpat.otherapp.MainActivity";intent.setClassName(packageName, className);intent.setAction(Intent.ACTION_VIEW);intent.addCategory("android.intent.category.BROWSABLE");intent.setData(Uri.parse("http://www.csdn.net"));startActivity(intent);
这里先是通过显式intent指定要启动的activity为com.ccpat.otherapp中的com.ccpat.otherapp.MainActivity,然后又通过隐式intent指定要启动的activity为action为Intent.ACTION_VIEW,category为”android.intent.category.BROWSABLE”。 这时会显式intent指定的activity,也就是启动com.ccpat.otherapp中的com.ccpat.otherapp.MainActivity,而不是打开浏览器。
- Android Activity的启动和跳转
- Android中Activity的新建和跳转
- Android的Activity跳转和ProgressBar进度条
- android Activity的跳转
- android activity跳转 和 生命周期
- Android--(1)Activity组件的作用,如何创建Activity,如何启动Activity,以及Activity之间跳转的示例
- 实验四Activity启动和跳转
- 拆解Activity的启动和跳转另一个Activity的生命周期的变化
- Android Activity的跳转:普通跳转(显式跳转,隐式跳转)和传值跳转
- Android:Activity的生命周期和启动方式
- Android Activity的启动和创建
- android中Activity的跳转
- Android实现Activity的跳转
- android Activity之间的跳转
- Android Activity之间的跳转
- Android中Activity的跳转
- Android Activity的跳转动画
- Android 中 Activity的跳转
- nyoj123——士兵杀敌(四)
- 《iOS移动开发从入门到精通》图书连载18:函数作为参数和返回类型
- android中华为、小米手机设置头像裁剪失败问题
- BZOJ 1053: [HAOI2007]反素数ant 数论,DFS
- Android 6.0新特性之Doze模式
- Android Activity的启动和跳转
- 一些贪心算法的盲区
- 前端实战实用笔记
- appium自动化测试环境搭建
- c#第一,二章总结
- 测试工程如何搭建?配置文件如何读取?
- H5利用FileReader上传图片
- 编译原理分析过程
- 关于climits