大屏幕菜谱

Android 提供了打造五星级大屏幕应用所需的一切要素。本菜谱中的食谱精选并组合了各种优质要素,以解决具体的开发问题。每个食谱都包含最佳实践、高质量代码示例和分步说明,帮助您成为大屏幕应用顶级开发者。

星级评定

食谱的星级评定基于其与大屏幕应用质量指南的符合程度。

Five-star rating 符合1级标准,大屏幕差异化
Four-star rating 符合2级标准,大屏幕优化
Three-star rating 符合3级标准,大屏幕就绪
Two-star rating 提供一些大屏幕功能,但未达到大屏幕应用质量指南的要求
One-star rating 满足特定用例的需求,但无法正确支持大屏幕

Chromebook相机支持

Three-star rating

让Chromebook用户在Google Play上注意到您的应用。

如果您的相机应用只能使用基本相机功能,请不要让应用商店阻止Chromebook用户安装该应用,仅仅是因为您无意中指定了高端手机上才有的高级相机功能。

Chromebook内置前置(面向用户)摄像头,非常适合视频会议、快照和其他应用。但并非所有Chromebook都配有后置(面向世界)摄像头,而且大多数Chromebook的前置摄像头都不支持自动对焦或闪光灯。

最佳实践

多功能相机应用支持所有设备,无论其相机配置如何——配备前置摄像头、后置摄像头或通过USB连接的外部摄像头的设备。

为确保应用商店让您的应用可供尽可能多的设备使用,请务必声明您的应用使用的所有相机功能,并明确指出这些功能是否必不可少。

要素

  • CAMERA权限:允许您的应用访问设备的摄像头
  • <uses-feature>清单元素:告知应用商店您的应用使用的功能
  • required属性:指示应用商店您的应用是否可以在没有指定功能的情况下运行

步骤

总结

声明CAMERA权限。声明提供基本相机支持的相机功能。指定每个功能是否必不可少。

1. 声明CAMERA权限

将以下权限添加到应用清单

<uses-permission android:name="android.permission.CAMERA" />
2. 声明基本相机功能

将以下功能添加到应用清单

<uses-feature android:name="android.hardware.camera.any" android:required="false" />
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
<uses-feature android:name="android.hardware.camera.flash" android:required="false" />
3. 指定每个功能是否必不可少

对于android.hardware.camera.any功能,设置android:required="false",以允许任何类型的内置或外部摄像头(或根本没有摄像头)的设备访问您的应用。

对于其他功能,请设置android:required="false",以确保没有后置摄像头、自动对焦或闪光灯等设备(例如 Chromebook)也可以在应用商店访问您的应用。

结果

Chromebook 用户可以从 Google Play 和其他应用商店下载并安装您的应用。并且具有全功能摄像头支持的设备(例如手机)也不会受到其摄像头功能的限制。

通过明确设置您的应用支持的摄像头功能并指定您的应用所需的功能,您可以使您的应用尽可能多地适用于各种设备。

其他资源

更多信息,请参阅 摄像头硬件功能 中的 <uses-feature> 文档。

应用方向在手机上受限,但在大型屏幕设备上不受限

Two-star rating

您的应用在手机上竖屏模式下运行良好,因此您已将其限制为仅限竖屏模式。但是您发现有机会在横向的大屏幕上做更多的事情。

您如何同时做到这两点——在小屏幕上将应用限制为竖屏方向,但在大型屏幕上启用横屏方向呢?

最佳实践

最佳应用会尊重用户的偏好,例如设备方向。

大屏幕应用质量 指南建议应用支持所有设备配置,包括纵向和横向方向、多窗口模式以及可折叠设备的折叠和展开状态。应用应针对不同的配置优化布局和用户界面,并且应用应在配置更改期间保存和恢复状态。

此方法是一种临时措施——少量的大屏幕支持。在您可以改进应用以完全支持所有设备配置之前,可以使用此方法。

要素

步骤

总结

在应用清单中启用应用默认处理方向更改。在运行时,确定应用窗口大小。如果应用窗口较小,则通过覆盖清单方向设置来限制应用的方向。

1. 在应用清单中指定方向设置

