Android基础查缺补漏之Intent&Activity

第一次接触Android是在我大三那会,大概是Gingerbread和Ice Cream Sandwich还很流行的时候。放现在看,不仅很多Jelly Bean及以后的新技术都没接触过,好些早就有的东西当时学的也不扎实,所以现在回过头来再补补。首先补上的是关于Intent和Activity的一些东西,这恐怕也是学习Android最一开始学的内容了。

一、隐式Intent

之前启动Activity、启动Service啥的,用的多是类似new Intent(this, Foo.class)这样的Intent,这种明确指定了类名的Intent叫做显式Intent,对应的就有隐式Intent,即没有指定类名而仅是指定了要执行的操作的Intent。

声明隐式Intent时可以携带的信息包括Action、Data、Type和Category。比较常用的是前三者,分别用于指定要执行的操作、要操作数据的URI和要操作数据的MIME类型,对应方法setAction()、setData()和setType(),不过由于Data和Type会相互覆盖,所以还有一个setDataAndType()方法。

下面的代码就可以发送一个隐式Intent,用于浏览CSDN网站。

Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.csdn.net"));

当这个Intent被发出后,Android会检查所有已经安装的App,看谁能够处理它。如果只有一个App能处理,自然只能用这个App,否则会让用户选择用哪个App来处理。不过,如果没有App能处理,App会崩溃,所以可以在Intent发出前,先检查有没有App能处理,代码如下。

if (intent.resolveActivity(getPackageManager()) != null) {
    startActivity(intent);
} else {
    Toast.makeText(this, "没有应用可以处理这个Intent", Toast.LENGTH_SHORT).show();
}
在有多个App可选的情况下,用户可以选定一个默认App,如果不希望用户做这样的选择,也可以强制弹出选择App的对话框(对比会发现,已经没有“仅此一次”和“始终”可选了)。实现的方法也很简单,只要在现有Intent的基础上包装一层Chooser(参数中的null可以替换成对话框的标题),但实际上是重新实例化了一个Action为Intent.ACTION_CHOOSER的Intent,而把原来的Intent放在新Intent的Extras中。

Intent sendIntent = Intent.createChooser(intent, null);
startActivity(sendIntent);

最后是关于声明应用所能接收的隐式Intent,通过在清单文件中为相应组件添加<intent-filter>标签即可。<intent-filter>标签下可配置<action>、<data>、<category>子标签,分别用来过滤所能接受的Intent操作、数据URI(包括scheme、host、port、path等部分)、数据MIME和Intent类型。因为startActivity()等方法发出的Intent默认添加了CATEGORY_DEFAULT这么一个category,所以在过滤Intent的时候也必须添加它。下面这段代码就让某个Activity具有了接受“浏览HTTP之Intent”的功能(可不一定真的实现了浏览HTTP的功能哦~接收某个Intent又不能实现相应功能是会严重影响体验的)。

<intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT"/>
    <data android:scheme="http" />
</intent-filter>

二、Activity的四种启动模式

Activity一共有standard、singleTop、singleTask和singleInstance四种启动模式,可以通过配置<activity>标签的android:launchMode属性来改变(当然,有些模式是可以通过Intent的setFlag()方法来设置的)。

用这样一个App来探究这四种模式。App中共有FirstActivity、SecondActivity、ThirdActivity3个界面,每个Activity上都是3个按钮,分别用来跳转到相应的Activity。每个Activity在完整生存期对应的方法(onCreate()和onDestory())被调用时打印自己的haseCode(和所属的taskId)。

standard模式是默认的模式,可以不必指定,其特点是Activity每次启动时都会重新实例化,而与当前回退栈栈顶的Activity无关。

示例:在这个App连续中点击2次StartFirstActivity按钮,Logcat会打印下面的内容。可以看出,连同通过Launcher启动的,一共实例化了3个FirstActivity实例,也要按3次Back键才能完全退出App。

06-06 16:59:41.488 30088-30088/com.example.test1 D/FirstActivity: 64651776 onCreate, TaskId == 61
06-06 16:59:54.862 30088-30088/com.example.test1 D/FirstActivity: 65862281 onCreate, TaskId == 61
06-06 16:59:57.844 30088-30088/com.example.test1 D/FirstActivity: 137213575 onCreate, TaskId == 61
06-06 17:00:01.022 30088-30088/com.example.test1 D/FirstActivity: 137213575 onDestory
06-06 17:00:02.323 30088-30088/com.example.test1 D/FirstActivity: 65862281 onDestory
06-06 17:00:03.071 30088-30088/com.example.test1 D/FirstActivity: 64651776 onDestory

singleTop模式与standard模式的区别则在于,如果在启动某个Activity时,它的实例已经位于回退栈栈顶,则不会再实例化一次,而是会直接调用这个Activity的onNewIntent()方法(话说我头一回见这个方法是在做一个用到NFC前台任务调度的App时)向其传递新的Intent,但相反地,依然会进行实例化。

