4. 车辆属性读取
任务说明
车载系统对应用生命周期有更严格的管控:车辆熄火、屏幕关闭或切换到其他车载服务时,系统可能随时回收后台资源。本案例实现一个最小可运行的Activity与Fragment生命周期管理示例,重点验证:Activity在配置变更(如车机屏幕旋转)时状态保留、Fragment在Activity重建后正确恢复,以及关键生命周期回调中资源的正确释放与重建。
环境依赖
- Android SDK API 26+(覆盖车载系统常见版本)
- AndroidX Fragment库(androidx.fragment:fragment:1.6.0+)
- 编译工具:Android Studio 或 Gradle命令行
核心实现
以下代码包含一个Activity和一个Fragment。Activity通过onSaveInstanceState保存计数器状态,在重建后恢复;Fragment在Activity重建时通过FragmentManager自动恢复,并在其生命周期回调中打印日志,便于在Logcat中观察调用顺序。
// MainActivity.java
package com.example.carlifecycle;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "CarLifecycle";
private static final String KEY_COUNT = "count";
private int count = 0;
private TextView tvCount;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvCount = findViewById(R.id.tv_count);
if (savedInstanceState != null) {
count = savedInstanceState.getInt(KEY_COUNT);
Log.d(TAG, "Activity onCreate - 恢复状态, count=" + count);
} else {
Log.d(TAG, "Activity onCreate - 首次创建");
}
tvCount.setText("计数: " + count);
// 添加Fragment(仅在首次创建时添加,避免重复)
if (savedInstanceState == null) {
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.fragment_container, new CarFragment(), "car_fragment");
ft.commit();
}
}
@Override
protected void onStart() {
super.onStart();
Log.d(TAG, "Activity onStart");
}
@Override
protected void onResume() {
super.onResume();
Log.d(TAG, "Activity onResume");
}
@Override
protected void onPause() {
super.onPause();
Log.d(TAG, "Activity onPause");
}
@Override
protected void onStop() {
super.onStop();
Log.d(TAG, "Activity onStop");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d(TAG, "Activity onDestroy");
}
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(KEY_COUNT, count);
Log.d(TAG, "Activity onSaveInstanceState - 保存 count=" + count);
}
// 模拟用户操作:点击按钮增加计数
public void incrementCount() {
count++;
if (tvCount != null) {
tvCount.setText("计数: " + count);
}
Log.d(TAG, "计数增加至: " + count);
}
}
// CarFragment.java
package com.example.carlifecycle;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
public class CarFragment extends Fragment {
private static final String TAG = "CarLifecycle";
@Override
public void onAttach(@NonNull android.content.Context context) {
super.onAttach(context);
Log.d(TAG, "Fragment onAttach");
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "Fragment onCreate");
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
Log.d(TAG, "Fragment onCreateView");
View view = inflater.inflate(R.layout.fragment_car, container, false);
Button btnIncrement = view.findViewById(R.id.btn_increment);
btnIncrement.setOnClickListener(v -> {
if (getActivity() instanceof MainActivity) {
((MainActivity) getActivity()).incrementCount();
}
});
return view;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Log.d(TAG, "Fragment onViewCreated");
}
@Override
public void onStart() {
super.onStart();
Log.d(TAG, "Fragment onStart");
}
@Override
public void onResume() {
super.onResume();
Log.d(TAG, "Fragment onResume");
}
@Override
public void onPause() {
super.onPause();
Log.d(TAG, "Fragment onPause");
}
@Override
public void onStop() {
super.onStop();
Log.d(TAG, "Fragment onStop");
}
@Override
public void onDestroyView() {
super.onDestroyView();
Log.d(TAG, "Fragment onDestroyView");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "Fragment onDestroy");
}
@Override
public void onDetach() {
super.onDetach();
Log.d(TAG, "Fragment onDetach");
}
}
<!-- res/layout/activity_main.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/tv_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="24sp"
android:text="计数: 0" />
<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<!-- res/layout/fragment_car.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<Button
android:id="@+id/btn_increment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="增加计数" />
</LinearLayout>
运行与验证
- 创建Android工程,包名设为
com.example.carlifecycle,将上述Java代码放入app/src/main/java/com/example/carlifecycle/,XML布局放入app/src/main/res/layout/。 - 在
app/build.gradle中确认依赖包含androidx.appcompat:appcompat:1.6.0和androidx.fragment:fragment:1.6.0。 - 连接车载模拟器或真机(API 26+),点击Run运行应用。
- 打开Logcat,过滤标签
CarLifecycle,观察生命周期日志。
通过条件
- 首次启动时,日志顺序为:Activity onCreate → onStart → onResume,Fragment onAttach → onCreate → onCreateView → onViewCreated → onStart → onResume。
- 点击“增加计数”按钮,界面计数递增,Logcat输出对应日志。
- 旋转屏幕(或模拟配置变更),Activity和Fragment均经历销毁与重建。Activity的
onSaveInstanceState被调用,重建后onCreate中恢复count值,界面显示旋转前的计数。 - Fragment在Activity重建后自动恢复,不会重复添加,且其视图正常显示。
- 按Home键或关闭屏幕(模拟车载熄屏),Activity依次回调onPause → onStop;重新回到应用时回调onRestart → onStart → onResume。
常见问题
- Fragment重复添加:Activity重建后若在
onCreate中无条件添加Fragment,会导致重复。本案例通过savedInstanceState == null判断避免。 - 状态丢失:车载系统可能因内存不足直接杀死后台Activity,此时
onSaveInstanceState仍会被调用,但恢复时机在用户重新导航回该Activity时。本案例的计数恢复逻辑覆盖此场景。 - 车载特殊场景:车辆熄火时系统可能直接调用
onStop而不经过onPause(取决于OEM实现),因此资源释放应放在onStop而非onPause中,本案例日志可帮助观察实际回调顺序。