您可以避免声明应用清单的 screenOrientation 元素(在这种情况下,方向默认为 unspecified),或者将屏幕方向设置为 fullUser。如果用户未锁定基于传感器的旋转,则您的应用将支持所有设备方向。

<activity
    android:name=".MyActivity"
    android:screenOrientation="fullUser">

使用 unspecifiedfullUser 之间的区别很细微但很重要。如果您不声明 screenOrientation 值,系统将选择方向,并且系统用于定义方向的策略可能因设备而异。另一方面,指定 fullUser 更贴近用户为设备定义的行为:如果用户已锁定基于传感器的旋转,则应用将遵循用户偏好;否则,系统将允许所有四种可能的屏幕方向(纵向、横向、反向纵向或反向横向)。请参阅 android:screenOrientation

2. 确定屏幕大小

将清单设置为支持所有用户允许的方向后,您可以根据屏幕大小以编程方式指定应用方向。

Jetpack WindowManager 库添加到模块的 build.gradlebuild.gradle.kts 文件中

Kotlin

implementation("androidx.window:window:version")
implementation("androidx.window:window-core:version")

Groovy

implementation 'androidx.window:window:version'
implementation 'androidx.window:window-core:version'

使用 Jetpack WindowManager WindowMetricsCalculator#computeMaximumWindowMetrics() 方法获取设备屏幕大小作为 WindowMetrics 对象。可以将窗口指标与窗口大小类进行比较,以确定何时限制方向。

窗口大小类 提供了小屏幕和大屏幕之间的断点。

使用 WindowWidthSizeClass#COMPACTWindowHeightSizeClass#COMPACT 断点来确定屏幕大小

Kotlin

/** Determines whether the device has a compact screen. **/
fun compactScreen() : Boolean {
    val metrics = WindowMetricsCalculator.getOrCreate().computeMaximumWindowMetrics(this)
    val width = metrics.bounds.width()
    val height = metrics.bounds.height()
    val density = resources.displayMetrics.density
    val windowSizeClass = WindowSizeClass.compute(width/density, height/density)

    return windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.COMPACT ||
        windowSizeClass.windowHeightSizeClass == WindowHeightSizeClass.COMPACT
}

Java

/** Determines whether the device has a compact screen. **/
private boolean compactScreen() {
    WindowMetrics metrics = WindowMetricsCalculator.getOrCreate().computeMaximumWindowMetrics(this);
    int width = metrics.getBounds().width();
    int height = metrics.getBounds().height();
    float density = getResources().getDisplayMetrics().density;
    WindowSizeClass windowSizeClass = WindowSizeClass.compute(width/density, height/density);
    return windowSizeClass.getWindowWidthSizeClass() == WindowWidthSizeClass.COMPACT ||
                windowSizeClass.getWindowHeightSizeClass() == WindowHeightSizeClass.COMPACT;
}
    注意
  • 以上示例实现为活动的 方法;因此,活动在 computeMaximumWindowMetrics() 的参数中被取消引用为 this
  • 使用 computeMaximumWindowMetrics() 方法而不是 computeCurrentWindowMetrics() 方法,因为应用可以在多窗口模式下启动,这会忽略屏幕方向设置。除非应用窗口是整个设备屏幕,否则确定应用窗口大小并覆盖方向设置是没有意义的。

有关声明依赖项以使 computeMaximumWindowMetrics() 方法在您的应用中可用的说明,请参阅 WindowManager

3. 覆盖应用清单设置

确定设备具有紧凑型屏幕大小后,您可以调用 Activity#setRequestedOrientation() 来覆盖清单的 screenOrientation 设置

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    requestedOrientation = if (compactScreen())
        ActivityInfo.SCREEN_ORIENTATION_PORTRAIT else
        ActivityInfo.SCREEN_ORIENTATION_FULL_USER
    ...
    // Replace with a known container that you can safely add a
    // view to where the view won't affect the layout and the view
    // won't be replaced.
    val container: ViewGroup = binding.container

    // Add a utility view to the container to hook into
    // View.onConfigurationChanged. This is required for all
    // activities, even those that don't handle configuration
    // changes. You can't use Activity.onConfigurationChanged,
    // since there are situations where that won't be called when
    // the configuration changes. View.onConfigurationChanged is
    // called in those scenarios.
    container.addView(object : View(this) {
        override fun onConfigurationChanged(newConfig: Configuration?) {
            super.onConfigurationChanged(newConfig)
            requestedOrientation = if (compactScreen())
                ActivityInfo.SCREEN_ORIENTATION_PORTRAIT else
                ActivityInfo.SCREEN_ORIENTATION_FULL_USER
        }
    })
}

