Android Activity要点
Android Activity
1生命周期
(1)onCreate: 创建,进行Activity的一些初始化工作,比如使用setContentView加载布局,对一些控件和变量进行初始化等。此时Activity还在后台,不可见。
(2)onStart: 启动,Activity已经可见,但是还没出现在前台。在Activity的切换以及按Home键返回桌面再切回应用的过程中被多次调用。Bundle数据的恢复在onStart中进行更合适。
(3)onResume: 继续、重新开始,Activity已经出现在前台并且可见了,可以打开独占设备。
(4)onPause:pause暂停,要跳到另一个Activity或应用正常退出时执行。此时Activity在前台并可见,可以进行一些轻量级的工作。跳转Activity时当一个Activity执行完了onPause方法后另一个Activity才会启动。
(5)onStop:停止,Activity已经不可见,但还在内存中。可做一些资源的回收工作。
(6)onDestroy:毁灭,这个阶段Activity被销毁,不可见,可做释放资源释放及回收工作。
(7)onRestart:重新开始,从不可见切换回来时调用,Activity在这时可见。
2启动模式
启动模式launchMode:默认情况下,使用启动模式:standard。
standard(不复用,每次new)
singleTop(复用栈顶实例)
有相同的activity在前台于用户交互,则复用这个Activity,会调用Activity.onNewIntent()。
栈顶不是target Activity,则new一个。
对于新的Intent,要负责onCreate() 和 onNewIntent() 来控制使它适用于所有情况。
singleTask(复用栈内实例)
有相同的activity在前台于用户交互,则复用这个Activity,会调用Activity.onNewIntent()。
栈顶不是目标Activity,则清除此activty旧实例以上的所有activity。
启动实例的Intent的flag会被设置Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT
注意:会自动地破坏其他的activity,让该实例出现在栈顶。
场景1:入口Activity比较适用这种情况,因为MainActivity再返回就是退出应用。
场景2:与另一个应用合作,另一个应用拥有调用singleTask activity存在的任务
singleInstance
开辟一个只允许一个activity实例运行的task.
intent再次启动这个activity,task会被调到前台,其Activity.onNewIntent() 会被调用.
如果这个activity实例要启动一个新activity,那么新activity会在一个新task中运行。
3 MainActivity的声明
作为应用的入口Activity,需要设置intent-filter action为android.intent.action.MAIN,category为android.intent.category.LAUNCHER。
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
4. 详细条目
4.1 简述Activity
四大组件之一,一般一个用户交互界面对应一个activity
setContentView() ,// 要显示的布局
button.setOnclickLinstener{
// 对控件注册事件
}
activity 是Context的子类,同时实现了window.callback和keyevent.callback, 可以处理与窗体用户交互的事件。
常用的的有FragmentActivitiy,ListActivity , PreferenceActivity ,TabAcitivty等。
如果界面有共同的特点或者功能的时候,还会自己定义一个BaseActivity。
4.2 描述Activity生命周期
生命周期描述的是一个类从创建(new出来)到死亡(垃圾回收)的过程中会执行的方法。 在这个过程中,针对不同的生命阶段会调用不同的方法。
Activity从创建到销毁有多种状态,从一种状态到另一种状态时会激发相应的回调方法,这些回调方法包括:oncreate ondestroy onstop onstart onresume onpause。
其实这些方法都是两两对应的,onCreate创建与onDestroy销毁;
onStart可见与onStop不可见;onResume在前台(捕获焦点,可编辑)与onPause暂停。
onRestart方法 在Activity被onStop后,但是没有被onDestroy,再次启动此Activity时就调用onRestart(而不再调用onCreate)方法。
4.3 两个Activity之间跳转时必然会执行哪几个方法
在A里面激活B组件,A 会调用 onPause()方法;然后B 调用onCreate() ,onStart(), onResume() 。
如果B覆盖了窗体, A会调用onStop()方法。 如果B个透明的,或者是对话框的样式, A就不会调用onStop()方法。
4.4 横竖屏切换时候Activity的生命周期
跟清单文件里的配置有关系:
1、默认切屏首先销毁当前activity,然后重新加载,重新调用各个生命周期。
2、设置Activity的android:configChanges="orientation|keyboardHidden|screenSize"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法。
游戏开发中, 屏幕的朝向都是写死的,横竖屏切换的时候,如果有弹窗会被销毁。
4.5 如何将一个Activity设置成窗口的样式
清单文件里的配置样式android:theme="@android:style/Theme.Dialog"
4.6 你后台的Activity被系统回收怎么办?
如果后台的Activity由于某原因被系统回收了,如何在被系统回收之前保存当前状态?
除了在栈顶的activity,其他的都有可能在内存不足的时候被系统回收,一个activity越处于栈底,被回收的可能性越大.
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putLong("id",1234567890);
}
@Override
public void onCreate(Bundle savedInstanceState) {
//判断savedInstanceState如果不为空就取出来
int id = outState.getLong("id",0);
// todo 恢复界面
super.onCreate(savedInstanceState);
}
UI控件大多都实现了onSaveInstanceState()方法,当activity被摧毁和重建时, 指定过ID的UI控件会自动保存和恢复状态数据
备用方案:切换到后台的时把数据保存,在切换到前台时重新获取数据恢复界面
Activity 中 onSaveInstanceState(Bundle outState) 调用时机
home键最小化时或长按home键,屏幕旋转时, 开启新的Activity,在onPause后调用
Frament 中 onSaveInstanceState(Bundle outState) 调用时机
home键最小化时或长按home键 ,按下电源键,托管该Fragment的Activity 旋转时,托管该Fragment的Activity开启新的Activity时,在onPause后调用
Activity 中 onRestoreInstanceState(Bundle savedInstanceState) 调用时机
activity“确实”被销毁,在onStart()之后调用onRestoreInstanceState
没有设置android:configChanges=”orientation|screenSize”,在屏幕旋转时, activity“确实”被销毁,在onStart()之后调用
Fragment 中 setRetainInstance方法介绍
Fragment还可以通过在onCreate()中setRetainInstance(true)来保存自定义的对象数据。
设置后,Activity被系统销毁又重新创建时(如屏幕旋转),可以不完全销毁Fragment,成员变量值会保留,恢复时跳过onDestroy()和onCreate()
4.7 如何退出Activity?
退出activity 直接调用 finish () 方法 . //一般用户点击back键,就退出一个activity
退出activity 会执行 onDestroy()方法 .
4.8 如何安全退出已调用多个Activity的Application?
1. 递归退出
在打开新的Activity时使用startActivityForResult,然后自己加标志,在onActivityResult中处理关闭,在需要关闭的场景下递归关闭前面的所有Activity。
2. 记录打开的Activity,退出时逐个关闭
每打开一个Activity,就记录在application 全集的环境的list里。在需要退出时,关闭(finish)每一个Activity即可。
3. 发送特定广播(可处理多组件的情况):
在需要结束应用时,发送一个特定的广播。
需要关闭activity 注册接受广播的意图,收到广播后,关闭即可。
4. 通过 intent的flag FLAG_ACTIVITY_CLEAR_TOP来实现
启动多个Activity从A->B->C->D,如果需要从D直接退出程序。
Intent intent = new Intent();
intent.setClass(D.this, A.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();
开启A时将会清除该进程空间的所有Activity。
A在Manifest.xml配置启动模式android:launchMode="singleTop"
在A的onNewIntent中处理退出
Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if ((Intent.FLAG_ACTIVITY_CLEAR_TOP & intent.getFlags()) != 0) {
finish();
}
}
4.9 两个Activity之间怎么传递数据?
1. 基本数据类型通过Intent直接传递
intent.putExtra(name,value)
// 通过intentputExtra 方法 基本数据类型 都传递
intent.getStringExtra("key","value");
Bundle bundle= new Bundle();
bundle.putShort(key,value);
intent.putExtras(bundle)
2. 文件/网络资源通过Intent传递Uri
intent.setData(uri)
Uri uri = Uri.fromFile(file); //大图片的传递
3. 让对象实现 implements Serializable 接口把对象存放到文件上.
//通过 ObjectOutputStream 存储对象
File file = new File("c:\1.obj");
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
Student stu = new Student();
oos.writeObject(stu);
//从文件中把对象读出来
ObjectInputStreamois = new ObjectInputStream(arg0);
Student stu1 = (Student) ois.readObject();
4. 自定义的application类,全局里面存放对象。
4.10 同一个程序不同的Activity放在不同的Task任务栈
Singleinstance 运行在另外的单独的任务栈里面
激活一个新的activity时候, 给intent设置flag FLAG_ACTIVITY_NEW_TASK
这个被激活的activity就会在新的task栈里面。
Intentintent = new Intent(A.this,B.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
4.11 Activity启动模式的应用场景
singleTop 适合接收通知启动的内容显示页面
例如新闻客户端的新闻内容页面,不用每次收到10个新闻推送都打开一个新页面
singleTask适合作为程序入口点
例如浏览器的主界面。不管从多少个应用启动浏览器,只会启动主界面一次,其余情况都会走onNewIntent,并且会清空主界面上面的其他页面。
singleInstance适合需要与程序分离开的页面
一个实例在单独的Task中,完全不影响其他Activity。
例如:闹铃提醒界面,将闹铃提醒与闹铃设置分离。
不要用于中间页面 A -> B (singleInstance) -> C,完全退出后,再启动,首先打开的是B