示例:将FirstActivity修改为singleTop模式,然后先点击任意多次StartFirstActivity按钮,再分别点击一次StartSecondActivity按钮和StartFirstActivity按钮。观察Logcat会发现在FirstActivity上点击StartFirstActivity按钮时没有实例化新的FirstActivity对象,但在SecondActivity上点击StartFirstActivity按钮时却实例化了新的FirstActivity对象,要退出App也需要按3次Back键。

06-06 17:05:48.792 3494-3494/com.example.test1 D/FirstActivity: 64651776 onCreate, TaskId == 63
06-06 17:05:54.243 3494-3494/com.example.test1 D/SecondActivity: 254974606 onCreate, TaskId == 63
06-06 17:05:57.542 3494-3494/com.example.test1 D/FirstActivity: 209586612 onCreate, TaskId == 63
06-06 17:06:02.590 3494-3494/com.example.test1 D/FirstActivity: 209586612 onDestory
06-06 17:06:03.888 3494-3494/com.example.test1 D/SecondActivity: 254974606 onDestory
06-06 17:06:04.507 3494-3494/com.example.test1 D/FirstActivity: 64651776 onDestory

singleTask模式则没有了singleTop模式的“当要启动的Activity不在回退栈栈顶时需要重新实例化”的问题。当启动一个singleTask模式的Activity时,系统会检查回退栈,如果栈中已经存在这个Activity的实例,那么就直接使用它,在它上面的其他Activity统统会被销毁(这也是栈的特性决定的吧),反之当然还是要进行实例化的。

示例:将FirstActivity修改为SingleTask模式,同样地先点击任意多次StartFirstActivity按钮,再分别点击StartSecondActivity、StartThirdActivity和StartFirstActivity按钮各一次。观察到在FirstActivity上点击StartFirstActivity按钮时没有任何变化,但在ThirdActivity上点击StartFirstActivity按钮时,原本位于栈顶的ThirdActivity和SecondActivity都被销毁了,此时要退出App只需要按一次Back键,至始至终FirstActivity也只实例化了一次。

06-06 17:11:28.034 8438-8438/com.example.test1 D/FirstActivity: 64651776 onCreate, TaskId == 64
06-06 17:11:34.912 8438-8438/com.example.test1 D/SecondActivity: 254974606 onCreate, TaskId == 64
06-06 17:11:36.626 8438-8438/com.example.test1 D/ThirdActivity: 232204765 onCreate, TaskId == 64
06-06 17:11:41.240 8438-8438/com.example.test1 D/SecondActivity: 254974606 onDestory
06-06 17:11:42.102 8438-8438/com.example.test1 D/ThirdActivity: 232204765 onDestory
06-06 17:11:46.972 8438-8438/com.example.test1 D/FirstActivity: 64651776 onDestory

最后一个是SingleInstance模式,字面上的意思是“单例”,但Android不仅仅保证对应的Activity只有一个实例,甚至保证对应的Activity在一个单独的回退栈里运行。

示例:将FirstActivity修改回standard模式、将SecondActivity修改为singleInstance模式,依次点击StartSecondActivity、StartThirdActivity、StartSecondActivity、StartFirstActivity按钮各一次。观察Logcat,发现这是四种模式中唯一出现了不同taskId的,而且与其他Activity不位于同一个回退栈中的Activity,正是被设置为singleInstance模式的SecondActivity,而且不论怎样启动SecondActivity,始终出现的都是这个“与众不同”的Activity。而在退出App时,因为当前Activity位于第一个回退栈中的FirstActivity,所以依次先销毁了这个栈中的3个Activity,然后才轮到另一个回退栈中的SecondActivity被销毁。

06-06 17:21:42.175 10822-10822/com.example.test1 D/FirstActivity: 265994406 onCreate, TaskId == 71
06-06 17:21:43.779 10822-10822/com.example.test1 D/SecondActivity: 27392981 onCreate, TaskId == 72
06-06 17:21:45.744 10822-10822/com.example.test1 D/ThirdActivity: 160142899 onCreate, TaskId == 71
06-06 17:21:48.879 10822-10822/com.example.test1 D/FirstActivity: 98859028 onCreate, TaskId == 71
06-06 17:21:53.317 10822-10822/com.example.test1 D/FirstActivity: 98859028 onDestory
06-06 17:21:54.601 10822-10822/com.example.test1 D/ThirdActivity: 160142899 onDestory
06-06 17:21:56.485 10822-10822/com.example.test1 D/FirstActivity: 265994406 onDestory
06-06 17:21:56.928 10822-10822/com.example.test1 D/SecondActivity: 27392981 onDestory

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值