4、车机应用基础:Activity生命周期、Intent与IntentFilter、布局文件基础、AndroidManifest.xml详解
各位同学,欢迎来到第四章。这一章可以说是车机应用开发的「地基」。你想想看,一个车机应用从启动到关闭,系统是怎么管理它的?不同页面之间怎么跳转?界面长什么样又由谁说了算?
嗯,这些问题,我们今天一次性讲清楚。我个人习惯把这一章叫做「车机应用的骨架与血脉」——骨架是布局和清单文件,血脉就是Activity和Intent。
4.1 Activity生命周期:车机应用的「生老病死」
Activity是什么?说白了,它就是车机屏幕上的一扇「窗口」。你看到的导航界面、音乐播放界面,背后都是一个Activity在撑着。
但系统资源是有限的,尤其是车机,内存比手机还紧张。所以系统会随时「回收」那些看不见的Activity。这就引出了生命周期——系统管理Activity的一套规则。
4.1.1 七个核心回调方法
我直接给你列出来,这是面试必考,也是开发必用的:
| 回调方法 | 触发时机 | 典型用途 |
|---|---|---|
| onCreate() | Activity第一次创建 | 初始化布局、绑定数据、恢复状态 |
| onStart() | Activity即将可见 | 开始动画、注册广播 |
| onResume() | Activity获得焦点,可交互 | 启动传感器、恢复音乐播放 |
| onPause() | Activity失去焦点,但部分可见 | 保存草稿、暂停动画 |
| onStop() | Activity完全不可见 | 释放资源、停止定位 |
| onDestroy() | Activity被销毁 | 清理内存、解绑服务 |
| onRestart() | Activity从停止状态重新启动 | 重新加载数据 |
车机场景特别提醒:车机不像手机,用户可能随时切换应用(比如导航切到音乐),也可能因为倒车影像突然抢占屏幕。所以onPause和onStop里的逻辑一定要轻量,别做耗时操作。
4.1.2 生命周期流转的三种典型路径
我画个简单的流程给你看:
- 完整启动:onCreate → onStart → onResume。这是最正常的路径。
- 按Home键/被覆盖:onPause → onStop。再回来时走onRestart → onStart → onResume。
- 按返回键:onPause → onStop → onDestroy。彻底拜拜。
我的经验:我曾经在车机项目里犯过一个低级错误——在onStop里做了网络请求,结果用户切到倒车影像再切回来,界面卡死了。后来才明白,onStop里只适合做「保存状态」这种轻活,重活请交给Service或者协程。
4.2 Intent与IntentFilter:车机应用的「通信员」
Activity之间怎么跳转?数据怎么传递?靠的就是Intent。我把它比作「信使」——它带着你的请求和数据,去找对应的组件。
4.2.1 显式Intent vs 隐式Intent
这两种方式,你都得掌握:
- 显式Intent:直接指定目标组件的包名和类名。比如从MainActivity跳到MusicActivity。简单粗暴,自己人用。
- 隐式Intent:不指定具体组件,而是声明一个「动作」。比如你想打开一个网页,系统会找到能处理这个动作的浏览器。车机里常用在「分享」或「导航」场景。
代码示例:
// 显式Intent:跳转到音乐播放界面
Intent intent = new Intent(this, MusicActivity.class);
intent.putExtra("song_id", "12345");
startActivity(intent);
// 隐式Intent:打开导航
Intent mapIntent = new Intent(Intent.ACTION_VIEW);
mapIntent.setData(Uri.parse("geo:39.9042,116.4074"));
startActivity(mapIntent);
4.2.2 IntentFilter:告诉系统「我能做什么」
隐式Intent能生效,全靠IntentFilter。它在AndroidManifest.xml里声明,告诉系统:我这个Activity能处理哪些动作。
举个例子,你的车机音乐应用想响应「播放音乐」这个系统广播:
<activity android:name=".MusicPlayerActivity">
<intent-filter>
<action android:name="com.example.action.PLAY_MUSIC" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
避坑指南:我曾经在车机项目里遇到一个bug——音乐应用死活收不到系统发来的「播放」指令。查了半天,发现是IntentFilter里忘了加android.intent.category.DEFAULT。记住,startActivity()默认会带上这个category,你不声明,系统就匹配不上。
4.3 布局文件基础:车机界面的「施工图纸」
车机屏幕和手机不一样。手机竖屏多,车机横屏多。而且车机屏幕尺寸五花八门——7寸、10寸、12.3寸都有。所以布局文件怎么写,直接影响用户体验。
4.3.1 五大常用布局
| 布局名称 | 特点 | 车机适用场景 |
|---|---|---|
| LinearLayout | 线性排列,水平或垂直 | 设置菜单、列表项 |
| RelativeLayout | 相对定位,灵活 | 复杂仪表盘布局 |
| FrameLayout | 层叠显示,后添加的在上层 | 弹窗、悬浮按钮 |
| ConstraintLayout | 约束布局,性能好,适配强 | 推荐用于所有车机界面 |
| GridLayout | 网格排列 | 应用抽屉、快捷功能 |
我的建议:车机开发,优先用ConstraintLayout。为什么?因为它能减少布局嵌套,提升渲染性能。车机硬件普遍比手机弱,嵌套多了容易掉帧。我见过一个项目,一个界面嵌套了7层LinearLayout,结果启动卡了2秒——后来全改成ConstraintLayout,瞬间流畅。
4.3.2 一个简单的车机布局示例
假设我们要做一个音乐播放界面,顶部是歌曲信息,中间是进度条,底部是控制按钮:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- 歌曲名称 -->
<TextView
android:id="@+id/tv_song_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="蓝莲花"
android:textSize="24sp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="40dp"/>
<!-- 进度条 -->
<SeekBar
android:id="@+id/seek_bar"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/tv_song_name"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:layout_marginTop="30dp"/>
<!-- 播放/暂停按钮 -->
<ImageButton
android:id="@+id/btn_play"
android:layout_width="60dp"
android:layout_height="60dp"
android:src="@drawable/ic_play"
app:layout_constraintTop_toBottomOf="@id/seek_bar"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="30dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
4.4 AndroidManifest.xml详解:车机应用的「身份证」
每个Android应用根目录下都有一个AndroidManifest.xml。它告诉系统:你是谁?你能做什么?你需要什么权限?
我把它比作「身份证+简历」——系统通过它认识你的应用。
4.4.1 核心配置项
- package:应用的唯一标识,比如com.example.carplayer。不能重复。
- application:应用级别的配置,包括图标、主题、是否可调试等。
- activity:声明每一个Activity。注意,不声明就无法启动。
- intent-filter:前面讲过了,声明Activity能响应的隐式意图。
- uses-permission:声明应用需要的权限。车机里常用的是定位、网络、读取存储。
一个典型的车机应用清单文件:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.carmusic">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="车机音乐"
android:theme="@style/Theme.CarMusic">
<activity android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".MusicPlayerActivity"
android:exported="false" />
</application>
</manifest>
避坑指南:我曾经在车机项目里遇到一个诡异问题——应用安装后,点击图标没反应。查了半天,发现是MainActivity的intent-filter里漏写了android.intent.category.LAUNCHER。没有这个,系统就不知道哪个Activity是入口。嗯,这种低级错误,犯一次就记住了。
4.5 本章小结
这一章的内容,说白了就是车机应用的「骨架」和「血脉」:
- Activity生命周期:掌握七个回调,尤其注意车机场景下的onPause和onStop。
- Intent与IntentFilter:显式用于内部跳转,隐式用于跨应用通信。IntentFilter别忘了加DEFAULT。
- 布局文件:优先用ConstraintLayout,减少嵌套,提升性能。
- AndroidManifest.xml:应用的身份证,所有组件和权限都要在这里声明。
下一章,我们会深入车机特有的「多屏交互」和「车载服务」——那才是车机开发真正有意思的地方。到时候见。
课后练习:试着写一个车机音乐播放器的雏形,包含两个Activity:主界面和播放界面。用显式Intent传递歌曲ID,用隐式Intent响应系统「播放音乐」的广播。布局用ConstraintLayout实现。
公众号:蓝海资料掘金营,微信deep3321