当前位置: 首页 > news >正文

Android开发-屏幕变更事件

一、什么是屏幕变更事件?

当设备的配置(Configuration) 发生变化时,Android 系统会触发 Configuration Change 事件。

常见的配置变更类型

变更类型示例
orientation屏幕旋转(竖屏 ↔ 横屏)
screenLayout屏幕尺寸/密度变化(如折叠屏展开)
keyboardHidden软键盘弹出/隐藏
fontScale系统字体大小调整
locale系统语言切换
uiMode夜间模式开启/关闭

⚠️ 默认行为:系统会销毁并重建 Activity(调用 onDestroy()onCreate()),以便加载适配新配置的资源。

二、默认行为:Activity 重建

生命周期流程

Activity A (竖屏)↓ 用户旋转屏幕
onPause() → onStop() → onDestroy()↓ 系统重建
onCreate() → onStart() → onResume()→ Activity A (横屏)

问题与挑战

  1. 状态丢失onCreate() 中初始化的数据可能丢失。
  2. 性能损耗:重复执行 setContentView()、数据库查询、网络请求。
  3. 用户体验差:页面闪退或重新加载。

三、方案一:允许重建 + 正确保存状态

如果选择接受默认重建行为,必须确保关键数据不丢失。

1. 使用 onSaveInstanceState() 保存临时状态

public class MainActivity extends AppCompatActivity {private String userInput;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);EditText editText = findViewById(R.id.edit_text);// 恢复保存的状态if (savedInstanceState != null) {userInput = savedInstanceState.getString("USER_INPUT");editText.setText(userInput);}}@Overrideprotected void onSaveInstanceState(@NonNull Bundle outState) {super.onSaveInstanceState(outState);// 保存用户输入EditText editText = findViewById(R.id.edit_text);outState.putString("USER_INPUT", editText.getText().toString());}
}

适用场景:轻量级状态(如文本框内容、滚动位置)。
不适用:大数据、文件句柄、网络连接。

2. 使用 ViewModel 保留复杂数据

public class MainViewModel extends ViewModel {private MutableLiveData<List<String>> dataList = new MutableLiveData<>();public LiveData<List<String>> getDataList() {return dataList;}public void loadData() {// 模拟耗时加载new Handler().postDelayed(() -> {List<String> data = Arrays.asList("Item 1", "Item 2", "Item 3");dataList.setValue(data);}, 2000);}
}
// 在 Activity 中使用
viewModel = new ViewModelProvider(this).get(MainViewModel.class);
viewModel.getDataList().observe(this, list -> {// 更新 UI,即使 Activity 重建,数据依然存在adapter.submitList(list);
});

优势:生命周期独立于 Activity,配置变更时不销毁。

四、方案二:阻止重建 + 手动处理变更

通过在 AndroidManifest.xml 中声明 android:configChanges,可阻止系统自动重建 Activity。

1. 声明要自行处理的配置变更

<activityandroid:name=".MainActivity"android:exported="true"android:configChanges="orientation|screenSize|keyboardHidden"android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter>
</activity>

🔍 关键属性说明