Java

@Override
protected void onCreate(Bundle savedInstance) {
    super.onCreate(savedInstanceState);
    if (compactScreen()) {
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    } else {
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_USER);
    }
    ...
    // Replace with a known container that you can safely add a
    // view to where the view won't affect the layout and the view
    // won't be replaced.
    ViewGroup container = binding.container;

    // Add a utility view to the container to hook into
    // View.onConfigurationChanged. This is required for all
    // activities, even those that don't handle configuration
    // changes. You can't use Activity.onConfigurationChanged,
    // since there are situations where that won't be called when
    // the configuration changes. View.onConfigurationChanged is
    // called in those scenarios.
    container.addView(new View(this) {
        @Override
        protected void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
            if (compactScreen()) {
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            } else {
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_USER);
            }
        }
    });
}

通过将逻辑添加到 onCreate()View.onConfigurationChanged() 方法,您可以获取最大窗口指标并在活动调整大小或在显示屏之间移动时(例如设备旋转后或可折叠设备折叠或展开后)覆盖方向设置。有关配置更改发生的时间以及它们何时导致活动重新创建的更多信息,请参阅 处理配置更改

结果

现在,无论设备如何旋转,您的应用都应保持在小屏幕上的纵向方向。在大屏幕上,应用应支持横向和纵向方向。

其他资源

有关帮助您将应用升级以始终支持所有设备配置的信息,请参阅以下内容

使用外部键盘空格键暂停和恢复媒体播放

Four-star rating

大屏幕优化包括处理外部键盘输入的能力,例如响应按下空格键来暂停或恢复视频和其他媒体的播放。这对于平板电脑(通常连接到外部键盘)和 Chromebook(通常带有外部键盘,但也可以在平板电脑模式下使用)尤其有用。

当媒体是窗口的唯一元素(例如全屏视频播放)时,请在活动级别或在 Jetpack Compose 中在屏幕级别响应按键事件。

最佳实践

每当您的应用播放媒体文件时,用户都应该能够通过按下物理键盘上的空格键来暂停和恢复播放。

要素

Compose

  • onPreviewKeyEventModifier,当组件(或其子组件之一)获得焦点时,使组件能够拦截硬件按键事件。
  • onKeyEvent:与 onPreviewKeyEvent 类似,此 Modifier 使组件能够在它(或其子组件之一)获得焦点时拦截硬件按键事件。

视图

  • onKeyUp():当按键释放且未由活动中的视图处理时调用。

步骤

总结

基于视图的应用和基于 Jetpack Compose 的应用以类似的方式响应键盘按键:应用必须侦听按键事件、过滤事件并响应选定的按键,例如空格键。

1. 侦听键盘事件

视图

在应用中的活动中,覆盖 onKeyUp() 方法

Kotlin

override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean {
    ...
}

Java

@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
    ...
}

每次释放按下的键时都会调用此方法,因此它每次按键都会精确地触发一次。

Compose

使用 Jetpack Compose,您可以在管理按键的屏幕中利用 onPreviewKeyEventonKeyEvent 修饰符

Column(modifier = Modifier.onPreviewKeyEvent { event ->
    if (event.type == KeyEventType.KeyUp) {
        ...
    }
    ...
})

Column(modifier = Modifier.onKeyEvent { event ->
    if (event.type == KeyEventType.KeyUp) {
        ...
    }
    ...
})

2. 过滤空格键按下

onKeyUp() 方法或 Compose onPreviewKeyEventonKeyEvent 修饰符方法内,过滤 KeyEvent.KEYCODE_SPACE 以将正确的事件发送到您的媒体组件

视图

Kotlin

