Android开发学习 -- Day3 探究Activity(二
上一章的内容中,我们手动创建了Activity,并学会使用Toast和添加Menu菜单。今天要学习更多的内容。
一、使用Intent在Activity之间穿梭
1、使用显式Intent
现在相信我们已经能够熟练的创建Activity了,新建一个SecActivity,让Android Studio帮我创建SecActivity.java和activity_sec.xml文件。由于SecActivity不是主Activity,因此不惜要配置<intent-filter>标签里的内容。第二个Activity创建成功,剩下的问题件就是如何启动这个Activity,这里我们需要引入一个新的概念:Intent。
Intent是Android程序汇总各组件之间进行交互的一种重要方式,他不仅可以知名当前组件想要执行的动作,还可以在不停组件之间传递数据。Intent一般可被用于启动Activity、启动Service以及发送广播等场景。
Intent大致可以分为两种:显式Intent和隐式Intent,我们先来看一下显式Intent。
Intent有多个构造函数的重载,其中一个是Intent(Context packageContext, Class<?> cls)。这个构造函数接收两个参数,第一个参数Context要求提供一个可以启动Activity的上下文,第二个参数Class则是指定我们想要启动的目标Activity,通过这个构造函数就可以构建出Intent的“意图”。Activity类中提供一个startActivity()方法,这个方法是专门用于启动Activity的,他接收一个Intent参数,我们将构建好的intent传入startActivity()方法就可以启动目标Activity了。
private static final String[] strs = new String[]{"显式intent:Sec Activity"};
private ListView lv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_view_demo);
lv = findViewById(R.id.list_view_demo);
lv.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, strs));
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
switch (position){
case 0:
Intent intent = new Intent(ListViewDemoActivity.this, SecActivity.class);
startActivity(intent);
break;
default:
}
}
});
}
为了后面方便,我们先创建了一个listVIew来存放目录,目前只有一条"显式intent:Sec Activity"。然后使用了ArrayAdapter并且设置了对应的响应事件。
可以看到我们构建了一个Intent,传入ListViewDemoActivity.this作为上下文,传入SecActivity.class作为目标活动。这样我们的“意图”就非常明显了,即在ListViewDemoActivity的基础上,打开SecActivity,然后通过startActivity()来执行这个Intent。
重新运行下应用,点击第一个条目,就能成功的打开SecActivity了。
2、使用隐式Intent
相比于显式Intent,隐式Intent则含蓄许多,它并不明确的指出我们想要启动哪一个Activity,而是指定了一系列更为抽象的action和category等信息,然后交由系统去分析这个Intent,并帮我们找出合适的Activity去启动。
所谓合适的Activity,简单来说就是可以响应我们这个隐式Intent的Activity。通过在<Activity>标签下配置<intent-filter>的内容,可以指定当前Activity能够响应的action和category。打开AndroidManifest.xml,添加如下代码
<activity android:name=".Activity.SecActivity">
<intent-filter>
<action android:name="com.johnhao.listviewdemo.ACTION_START" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.MY_CATEGROY" />
</intent-filter>
</activity>
在<action>标签中,我们指明了当前Activity活动可以响应com.johnhao.listviewdemo.ACTION_START这个action,而<category>标签则包含了一些附加信息,更精确地指明当前Activity能够响应的Intent中还可能带有category。只有<action>和<category>中的内容同时能够匹配上Intent中指定的action和category时,这个Activity才能响应该Intent。
我们在ListView中新添加一条“隐式intent:Sec Activity”,并且新建一个对应的case分支
private static final String[] strs = new String[]{"显式intent:Sec Activity", "隐式intent:Sec Activity"};
......
case 1:
Intent hide_intent = new Intent("com.johnhao.listviewdemo.ACTION_START");
hide_intent.addCategory("android.intent.category.MY_CATEGROY");
startActivity(hide_intent);
break;
可以看到我们使用了Intent的另一个构造函数,直接将action的字符串穿了进去,表明我们想要启动能够响应com.johnhao.listviewdemo.ACTION_START这个action的活动。在这里我们设置了两个category,一个默认的Default,另一个是MY_CATEGROY。Default是一种默认的category,在调用startActivity()方法时会自动将这个category添加到Intent中。当category值不为default时,我们可以调用Intent中的addCategory()方法来添加一个category,这里我们的category值为“android.intent.category.MY_CATEGROY”。
重新运行下程序,试一试显式Intent和隐式Intent都能成功的打开SecActivity。
3、更多隐式Intent的用法
使用隐式Intent,我们不仅可以启动自己程序内的Activity,还可以启动其他应用程序的Activity,这使得Android多个应用职期间的功能共享成为了可能。例如我们想打开一个网页,这时其实没必要自己去实现一个浏览器,而是只需要调用系统的浏览器来打开这个网页就行了。
我们在list中再添加一条打开网页,并设置list的点击事件:
......
case 2:
Intent web_intent = new Intent(Intent.ACTION_VIEW);
web_intent.setData(Uri.parse("http://www.baidu.com"));
startActivity(web_intent);
break;
这里我们首先定制了Intent的action是Intent.ACTION_VIEW,这是一个Android系统内置的动作,其常量值为android.intent.action.VIEW。然后通过Uri.parse()方法,将一个往回走字符串解析成一个Uri对象,在调用Intent的setData()方法将这个Urii对象传递进去。
重新运行程序,点击该条list之后,就能打开系统的浏览器了。
![](https://img.haomeiwen.com/i7633163/15712b2ccc73baa5.gif)
4、向下一个Activity传递数据
上面我们通过Intent实现了Activity的启动,其实Intent还以在启动Activity的时候传递数据。
Intent中提供了一系列的putExtra()方法的重载,可以吧我们想要传递的数据暂存在Intent中。启动一个Activity后,只需要把这些数据再从Intent中取出就可以了。比如我们要传递一个字符串过去,可以这样实现。
String data = "Hello, new Activity, this is message in Intent";
Intent data_intent = new Intent(ListViewDemoActivity.this, ThrActivity.class);
data_intent.putExtra("extra_data", data);
startActivity(data_intent);
这里还是使用显式Intent来启动Activity,并通过putExtra()方法传递了一个字符串。putExtra()方法接收两个参数,第一个参数是键,第二参数是要传达的数据。
然后我们在ThrActivity中把数据取出,并显示出来:
private TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_thr);
setTitle("ThrdActivity");
Intent intent = getIntent();
String data = intent.getStringExtra("extra_data");
tv = (TextView)findViewById(R.id.tv);
if (null != data){
tv.setText(data);
}
}
首先通过getIntent()方法获取到用于启动ThrActivity的Intent,然后调用getStringExtra()方法,传入对应的键值来获取传递的数据。前面我们传的是String,所以使用getStringExtra()方法;如果传递的是布尔型的,则需要使用getBooleanExtar()方法,以此类推。这里我们使用了一个textView用来展示数据,当获取到Intent中的数据时,就调用setText()方法,将数据展示出来。
重新运行程序,点击跳转后,我们就能看到在页面上,展示了我们传递的数据。
![](https://img.haomeiwen.com/i7633163/cfc7c000e148cfb0.png)
5、返回数据给上一个Activity
既然可以传递数据给下一个Activity,那么也可以返回数据给上一个Activity。不过不同的是,返回上一个Activity只需要按一下back键就可以了,没有用于启动Activity的Intent来传递数据。不过通过查阅文档可以发现,Activity中还有一个startActivityForResult()方法也是用于启动Activity的。但这个方法期望在Activity销毁的时候能够返回一个结果给上一个Activity。
startActivityForResult()接收两个参数,第一个参数还是Intent,第二个参数是请求码,用于在之后的回调中判断数据来源。首先我们先创建一个点击事件:
Intent back_data = new Intent(ListViewDemoActivity.this, SecActivity.class);
startActivityForResult(back_data, 1);
使用startActivityForResult()方法启动SecActivity,请求码设置为1。接下来,我们修改SecActivity的代码,添加一个按钮,并给按钮注册点击事件:
btn2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String data = "message from SecActivity";
Intent intent = new Intent();
intent.putExtra("Extra_data", data);
setResult(RESULT_OK, intent);
finish();
}
});
可以看到,我们还是构建了一个Intent,只不过这个Intent只用于传递数据,没有指定任何“意图”。把数据存放在Intent中,然后调用了setResult()方法,用于向上一个Activity返回处理结果,一般只试用RESULT_OK或RESULT_CANCELED这两个值。第二个参数为要传递的数据,然后调用finish()方法来销毁当前Activity。
由于我们是通过startActivityForResult()方法启动的SecActivity,在SecActivity被销毁之后会回调上一个Activity的onActivityResult()方法,因此我们需要重写onActivityResult()方法:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case 1:
if (resultCode == RESULT_OK) {
String data_back = data.getStringExtra("Extra_data");
Toast.makeText(this, data_back, Toast.LENGTH_SHORT).show();
}
break;
default:
}
}
onActivityResult()方法带有3个参数,第一个参数是requestCode,即我们在启动Activity是传递的请求码。第二个参数resultCode,即我们返回数据是传入的处理结果。第三个参数data,即携带返回数据的Intent。一个Activity中,可能存在很多请求不同Activity的行为,每一个startActivityForResult()都会回调onActivityResult()方法,这时候就需要用requestCode来区分数据来源。
重新运行应用,当从SecActivity返回时,就能看到弹出了一个Toast提示。
![](https://img.haomeiwen.com/i7633163/804539d5c7611a6e.gif)
今天学习了在Activity中使用Intent的一些知识,利用显式或隐式Intent来启动Activity,还有更多关于隐式Intent的用法,以及通过intent向下一个或上一个Activity传递数据。小伙伴们都掌握了么。