  • orientation:屏幕方向变更(横/竖屏)
  • screenSize:屏幕尺寸变化(API 13+,常与 orientation 同时使用)
  • keyboardHidden:软键盘显示/隐藏

2. 重写 onConfigurationChanged() 方法

@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {super.onConfigurationChanged(newConfig);// 判断当前屏幕方向if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {Toast.makeText(this, "已切换到横屏", Toast.LENGTH_SHORT).show();// 动态调整 UIadjustForLandscape();} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {Toast.makeText(this, "已切换到竖屏", Toast.LENGTH_SHORT).show();adjustForPortrait();}
}

3. 动态调整 UI 示例

private void adjustForLandscape() {// 横屏下隐藏某些 ViewfindViewById(R.id.ad_banner).setVisibility(View.GONE);// 调整 RecyclerView 布局管理器RecyclerView recyclerView = findViewById(R.id.recycler_view);recyclerView.setLayoutManager(new GridLayoutManager(this, 2));
}private void adjustForPortrait() {// 竖屏下显示广告findViewById(R.id.ad_banner).setVisibility(View.VISIBLE);// 恢复线性布局RecyclerView recyclerView = findViewById(R.id.recycler_view);recyclerView.setLayoutManager(new LinearLayoutManager(this));
}

优点:避免 Activity 重建,提升性能。
缺点:需手动处理所有 UI 变化,代码复杂度增加。

五、为不同屏幕提供专属布局

最优雅的适配方式是使用 资源限定符(Resource Qualifiers),让系统自动加载合适的布局。

1. 创建横屏专用布局

res/
├── layout/
│   └── activity_main.xml          # 竖屏布局
└── layout-land/└── activity_main.xml          # 横屏布局

2. 横屏布局示例(layout-land/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="horizontal"><!-- 左侧列表 --><fragmentandroid:id="@+id/fragment_list"android:name="com.example.NewsListFragment"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1" /><!-- 右侧详情 --><FrameLayoutandroid:id="@+id/detail_container"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="2" /></LinearLayout>

优势:完全解耦,UI 设计自由度高,适合平板或大屏设备。

六、高级技巧与最佳实践

1. 监听软键盘弹出/隐藏

// 在 onConfigurationChanged 中判断
if (newConfig.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO) {// 软键盘弹出
} else if (newConfig.keyboardHidden == Configuration.KEYBOARDHIDDEN_YES) {// 软键盘隐藏
}

2. 折叠屏与多窗口支持

<!-- 支持多窗口 -->
<activityandroid:name=".MainActivity"android:resizeableActivity="true"android:supportsPictureInPicture="true"android:configChanges="orientation|screenSize|smallestScreenSize">
</activity>

3. 使用 Jetpack Compose 实现响应式 UI

@Composable
fun ResponsiveLayout() {val configuration = LocalConfiguration.currentval isLandscape = configuration.orientation == Configuration.ORIENTATION_LANDSCAPEif (isLandscape) {Row { /* 横屏布局 */ }} else {Column { /* 竖屏布局 */ }}
}

七、常见问题与避坑指南

  1. android:configChanges 不生效?
    确保同时声明 orientationscreenSize(API 13+)。

  2. 横屏布局未加载?
    检查文件夹命名是否正确(layout-land),且无拼写错误。

  3. ViewModel 数据在重建后丢失?
    确保使用 ViewModelProvider(this) 而非 ViewModelProvider(requireActivity())

  4. 动画在旋转后中断?
    将动画逻辑放在 ViewModel 或使用 onRetainNonConfigurationInstance()

八、结语

感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!

http://www.dtcms.com/a/414525.html

相关文章:

  • 十大咨询公司排行榜aso优化师主要是干嘛的
  • LeetCode第1346题 - 检查整数及其两倍数是否存在
  • 【Leetcode hot 100】207.课程表
  • 搜索引擎高级搜索技巧
  • 2.3 物理层设备 (答案见原书 P48)
  • 华为OBS obsutil使用
  • 租购同权七年之痒:政策善意如何变现?
  • 【Linux操作系统】基础开发工具
  • 老年ai模拟恋爱抖音快手微信小程序看广告流量主开源
  • 知名的网站制作公司需要多少钱企业宣传网站模板下载
  • 深圳横岗做网站的网站品牌形象设计怎么做
  • 社区网站推广方案百度百家号注册
  • 编程竞赛高频考点
  • Linux 程序使用 STDOUT 打印日志导致程序“假死”?一次线上 Bug 的深度排查与解决
  • (一)routeros命令笔记:开局篇
  • 网站推广模式一份完整的项目计划书
  • 基于STM32设计的智能安全头盔_299
  • ​VR应急安全学习机,提升应对自然灾害时自救互救的应急技能
  • app网站建设公司竞彩网站建设
  • pytorch基本运算-torch.normal()函数输出多维数据时,如何绘制正态分布函数图
  • OpenCV2-图像基本操作-阈值与平滑处理-形态学-梯度运算
  • 【开题答辩全过程】以 springboot+美食电子商城的设计与实现为例,包含答辩的问题和答案
  • MySQL所有关键字详细含义说明
  • MySQL表压缩:用CPU换I/O的秘密武器
  • 做外贸网站需要缴什么税重庆高端网站建设价格
  • java面试day5 | 消息中间件、RabbitMQ、kafka、高可用机制、死信队列、消息不丢失、重复消费
  • 时序数据库选型指南:如何为企业选择合适的时序数据库解决方案
  • 【iOS】alloc、init、new
  • 做网站的开发心得wordpress是不是一定要买服务器
  • AI觉醒:小白的大模型冒险记 第10章:故事续写竞技场 - 实战演练