if (keyCode == KeyEvent.KEYCODE_SPACE) {
    togglePlayback()
    return true
}
return false

Java

if (keyCode == KeyEvent.KEYCODE_SPACE) {
    togglePlayback();
    return true;
}
return false;

Compose

Column(modifier = Modifier.onPreviewKeyEvent { event ->
    if (event.type == KeyEventType.KeyUp && event.key == Key.Spacebar) {
        ...
    }
    ...
})

Column(modifier = Modifier.onKeyEvent { event ->
    if (event.type == KeyEventType.KeyUp && event.key == Key.Spacebar) {
        ...
    }
    ...
})

结果

现在,您的应用可以响应空格键按下以暂停和恢复视频或其他媒体。

其他资源

要了解有关键盘事件以及如何管理键盘事件的更多信息,请参阅处理键盘输入

触笔掌拒功能

Five-star rating

触笔在大型屏幕上可以成为一款高效且极具创造性的工具。但是,当用户使用触笔在应用上绘图、书写或进行交互时,他们有时会用手掌触摸屏幕。触摸事件可能会在系统识别并将其作为意外手掌触摸而忽略之前就报告给您的应用。

最佳实践

您的应用必须识别并忽略无关的触摸事件。Android 通过分派一个MotionEvent对象来取消手掌触摸。检查该对象是否存在ACTION_CANCELACTION_POINTER_UP以及FLAG_CANCELED,以确定是否应拒绝由手掌触摸引起的姿态。

要素

  • MotionEvent:表示触摸和移动事件。包含确定是否应忽略事件所需的信息。
  • OnTouchListener#onTouch():接收MotionEvent对象。
  • MotionEvent#getActionMasked():返回与移动事件关联的操作。
  • ACTION_CANCELMotionEvent常量,指示应撤消手势。
  • ACTION_POINTER_UPMotionEvent常量,指示除第一个指针之外的其他指针已抬起(即已松开与设备屏幕的接触)。
  • FLAG_CANCELEDMotionEvent常量,指示抬起的指针导致了意外的触摸事件。在 Android 13(API 级别 33)及更高版本中添加到ACTION_POINTER_UPACTION_CANCEL事件。

步骤

总结

检查分派到您的应用的MotionEvent对象。使用MotionEvent API 来确定事件特征。

  • 单指针事件 — 检查ACTION_CANCEL。在 Android 13 及更高版本上,也检查FLAG_CANCELED
  • 多指针事件 — 在 Android 13 及更高版本上,检查ACTION_POINTER_UPFLAG_CANCELED

响应ACTION_CANCELACTION_POINTER_UP/FLAG_CANCELED事件。

1. 获取运动事件对象

向您的应用添加OnTouchListener

Kotlin

val myView = findViewById<View>(R.id.myView).apply {
    setOnTouchListener { view, event ->
        // Process motion event.
    }
}

Java

View myView = findViewById(R.id.myView);
myView.setOnTouchListener( (view, event) -> {
    // Process motion event.
});
2. 确定事件操作和标志

检查ACTION_CANCEL,它指示所有 API 级别上的单指针事件。在 Android 13 及更高版本上,检查ACTION_POINTER_UP是否存在FLAG_CANCELED

Kotlin

val myView = findViewById<View>(R.id.myView).apply {
    setOnTouchListener { view, event ->
        when (event.actionMasked) {
            MotionEvent.ACTION_CANCEL -> {
                //Process canceled single-pointer motion event for all SDK versions.
            }
            MotionEvent.ACTION_POINTER_UP -> {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
                   (event.flags and MotionEvent.FLAG_CANCELED) == MotionEvent.FLAG_CANCELED) {
                    //Process canceled multi-pointer motion event for Android 13 and higher.
                }
            }
        }
        true
    }
}

Java

View myView = findViewById(R.id.myView);
myView.setOnTouchListener( (view, event) -> {
    switch (event.getActionMasked()) {
        case MotionEvent.ACTION_CANCEL:
            // Process canceled single-pointer motion event for all SDK versions.
        case MotionEvent.ACTION_UP:
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
               (event.getFlags() & MotionEvent.FLAG_CANCELED) == MotionEvent.FLAG_CANCELED) {
                //Process canceled multi-pointer motion event for Android 13 and higher.
            }
    }
    return true;
});
3. 撤消手势

