01. 菜单
创建菜单文件
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/menu_add" android:title="Add" /> <item android:id="@+id/menu_remove" android:title="Remove" /> </menu>
在 Activity 中进行添加和处理
/** * 创建自定义菜单 * * @param menu 系统指定的菜单对象 * @return true, 表示允许创建的菜单显示出来 */ @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu, menu);// 从资源中加载菜单 return true;// 允许菜单显示 } /** * 菜单 Item 的点击事件 * * @param item 菜单 Item * @return */ @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_add: ToastUtil.showShortToast(this, "Add"); break; case R.id.menu_remove: ToastUtil.showShortToast(this, "Remove"); break; } return true; }
02. Intent
显式 Intent
隐式 Intent
- action 每个 Intent 中只能指定一个 action
- category 每个 Intent 中可以指定多个 category
- data
data 详解
- android:scheme 用于指定数据的协议部分。
- android:host 用于指定数据的主机名部分。
- android:port 用于指定数据的端口部分。
- android:path 用于指定主机名和端口之后部分。
- android:mimeType 用于指定可处理的数据类型,允许使用通配符的方式进行指定。
注意:
android.intent.categore.DEFAULT
是一种默认的 category 在调用startActivity()
方法的时候会自动将这个 category 添加到 Intent 当中。- 只有
<action>
和<category>
中的内容同时能够匹配上 Intent 中指定的 action 和 category 时,活动才能响应该 Intent。 - 只有
<data>
标签中指定的内容和 Intent 中携带的 Data 完全一致是,当前活动才能够响应该 Intent。
启动浏览器
Intent browserIntent = new Intent(Intent.ACTION_VIEW); browserIntent.setData(Uri.parse("https://www.baidu.com")); startActivity(browserIntent);
启动拨号
Intent dialIntent = new Intent(Intent.ACTION_DIAL); dialIntent.setData(Uri.parse("tel:10086")); startActivity(dialIntent);
03. Activity 的生命周期
返回栈
其实 Android 是使用任务(Task)来管理活动的,一个任务就是一组存放在栈里的活动的集合,这个栈也被称作返回栈(Back Stack)。栈是一种后进先出的数据接口。
活动状态
- 运行状态
- 栈顶,可见,可交互
- 暂停状态
- 栈中,可见,不可交互
- 停止状态
- 栈中,不可见,不可交互
- 销毁状态
- 出栈
- 运行状态
生命周期函数
- onCreat()
- 初始化操作,加载布局,绑定事件等。
- onStart()
- 活动由不可见变为了可见。
- onResume()
- 活动准备好和用户进行交互。
- onPause()
- 这个方法在系统准备去启动或者恢复另一个活动的时候调用。我们通常会在这个方法中将一些消耗 CPU 的资源释放掉,以及保存一些关键数据,但这个方法的执行速度一定要快,不然会影响到新的栈顶活动的使用。
- onStop()
- 活动完全不可见。如果启动的新活动是一个对话框式的活动,那么
onPause()
执行onStop()
不执行。
- 活动完全不可见。如果启动的新活动是一个对话框式的活动,那么
- onDestroy()
- 活动被销毁之前调用。
- onRestart()
- 活动由停止状态变为运行状态之前调用。
- onCreat()
活动的生存期
- 完整生存期
- 可见生存期
- 前台生存期
04. 生命周期图
05. 活动被回收
场景:应用中有一个活动 A,用户在活动 A 的基础上启动了活动 B,活动 A 就进入了停止状态,这个时候由于系统内存不足,将活动 A 回收掉了,然后用户按下 Back 键返回活动 A,会出现什么情况?会正常显示活动 A 但不会执行活动 A 的 onRestart() 方法,而是会执行 onCreate() 方法将活动 A 重新创建一次。
问题:打个比方,活动 A 中有一个文本输入框,用户输入一段文字,然后启动了活动 B,这时候活动 A 被回收了,按下 Back 键返回活动 A,却发现输入的文字全部都没了。数据怎么存储?
生命周期回调:
// 启动活动 A JustDo23: RecoveryActivity ---> onCreate() JustDo23: RecoveryActivity ---> onStart() JustDo23: RecoveryActivity ---> onResume() // 在活动 A 的基础上启动活动 B JustDo23: RecoveryActivity ---> onPause() JustDo23: RecoveryActivity ---> onSaveInstanceState() JustDo23: RecoveryActivity ---> onStop() JustDo23: RecoveryActivity ---> onDestroy() // 按下 Back 键返回活动 A JustDo23: RecoveryActivity ---> onCreate() JustDo23: RecoveryActivity ---> tempData = Something you just typed JustDo23: RecoveryActivity ---> onStart() JustDo23: RecoveryActivity ---> onResume()
解决方法:Activity 中提供了一个 onSaveInstanceState() 方法,可以保证活动被回收之前一定会被调用。在活动的 onCreate() 方法中有一个对应的 Bundle 类型参数 saveInstanceState 从中获取保存的数据。
实现代码:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_recovery); if (savedInstanceState != null) {// 取出保存的数据 String tempData = savedInstanceState.getString("data_key"); LogUtils.e(simpleName + " ---> " + "tempData = " + tempData); } } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState);// 在销毁前进行的数据保存 String tempData = "Something you just typed"; outState.putString("data_key", tempData); }
测试方法
第一步,打开开发者选项;第二步,勾选不保留活动用户离开后即销毁每个活动。
测试发现
在测试中使用 EditText 测试 Activity 被系统回收,但发现返回之后 Activity 和 EditText 的确都是被重新创建了,但是 EditText 中输入的内容却仍然存在。其实是 View 有类似的保存数据的效果。
其他
06. 启动模式
- 四种启动模式
- standard
- singleTop
- singleTask
- singleInstance
- 指定为 singleInstance 模式的活动会启用一个新的返回栈来管理这个活动(其实如果 singTask 模式指定了不同的 taskAffinity,也会启动一个新的返回栈)。程序中有一个活动是允许其他程序调用的,则使用此模式。其他三种不能实现是因为每个应用都会有自己的返回栈,同一个活动在不同的返回栈中入栈时必须是创建了新的实例。
07. 活动的实践
获取 Activity 的 Task id
this.getTaskId();
获取 Activity 的名字
this.getClass().getSimpleName();
杀死当前进程
android.os.Process.killProcess(android.os.Process.myPid());// 删掉当前进程
活动管理集合
public class ActivityCollector { public static List<Activity> activityList = new ArrayList<>(); public static void addActivity(Activity activity) { activityList.add(activity); } public static void removeActivity(Activity activity) { activityList.remove(activity); } public static void finishAll() { for (Activity activity : activityList) { if (!activity.isFinishing()) { activity.finish(); } } activityList.clear(); android.os.Process.killProcess(android.os.Process.myPid());// 删掉当前进程 } }
启动活动
/** * 其他活动启动当前获取 * * @param context 上下文 * @param data1 传递数据 * @param data2 传递数据 */ public static void actionStart(Context context, String data1, String data2) { Intent intent = new Intent(context, StartActivity.class); intent.putExtra("param1", data1); intent.putExtra("param2", data2); context.startActivity(intent); }
08. 小结
- 关于向下兼容的 AppCompatActivity 需要学习。
- 关于栈和堆的相关知识需要学习总结。
- 弹出 Dialog 或者 PopupWindow 并不影响 Activity 的生命周期。
- 在开发者选项中的各个功能的使用方式。
- 和启动模式相关的有一个 onNewIntent(Intent intent) 方法需要注意。
- Activity 的 taskAffinity 属性。
- 随时随地退出程序。
- 启动活动的最佳写法。
- 退出程序的相关问题,如何真正退出程序,杀掉进程,最优做法是什么?