Activity Review
参考资料
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
<activity
android: name="com.alex33.SecondActivity"
android: icon="@drawable/cat"
android: label="第二个Activity">
<intent-filter>
<action android:name="com.alex33.JumpToSecondActiviy"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
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的主入口
<intent-filter>
<action android:name = "android.intent.action.MAIN" />
<category android:name = "android.intent.category.LAUNCHER" />
</intent-filter>
使用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的一些技巧
锁定为竖屏
<activity android:name="com.alex33.MainActivity"
android:label="@string/app_name"
android:screenOrientation="portrait">
// 竖屏为portrait,横屏为landscape
</activity>
去除标题
requestWindowFeature(Window.FEATURE_NO_TITLE);
Android清单文件中MimeType的用途
Intent-Filter中的有一个mimeType。它的作用是告诉Android系统本Activity可以处理的文件的类型。如设置为 “text/plain”表示可以处理“.txt”文件。
<intent-filter>
<actionandroid:name="android.intent.action.VIEW" />
<categoryandroid:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/jpeg ">
</intent-filter>
这样就把当前程序注册为可以打开/查看jpeg类型的图片
当在文件管理器里点击任何jpeg文件, 系统都会试图去执行你的程序。
" image/jpeg "这一类型属于标准的MIME Type。
一个简单的隐式跳转并传递值的Demo
UI
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.goldinfo.sendmessage.MainActivity">
<ListView
android:id="@+id/ll"
android:layout_width="match_parent"
android:layout_height="match_parent"></ListView>
</RelativeLayout>
item
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="TextView"
android:id="@+id/textView"
android:textColor="#123897"
/>
代码实现
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<String> adapter = new ArrayAdapter<String>(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);
}
});
}
}