当前位置: 代码网 > it编程>App开发>Android > Android开发教程之屏幕变更事件

Android开发教程之屏幕变更事件

2025年09月28日 Android 我要评论
一、什么是屏幕变更事件?当设备的配置(configuration)发生变化时,android 系统会触发configuration change事件。常见的配置变更类型变更类型示例orientatio

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

当设备的配置(configuration) 发生变化时,android 系统会触发 configuration change 事件。

常见的配置变更类型

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

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

二、默认行为:activity 重建

生命周期流程

activity a (竖屏)
    ↓ 用户旋转屏幕
onpause() → onstop() → ondestroy()
    ↓ 系统重建
oncreate() → onstart() → onresume()
    → activity a (横屏)

问题与挑战

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

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

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

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

public class mainactivity extends appcompatactivity {
    private string userinput;

    @override
    protected 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);
        }
    }

    @override
    protected 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. 声明要自行处理的配置变更

<activity
    android: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();
        // 动态调整 ui
        adjustforlandscape();
    } else if (newconfig.orientation == configuration.orientation_portrait) {
        toast.maketext(this, "已切换到竖屏", toast.length_short).show();
        adjustforportrait();
    }
}

3. 动态调整 ui 示例

private void adjustforlandscape() {
    // 横屏下隐藏某些 view
    findviewbyid(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">

    <!-- 左侧列表 -->
    <fragment
        android:id="@+id/fragment_list"
        android:name="com.example.newslistfragment"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1" />

    <!-- 右侧详情 -->
    <framelayout
        android: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. 折叠屏与多窗口支持

<!-- 支持多窗口 -->
<activity
    android:name=".mainactivity"
    android:resizeableactivity="true"
    android:supportspictureinpicture="true"
    android:configchanges="orientation|screensize|smallestscreensize">
</activity>

3. 使用 jetpack compose 实现响应式 ui

@composable
fun responsivelayout() {
    val configuration = localconfiguration.current
    val islandscape = configuration.orientation == configuration.orientation_landscape

    if (islandscape) {
        row { /* 横屏布局 */ }
    } else {
        column { /* 竖屏布局 */ }
    }
}

七、常见问题与避坑指南

  • android:configchanges 不生效?确保同时声明 orientation 和 screensize(api 13+)。

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

  • viewmodel 数据在重建后丢失?确保使用 viewmodelprovider(this) 而非 viewmodelprovider(requireactivity())

  • 动画在旋转后中断?将动画逻辑放在 viewmodel 或使用 onretainnonconfigurationinstance()

八、结语

到此这篇关于android开发教程之屏幕变更事件的文章就介绍到这了,更多相关android屏幕变更事件内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com