Android页面Activity&页面跳转&数据传递
导语
Activity&页面跳转&数据传递 介绍
一、创建第二个Activity
- 1.自定义类继承Activity (一个新的页面) 给其创建布局文件
- 2.需要在清单文件中为其配置一个activity标签
<activity android:name="包名.类名"> </activity>
- 注意:
- 1.在清单中进行如下配置,会在桌面出现两个图标,名字一样的快捷方式,
- 因为主页面,已经在activity标签配置了Activite入口,新页面又配置了Activity入口
<activity android:name="com.itheima.secondactivity.MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".SecondActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
- 2.在清单中进行如下配置后,会在桌面出现两个不同图标,不同名字的启动快捷方式
-
分别对应打开主页面和新建页面
<activity android:icon="@drawable/photo1" android:label="启动第一个" android:name="com.itheima.secondactivity.MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:icon="@drawable/photo2" android:label="启动第二个" android:name=".SecondActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
- activity标签中如果带有以下的
子节点,则会在系统中多创建一个快捷图标,就是新页面activity的启动图标 <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter>
- 一个应用程序可以在桌面创建多个快捷图标。
- activity的名称、图标可以和应用程序的名称、图标不相同
android:icon="@drawable/ic_launcher" android:label="@string/app_name"
###一个应用程序可以创建多个入口的activity,快捷图标 ,对应打开不同的页面
###只要配置了以下
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>`
###注意一个新页面,可以配置多个,用于其他页面进行匹配,使能够让其他页面跳转过来
#二、Activity的跳转
##2.1如何实现页面跳转
* Activity的跳转需要创建Intent对象,通过设置intent对象的参数指定要跳转Activity
public void click2(View v){
//显式意图
Intent intent = new Intent();
//指定目标Activity的字节码
intent.setClass(this, SecondActivity.class);
//显式跳转
startActivity(intent);
}
##Activity跳转分类
* 通过对Intent对象的参数设置不同,跳转方式也不同
* 显式意图:通过设置Activity的包名和类名实现跳转,称为显式意图
* 隐式意图:通过指定动作实现跳转,称为隐式意图
###显式意图:直接指定要激活的activity。效率高。直接指定。
* 跳转至同一项目下的另一个Activity,直接指定该Activity的字节码即可
public void click2(View v){
//显式意图
Intent intent = new Intent();
//指定目标Activity的字节码
intent.setClass(this, SecondActivity.class);
//显式跳转
startActivity(intent);
}
- 跳转至其他应用中的Activity,需要指定该应用的包名和该Activity的类名
public void click3(View v){ //显式意图 Intent intent = new Intent(); //启动系统自带的拨号器应用 //arg0:目标Activity所在的项目的应用包名 //arg1:目标Activity的包名和类名 intent.setClassName("com.android.dialer", "com.android.dialer.DialtactsActivity"); //显式跳转 startActivity(intent); }
###隐式意图:(动作,数据,category)开启新的activity。
* 1.隐式意图跳转至指定Activity
– 实际上系统的拨号器已经在自己的清单文件中进行了配置,使得此拨号器页面能够实现隐式启动,那么如何配置呢?
public void click4(View v){
Intent intent = new Intent();
//启动系统自带的拨号器应用
intent.setAction(Intent.ACTION_DIAL);
startActivity(intent);
}
* 2.要让一个Activity可以被隐式启动,需要在清单文件的activity节点中设置intent-filter子节点
* action 指定动作(可以自定义,可以使用系统自带的)name可以写任意自定义,一般比照谷歌的写法
* data 指定数据(操作什么内容)
* category 类别 (默认类别,机顶盒,车载电脑)
<intent-filter >
<action android:name="com.itheima.second"/>
<data
android:scheme="asd"
android:mimeType="aa/bb"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
##activity隐式启动在清单文件中的配置
* action activity对应的动作。 可以用任意一个字符串描述(最好,顾名思义)
* category 额外的类别参数。 指定工作的设备(车载电脑,机顶盒,默认的手机) 通常指定的参数android.intent.category.DEFAULT
* data 指定数据和数据的类型
* scheme 数据前缀
* host 主机名
* port 端口号
* path 路径 记得在前面加上 /
* mimeType 数据类型 从tomcat里面查找常见的数据类型
* 隐式启动页面,该页面的配置示例
<activity
android:name="com.itheima.activityjump.SecondActivity">
<intent-filter >
<action android:name="com.itheima.a1"/>
<data android:scheme="youyiyi1"/>
<action android:name="com.itheima.a3"/>
<data android:scheme="youyiyi3"/>
<data android:mimeType="text/name"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
<intent-filter >
<action android:name="com.itheima.a2"/>
<data android:scheme="youyiyi2"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
- 3.隐式意图启动Activity,需要为intent设置以上三个属性,且值必须与该Activity在清单文件中对三个属性的定义匹配
- 4.隐式意图启动Activity时要注意:
- 设置参数时setType()会清除setData(),而setData()会清除setType(), 两者不能共存,
- 所以通过setDataAndType(Uri.parse(“youyiyi3:xiaoming”), “text/name”);
- 一并将两者全部设置了
-
- 页面一跳转到页面二示例(如:隐式跳转上面配置的页面)
public void click5(View v){
Intent intent = new Intent();
intent.setAction(“com.itheima.a1”);
//匹配mimetype
// intent.setType(“text/name”);
//匹配scheme,注意setData()会将上面的setType清除
// intent.setData(Uri.parse(“youyiyi3:xiaoming”));
//匹配scheme和mimetype
intent.setDataAndType(Uri.parse(“youyiyi3:xiaoming”), “text/name”);//如果没有指定category,则自动添加以下代码
// intent.addCategory(Intent.CATEGORY_DEFAULT);
startActivity(intent);
} -
页面一跳转到页面二示例二(如:隐式跳转上面配置的页面)
public void click5(View v){ Intent intent = new Intent(); //匹配动作 intent.setAction("com.itheima.a2"); //匹配scheme intent.setData(Uri.parse("youyiyi2:xiaoming")); startActivity(intent); }
- 页面一跳转到页面二示例(如:隐式跳转上面配置的页面)
- 5.intent-filter节点及其子节点都可以同时定义多个,隐式启动时只需与任意一个匹配即可
#####在新页面获取通过setData传递的数据
- 获取启动此Activity的intent对象 ,通过intent得到数据
Intent intent = getIntent();
Uri uri = intent.getData();//第二个Activity获取传进过来的数据 public class SecondActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //指定Activity显示哪一个布局文件 setContentView(R.layout.activity_second); //获取传递过来的数据 //获取启动此Activity的intent对象 Intent intent = getIntent(); Uri uri = intent.getData(); System.out.println(uri); } }
###显式意图和隐式意图的应用场景
* 显式意图用于启动同一应用中的Activity,直接指定包名类名。效率高。
* 隐式意图用于启动不同应用中的Activity,通过action和data指定。
* 另外对于隐式意图:
– 如果系统中存在多个Activity的intent-filter同时与你的intent匹配,那么系统会显示一个对话框,列出所有匹配的Activity,由用户选择启动哪一个
#Activity跳转时的数据传递
* Activity通过Intent启动时,可以通过Intent对象携带数据到目标Activity
* 8大基本类型数据 以及数据的数组都是可以通过intnet传递
– intent.putExtra(name,values)
* 对象也可以通过intent传递。
– 要求对象一定是实现Serializable接口的 可序列化的对象。
– 要求对象一定是实现Parcelable 接口
- 方式一:直接将数据封装到intent中
public void click(View v){ EditText et_malename = (EditText) findViewById(R.id.et_malename); EditText et_femalename = (EditText) findViewById(R.id.et_femalename); String maleName = et_malename.getText().toString(); String femaleName = et_femalename.getText().toString(); Intent intent = new Intent(this, SecondActivity.class); //把数据封装至intent中 intent.putExtra("maleName", maleName); intent.putExtra("femaleName", femaleName); startActivity(intent); }
- 方式二:先把数据封装至bundle中,再把bundle封装至intent中
public void click(View v){ EditText et_malename = (EditText) findViewById(R.id.et_malename); EditText et_femalename = (EditText) findViewById(R.id.et_femalename); String maleName = et_malename.getText().toString(); String femaleName = et_femalename.getText().toString(); Intent intent = new Intent(this, SecondActivity.class); //把数据封装至bundle中 Bundle bundle = new Bundle(); bundle.putString("maleName", maleName); bundle.putString("femaleName", femaleName); //把bundle封装至intent中 intent.putExtras(bundle); startActivity(intent); } }
- 在目标Activity中取出数据(理解:在新页面,获取传递过来的数据)
Intent intent = getIntent(); String maleName = intent.getStringExtra("maleName"); String femaleName = intent.getStringExtra("femaleName"); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //指定Activity显示哪一个布局文件 setContentView(R.layout.activity_second); Intent intent = getIntent(); //直接获取封装在intent中的数据 //String maleName = intent.getStringExtra("maleName"); //String femaleName = intent.getStringExtra("femaleName"); //先通过intent获取Bundle对象 Bundle bundle = intent.getExtras(); //再通过Bundle对象,获取数据 String maleName = bundle.getString("maleName"); String femaleName = (String) bundle.get("femaleName"); Random rd = new Random(); int yinyuan = rd.nextInt(11) + 90; ((TextView)findViewById(R.id.tv)).setText(maleName + "与" + femaleName + "的缘分为" + yinyuan + ",实乃天作之合"); }
#Activity生命周期
* void onCreate()
* Activity已经被创建完毕,
* activity被创建的时候调用。 适合做界面的初始化操作。
* void onStart()
* Activity已经显示在屏幕,但没有得到焦点,
* activity界面用户可见。 适合更新界面。 继续播放视频
* void onResume()
* Activity得到焦点,可以与用户交互
* 获取焦点 按钮可以被点击
* void onPause()
* Activity失去焦点,无法再与用户交互,但依然可见
* 失去焦点 按钮可以看到,但是不可以被点击。游戏使用
* void onStop()
* Activity不可见,进入后台
* activity界面用户不可见。 界面不可见适合清理操作。暂停视频。视频播放器
* void onDestroy()
* Activity被销毁,
* activity被销毁的时候调用。 适合做扫尾的操作。数据保存的操作。短信内容的保存
* void onRestart()
* Activity从不可见变成可见时会执行此方法
* Activity生命周期使用场景
* Activity创建时需要初始化资源,销毁时需要释放资源;或者播放器应用,在界面进入后台时需要自动暂停
###完整生命周期(entire lifetime)
onCreate–>onStart–>onResume–>onPause–>onStop–>onDestory
###可视生命周期(visible lifetime)
onStart–>onResume–>onPause–>onStop
###前台生命周期(foreground lifetime)
onResume–>onPause
- opRestart()
- 在onPause(),onStop()时进程被杀死了,下面不会执行
#Activity的四种启动模式
##任务栈
* 什么是任务栈?
– 记录当前用户操作的行为的一种数据结构.(后进先出的数据结构)
– 最近打开的界面,先被关闭。
– 参考发送邮件的步骤 理解任务栈的概念。
– 每个应用会有一个Activity任务栈,存放已启动的Activity。一个应用程序默认是只有一个任务栈,特殊情况下singleinstance会有多个任务栈
##进程
android系统 ,应用程序退出和进程退出是两个不同的概念。
android系统为了让应用程序可以被快速的开启。所有的应用程序退出后,进程是不会退出的。’
只有系统的内存空间严重不足的时候,才会把进程给回收。
点击图标–>linux创建进程–>dalvik虚拟机–>读取清单文件,加载activity。
android理解应用程序退出: 任务栈清空了。
##线程
进程是操作系统分配内存空间的单位,每个进程的内存空间都是独立的。
线程是运行在进程里面。线程cpu执行的最小单位。如果进程挂了,线程也挂了。
##应用程序 application
android应用程序每个应用程序都是运行在自己的sandbox(沙箱)。
理解成一组activity,service,content priovder broadcastreceiver的组合。
##Activity的四种启动模式,修改任务栈的排列情况
- 1、standard 标准启动模式。一个activity默认就是标准的启动模式。
- 开启新的activity(可以开启自身),activity就会被创建出来,加入到任务栈的栈顶。
适用于绝大多数的应用场景。 - 不用在清单中进行配置
- 开启新的activity(可以开启自身),activity就会被创建出来,加入到任务栈的栈顶。
- 2、singleTop 单一顶部启动模式。
- 如果任务栈的栈顶存在这个要开启的activity,不会重新的创建activity,而是复用已经存在的activity。保证栈顶如果存在,不会重复创建。
- 在同一个任务栈里面可以有多个实例存在。
- 应用场景:浏览器的书签(浏览器添加到书签)singletop
- 清单配置
<activity android:launchMode="singleTop" android:name=".SecondActivity"> </activity>
- 3、singeTask 单一任务栈启动模式。,在当前任务栈里面只能有一个实例存在。
- 当开启activity的时候,就去检查在任务栈里面是否有实例已经存在,如果有实例存在就复用这个已经存在的activity,并且把这个activity上面的所有的别的activity都清空,复用这个已经存在的activity。
- 保证整个任务栈里面只有一个实例存在
- 应用场景:浏览器的activity
- 清单配置
<activity android:launchMode="singeTask" android:name=".SecondActivity"> </activity>
- 如果一个activity的创建需要占用大量的系统资源(cpu,内存)一般配置这个activity为singletask的启动模式。webkit内核 c代码
在什么时候使用singletask模式。
BrowserActivity 浏览器 开销(内存占用,cpu占用)非常大,singletask。保证在一个任务栈里面只有一个实例存在。
webkit 内核 页面。
很多东西需要初始化
html解析器
html渲染器
css 渲染器
javascript 执行引擎如果一个activity的资源开销非常大,建议使用singletask的启动模式。
浏览器的activity使用的就是singletask的启动模式。 - 4、singleInstance 单一实例启动模式。非常特殊, activity会运行在自己的任务栈里面,并且这个任务栈里面只有一个实例存在
- 类似于java中的单例模式,单态模式。在整个android手机操作系统里面只有一个activity的实例存在。
- singleinstance启动模式的activity会运行在自己单独的任务栈里面
- 如果你要保证一个activity在整个手机操作系统里面只有一个实例存在,使用singleInstance
- 应用场景: 电话拨打界面
- InCallScreen 通话的activity配置模式是singleinstance的。在整个手机操作系统里面只有他一个实例存在。
- 清单配置
<activity android:launchMode="singleInstance" android:name=".SecondActivity"> </activity>
##任务栈的细节
- 每个应用程序运行,系统都会分配一个新的任务栈。
- 问题:问系统里面有多少个任务栈存在?
- 有多少个应用程序正在运行(activity没有都被销y毁,回桌面),就有几个任务栈。
应该是就至少有几个 - 如果一个应用里面有一个singleinstance呢???
-
任务栈的id是一个int类型的整数,自增长的id。不关机的话由getTaskId()得到的进程id会不断增加
- 一启动,会给launcher,systemui两个任务栈
- 当只启动后台服务,没有启动画面,是不会分配任务栈的
##横竖屏切换的生命周期
* 默认情况下 ,横竖屏切换, 销毁当前的activity,重新创建一个新的activity
* 快捷键ctrl+F11
- 在一些特殊的应用程序常见下,比如游戏,不希望横竖屏切换activity被销毁重新创建
- 需求:禁用掉横竖屏切换的生命周期
- 横竖屏写死
android:screenOrientation="landscape" 横屏 android:screenOrientation="portrait" 竖屏
- 让系统的环境 不再去敏感横竖屏的切换。
android:configChanges="orientation|screenSize|keyboardHidden"
- 写死横竖屏示例:
<activity android:screenOrientation="portrait" android:configChanges="orientation|screenSize|keyboardHidden" android:name="com.itheima.lifecycle.MainActivity" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
#掌握开启activity获取返回值
###从A界面打开B界面, B界面关闭的时候,返回一个数据给A界面
步骤:
- 1, 用新方法startActivityForResult(intent, 0)替代startActivity(intent)去
启动目标activity并且获取返回值,- 在主页面用这个方法启动的目标Activity,当目标Activity销毁时,会触发主页面onActivityResult方法
- startActivityForResult()方法:
- 参数1:意图(启动新界面)
- 参数2:请求码(用来在触发启动onActivityResult方法时,做匹配用)
startActivityForResult(intent, 0);
public void click1(View v){
Intent intent = new Intent(this, ContactActivity.class);
//startActivity(intent);//用这个方法启动的Activity,当销毁时,会触发onActivityResult方法 startActivityForResult(intent, 10);
}
-
2.在新开启的界面里面实现设置数据的逻辑
- setResult()方法
- 参数1:结果码 返回给父页面,做匹配用
- 参数2:要返回的数据,放在意图中
Intent data = new Intent();
data.putExtra(“phone”, phone);
//设置一个结果数据,数据会返回给调用者
setResult(0, data);
finish();//关闭掉当前的activity,才会返回数据
- setResult()方法
-示例–当点击目标Activity中的ListView中任何一条目,触发设置数据的逻辑,销毁目标Activity
public class ContactActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_contact);
final String[] names = new String[]{
"白九日",
"莎九日",
"包九日",
};
ListView lv = (ListView) findViewById(R.id.lv);
lv.setAdapter(new ArrayAdapter<String>(this, R.layout.item_listview,
R.id.tv_name, names));
//给listview的条目设置点击侦听
lv.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Intent data = new Intent();
data.putExtra("name", names[position]);
//当此Activity销毁时,data就会被传递给上一个Activity
setResult(100, data);
//销毁当前Activity
finish();
}
});
}
}
-示例2–
public class MyActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
//指定Activity显示哪一个布局文件
setContentView(R.layout.activity_my);
//
final TextView tv_wife_name = (TextView) findViewById(R.id.tv_wife_name);
final TextView tv_wife_action = (TextView) findViewById(R.id.tv_wife_action);
tv_wife_name.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent data = new Intent();
data.putExtra("name", tv_wife_name.getText());
setResult(300, data);
finish();
}
});
tv_wife_action.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent data = new Intent();
data.putExtra("body", tv_wife_action.getText());
setResult(400, data);
finish();
}
});
}
}
- 3.在开启者activity里面实现方法(在主界面实现onActivityResult)
- onActivityResult()方法:
- 参数1:requestCode 请求码 区分请求来自于哪个按钮。
- 参数2:resultCode 结果码 区分请求来自于哪个结果。
- 参数3:data参数就是返回的结果数据。从里面把数据取出来。
onActivityResult(int requestCode, int resultCode, Intent data)
通过data获取返回的数据
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//通过请求码来判断数据来自哪个Activity
if(requestCode == 10){
String name = data.getStringExtra("name");
EditText et = (EditText) findViewById(R.id.et_name);
et.setText(name);
}
else if(requestCode == 20){
String name = data.getStringExtra("sms");
EditText et = (EditText) findViewById(R.id.et_body);
et.setText(name);
}
else if(requestCode == 30){
//通过结果码判断数据属于什么类型
if(resultCode == 300){
String name = data.getStringExtra("name");
EditText et = (EditText) findViewById(R.id.et_name);
et.setText(name);
}
else if(resultCode == 400){
String name = data.getStringExtra("body");
EditText et = (EditText) findViewById(R.id.et_body);
et.setText(name);
}
}
}
* 4.根据请求码和结果码确定业务逻辑