确定为手掌触摸后,您可以撤消手势在屏幕上的效果。

您的应用必须保留用户操作的历史记录,以便可以撤消意外输入(例如手掌触摸)。请参阅实现基本的绘图应用(位于增强 Android 应用中的触笔支持代码实验室中)以了解示例。

结果

您的应用现在可以识别并拒绝 Android 13 及更高 API 级别上的多指针事件以及所有 API 级别上的单指针事件的手掌触摸。

其他资源

更多信息,请参阅以下内容

WebView 状态管理

Three-star rating

WebView 是一款常用的组件,它提供了一种高级的状态管理系统。WebView必须在其配置发生更改时保持其状态和滚动位置。WebView在用户旋转设备或展开折叠式手机时可能会丢失滚动位置,这会迫使用户从WebView顶部再次滚动到之前的滚动位置。

最佳实践

尽量减少WebView重新创建的次数。WebView擅长管理其状态,您可以通过管理尽可能多的配置更改来利用此特性。您的应用必须处理配置更改,因为Activity重新创建(系统处理配置更改的方式)也会重新创建WebView,这会导致WebView丢失其状态。

要素

步骤

总结

要保存WebView状态,请尽可能避免Activity重新创建,然后让WebView失效,以便它可以在保留其状态的同时调整大小。

1. 将配置更改添加到应用的AndroidManifest.xml文件中

通过指定应用(而不是系统)处理的配置更改来避免活动重新创建

<activity
  android:name=".MyActivity"
  android:configChanges="screenLayout|orientation|screenSize
      |keyboard|keyboardHidden|smallestScreenSize" />

2. 每当应用收到配置更改时,都使WebView失效

Kotlin

override fun onConfigurationChanged(newConfig: Configuration) {
    super.onConfigurationChanged(newConfig)
    webView.invalidate()
}

Java

@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    webview.invalidate();
}

此步骤仅适用于视图系统,因为 Jetpack Compose 无需使任何内容失效即可正确调整Composable元素的大小。但是,如果 Compose 未正确管理,它会经常重新创建WebView。使用Accompanist WebView包装器可在您的 Compose 应用中保存和还原WebView状态。

结果

您的应用的WebView组件现在可以在多次配置更改(从调整大小到方向更改再到折叠和展开)中保留其状态和滚动位置。

其他资源

要了解有关配置更改以及如何管理配置更改的更多信息,请参阅处理配置更改

RecyclerView 状态管理

Three-star rating

RecyclerView可以使用最少的图形资源显示大量数据。当RecyclerView滚动浏览其项目列表时,RecyclerView会重用已滚动到屏幕外的项目的View实例,以便在它们滚动到屏幕上时创建新项目。但是,配置更改(例如设备旋转)可能会重置RecyclerView的状态,迫使用户再次滚动到他们之前在RecyclerView项目列表中的位置。

最佳实践

RecyclerView应在其配置发生所有更改时保持其状态(特别是滚动位置)及其列表元素的状态。

要素

步骤

总结

设置RecyclerView.Adapter的状态恢复策略以保存RecyclerView滚动位置。保存RecyclerView列表项目的状态。将列表项目的状态添加到RecyclerView适配器,并在将其绑定到ViewHolder时恢复列表项目的状态。

1. 启用Adapter状态恢复策略

启用RecyclerView适配器的状态恢复策略,以便在配置更改时保持RecyclerView的滚动位置。将策略规范添加到适配器构造函数

Kotlin

class MyAdapter() : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
    init {
        stateRestorationPolicy = StateRestorationPolicy.PREVENT_WHEN_EMPTY
    }
    ...
}

Java

class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    public Adapter() {
        setStateRestorationPolicy(StateRestorationPolicy.PREVENT_WHEN_EMPTY);
    }
    ...
}

2. 保存有状态列表项目的状态

保存复杂RecyclerView列表项目的状态,例如包含EditText元素的项目。例如,要保存EditText的状态,请添加类似于onClick处理程序的回调来捕获文本更改。在回调中,定义要保存的数据。

