Activity Review
参考资料
谷歌Activity参考文档
任务与返回栈, 官方文档的描述
Activity启动方式和Flag详解
Activity完全解析
Activity高级篇:Home键与Back键
Activity概述
一个应用通常由多个彼此松散联系的 Activity 组成。 一般会指定应用中的某个 Activity 为“主”Activity,即首次启动应用时呈现给用户的那个 Activity。 而且每个 Activity 均可启动另一个 Activity,以便执行不同的操作。 每次新 Activity 启动时,前一 Activity 便会停止,但系统会在堆栈(“返回栈”)中保留该 Activity。 当新 Activity 启动时,系统会将其推送到返回栈上,并取得用户焦点。 返回栈遵循基本的“后进先出”堆栈机制,因此,当用户完成当前 Activity 并按“返回”按钮时,系统会从堆栈中将其弹出(并销毁),然后恢复前一 Activity。
启动Activity
Intent intent = new Intent(this, SignInActivity.class);
startActivity(intent);
隐式意图
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
startActivity(intent);
Intent 对象的真正价值所在 — 您可以创建一个 Intent 对象,对您想执行的操作进行描述,系统会从其他应用启动相应的 Activity. <参考文档>
表述:
如果您想允许用户发送电子邮件,可以创建上面的实例 Intent
添加到 Intent 中的 EXTRA_EMAIL extra 是一个字符串数组,其中包含应将电子邮件发送到的电子邮件地址。 当电子邮件应用响应此 Intent 时,它会读取 extra 中提供的字符串数组,并将它们放入电子邮件撰写窗体的“收件人”字段。 在这种情况下,电子邮件应用的 Activity 启动,并且当用户完成操作时,您的 Activity 会恢复执行。
Manifest.xml
SecondActivity.java
Intent i = new Intent();
i.setAction("com.alex33.JumpToSecondActivity");
i.addCategory("android.intent.category.DEFAULT");
startActivity(intent);
通过隐式意图可以不报楼类文件的情况下, 调用一个Activity
Activity几种状态
Active(活动 | Active/Runing):当Activity位于栈顶时,它是可见,有焦点的前台Activity,可以用来响应用户的输入。
Paused(暂停 | Paused):一般情况,你的Activity可见但不具有焦点,例如 当前面的Activity是全透明或非透明的Activity时,下面的Activity就位于Paused状态。
Stopped(停止 | Stoped):当一个Activity彻底不可见时,就处于这个状态。此时Activity完全不可见,但在内存中仍旧保留该Activity的状态和成员信息。
Inactive(销毁 | Killed):当一个Activity被杀死时,就变成Inactive。Inactive Activity会从Activity栈中移除,如果重新显示需要重新启动。一般销毁由系统Dalvik控制。
Activity加载模式
在android里,有4种activity的启动模式,分别为:
standard: 标准模式,一调用startActivity()方法就会产生一个新的实例。
singleTop: 来了intent, 每次都创建新的实例,仅一个例外:当栈顶的activity 恰恰就是该activity的实例(即需要创建的实例)时,不再创建新实例。这解决了栈顶复用问题。
singleTask: 来了intent后,检查栈中是否存在该activity的实例,如果存在就把intent发送给它,否则就创建一个新的该activity的实例,放入一个新的task栈的栈底。肯定位于一个task的栈底,而且栈中只能有它一个该activity实例,但允许其他activity加入该栈。解决了在一个task中共享一个activity。
singleInstance: 这个跟singleTask基本上是一样,只有一个区别:在这个模式下的Activity实例所处的task中,只能有这个activity实例,不能有其他的实例。一旦该模式的activity的实例已经存在于某个栈中,任何应用在激活该activity时都会重用该栈中的实例,解决了多个task共享一个activity。
这些启动模式可以在功能清单文件AndroidManifest.xml中进行设置,中的launchMode属性。
Activity 生命周期
Activity跳转时的方法回调
生命周期回调的顺序经过明确定义,当两个 Activity 位于同一进程,并且由一个 Activity 启动另一个 Activity 时,其定义尤其明确。 以下是当 Activity A 启动 Activity B 时一系列操作的发生顺序:
- Activity A 的 onPause() 方法执行。
- Activity B 的 onCreate()、onStart() 和 onResume() 方法依次执行。(Activity B 现在具有用户焦点。)
- 然后,如果 Activity A 在屏幕上不再可见,则其 onStop() 方法执行。
您可以利用这种可预测的生命周期回调顺序管理从一个 Activity 到另一个 Activity 的信息转变。 例如,如果您必须在第一个 Activity 停止时向数据库写入数据,以便下一个 Activity 能够读取该数据,则应在 onPause() 而不是 onStop() 执行期间向数据库写入数据。
Manifest.xml的细节
清单文件中, intent过滤器有MAIN和LAUNCHER, 代表mainActivity的主入口
使用Bundle在Activity间传值
Bundle对象有如下方法:
存
putXxx(String key,Xxx data) : 向Bundle中放入int、String等各种类型的数据
putSerializable(String key,Serializable data) : 向Bundle中放入可序列化的对象
取
getXxx(String key):取出int、String等各种类型的数据
getSerializable(String key):取出可序列化的对象
当然我们还可以直接调用intent对象的putExtra(String key,Xxx data)方法存入数据,但其本质还是创建或使用了Bundle对象进行传值。
startActivityForResult的使用
A-Activity需要在B-Activtiy中执行一些数据操作,跳转至B-Activity后,B-Activity要将执行操作数据的结果返回给A-Activtiy,此时就需要使用 startActivityForResult()来启动B-Activity了。
使用的三个函数:
- startActivityForResult (Intent intent, Int requestCode)
- setResut (int resultCode, Intent intent)
- onActivityResult (int requestCode, int resultCode, Intent intent)
Step1.
在A中跳转的时候不是采用startActivity(intent) 这个方法,而是startActivityForResult(intent, Int requestCode)的形式,requestCode可以是大于等于0的任何值。
startActivityForResult(intent, 0);
Step2.
在A中重写onActivityResult方法,用来接收B回传的数据,因为传回来的resultCode不同而做差别处理。
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (resultCode) { //resultCode为回传的标记
case 20:
Bundle b=data.getExtras(); //data为B中回传的Intent
String str=b.getString("str1");//str即为回传的值
break;
default:
break;
}
}
Step3.
在B中采用setResult方法,并且之后要调用finish方法。
Intent intent=new Intent();
intent.putExtra("str1", str_bookname);
setResult(20, data);
finish(); //关闭掉这个Activity
关于A-B Activity切换, Home键, Back键的机制
任务与返回栈, 官方文档的描述
Activity 和任务的默认行为总结如下:
当 Activity A 启动 Activity B 时,Activity A 将会停止,但系统会保留其状态(例如,滚动位置和已输入表单中的文本)。如果用户在处于 Activity B 时按“返回”按钮,则 Activity A 将恢复其状态,继续执行。
用户通过按“主页”按钮离开任务时,当前 Activity 将停止且其任务会进入后台。 系统将保留任务中每个 Activity 的状态。如果用户稍后通过选择开始任务的启动器图标来恢复任务,则任务将出现在前台并恢复执行堆栈顶部的 Activity。
如果用户按“返回”按钮,则当前 Activity 会从堆栈弹出并被销毁。 堆栈中的前一个 Activity 恢复执行。销毁 Activity 时,系统不会保留该 Activity 的状态。
即使来自其他任务,Activity 也可以多次实例化。
Home键与Back键对Activity的生命周期影响
如果按下Back键,系统返回到桌面,并依次执行A:onPause -> A:onStop -> A:onDestroy。
如果按下Home键(非长按),系统返回到桌面,并依次执行A:onPause -> A:onStop。
由此可见,Back键和Home键主要区别在于是否会执行onDestroy。
Back键实现Home键效果
@Override
public void onBackPressed() {
Intent home = new Intent(Intent.ACTION_MAIN);
home.addCategory(Intent.CATEGORY_HOME);
startActivity(home);
}
或者
@Override
public void onBackPressed() {
moveTaskToBack(true);
}
moveTaskToBack()此方法直接将当前Activity所在的Task移到后台,同时保留activity顺序和状态。
关于finish()
- 将此Activity从Activity栈中移除。
- 调用了此Activity的onDestroy方法。
关于Activity的一些技巧
锁定为竖屏
// 竖屏为portrait,横屏为landscape
去除标题
requestWindowFeature(Window.FEATURE_NO_TITLE);
Android清单文件中MimeType的用途
Intent-Filter中的有一个mimeType。它的作用是告诉Android系统本Activity可以处理的文件的类型。如设置为 “text/plain”表示可以处理“.txt”文件。
这样就把当前程序注册为可以打开/查看jpeg类型的图片
当在文件管理器里点击任何jpeg文件, 系统都会试图去执行你的程序。
" image/jpeg "这一类型属于标准的MIME Type。
一个简单的隐式跳转并传递值的Demo
UI
activity_main.xml
item
代码实现
MainActivity
public class MainActivity extends AppCompatActivity {
private ListView lv;
private String[] msgs = {"天气太热了!买了个凉席,一睡变电热毯了!遇到个陌生人,相视一笑,变熟了!桌子太烫,麻将刚码好,嘿,居然糊了!",
"工作是枯燥的,赚钱是辛苦的,理想却是远大的,等咱有了钱,喝豆浆吃油条,想沾白糖沾白糖,豆浆买两碗,喝一碗,倒一碗!",
"给你点阳光你就灿烂,给你点洪水你就泛滥。破锅自有破锅盖,丑鬼自有丑女爱,只要情深意似海,麻子也能放光彩!",
"鸟儿,鸟儿,喳喳叫。清风,清风,去烦恼。祝福,祝福要趁早。短信,短信,恰恰好。朋友,朋友,看到短信笑一笑!",
"武当派,少林派,不如吃个苹果派;日月教,全真教,不如睡个大懒觉;降龙掌,销魂掌,不如养盆仙人掌;总之,你好我好大家好",
"我的问候,就是那冰激凌,融在你嘴里,甜在你胃里,爽在你心里。愿你把高温击退,把快乐放飞,生活有滋有味,笑容天天都美!",
"送你西瓜,爽口爽心顶呱呱;送你电扇,吹走烦躁发发汗;送你清凉油,神清气爽争上游;送你清心茶,伴你天天乐开花!",
"看事业线,你正走在成功路上;看生命线,你定会健康长寿;看感情线,你桃花运正旺。我的祝福三线合一,愿你快乐无比!",
"送你五万块,一万健康,一万快乐,一万平安,一万好运,一万幸福,一共五万块红砖。嘿嘿,自己建造个美好城堡吧!",
"好好活,慢慢过,一年更比一年乐;不要攀,不要比,不要自己气自己;少吃盐,多吃醋,少打麻将多散步。愿你:天天闲里忙着乐!"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lv = (ListView) findViewById(R.id.ll);
ArrayAdapter adapter = new ArrayAdapter(getApplicationContext(), R.layout.item, msgs);
lv.setAdapter(adapter);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView> parent, View view, int position, long id) {
//去除点击条目的数据
String content = msgs[position];
//使用隐式意图 跳转到短信页面
Intent intent = new Intent();
intent.setAction("android.intent.action.SEND");
intent.addCategory("android.intent.category.DEFAULT");
intent.setType("text/plain");
//key值需要到android源码中找
intent.putExtra("sms_body",content);
//开启Activity
startActivity(intent);
}
});
}
}