Kotlin

input.addTextChangedListener(
    afterTextChanged = { text ->
        text?.let {
            // Save state here.
        }
    }
)

Java

input.addTextChangedListener(new TextWatcher() {

    ...

    @Override
    public void afterTextChanged(Editable s) {
        // Save state here.
    }
});

在您的ActivityFragment中声明回调。使用ViewModel来存储状态。

3. 将列表项目状态添加到Adapter

将列表项目的状态添加到您的RecyclerView.Adapter。在创建主机ActivityFragment时,将项目状态传递到适配器构造函数

Kotlin

val adapter = MyAdapter(items, viewModel.retrieveState())

Java

MyAdapter adapter = new MyAdapter(items, viewModel.retrieveState());

4. 在适配器的ViewHolder中恢复列表项目状态

RecyclerView.Adapter中,当您将ViewHolder绑定到项目时,请恢复项目的狀態

Kotlin

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
    ...
    val item = items[position]
    val state = states.firstOrNull { it.item == item }

    if (state != null) {
        holder.restore(state)
    }
}

Java

@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
    ...
    Item item = items[position];
    Arrays.stream(states).filter(state -> state.item == item)
        .findFirst()
        .ifPresent(state -> holder.restore(state));
}

结果

您的RecyclerView现在可以恢复其滚动位置和RecyclerView列表中每个项目的状态。

其他资源

可拆卸键盘管理

Three-star rating

对可拆卸键盘的支持有助于最大限度地提高大屏幕设备上的用户生产力。每次将键盘连接到或从Android设备上断开连接时,Android都会触发配置更改,这可能会导致UI状态丢失。您的应用可以保存并恢复其状态,让系统处理活动重建,或者限制活动重建以进行键盘配置更改。在所有情况下,与键盘相关的所有数据都存储在Configuration对象中。keyboardkeyboardHidden配置对象的字段包含有关键盘类型及其可用性的信息。

最佳实践

针对大屏幕优化的应用支持各种类型的输入设备,从软件和硬件键盘到手写笔、鼠标、触控板和其他外围设备。

对外部键盘的支持涉及配置更改,您可以通过以下两种方式之一来管理这些更改

  1. 让系统重建当前正在运行的活动,您负责管理应用程序的状态。
  2. 自行管理配置更改(活动不会重建)
    • 声明所有与键盘相关的配置值
    • 创建配置更改处理程序

生产力应用通常需要对文本输入和其他输入的UI进行精细控制,因此可以从自行处理配置更改的方法中受益。

在特殊情况下,您可能希望在连接或断开硬件键盘时更改应用程序布局,例如,为工具或编辑窗口腾出更多空间。

由于监听配置更改的唯一可靠方法是覆盖视图的onConfigurationChanged()方法,您可以向应用活动添加一个新的View实例,并在视图的onConfigurationChanged()处理程序中响应由键盘连接或断开引起的配置更改。

要素

  • android:configChanges:应用清单的<activity>元素的属性。通知系统应用管理的配置更改。
  • View#onConfigurationChanged():对新应用配置传播做出反应的方法。

步骤

总结

声明configChanges属性并添加与键盘相关的值。向活动的视图层次结构中添加一个View并监听配置更改。

1. 声明configChanges属性

通过将keyboard|keyboardHidden值添加到已管理的配置更改列表中,更新应用清单中的<activity>元素

<activity
            android:configChanges="...|keyboard|keyboardHidden">

2. 向视图层次结构添加一个空视图

声明一个新的视图,并将您的处理程序代码添加到视图的onConfigurationChanged()方法中

Kotlin

val v = object : View(this) {
  override fun onConfigurationChanged(newConfig: Configuration?) {
    super.onConfigurationChanged(newConfig)
    // Handler code here.
  }
}

Java

View v = new View(this) {
    @Override
    protected void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        // Handler code here.
    }
};

结果

您的应用现在将响应外部键盘的连接或断开,而无需重建当前正在运行的活动。

其他资源

要了解如何在配置更改(例如键盘连接或断开)期间保存应用的UI状态,请参阅保存UI状态