自学内容网 自学内容网

Android onConfigurationChanged 基础配置

onConfigurationChanged 代替重建

0. 定义与基本用途

  • onConfigurationChanged()是Android中的一个生命周期方法。它在Activity(活动)中使用,用于处理设备配置发生改变的情况。当设备的配置发生变化,如屏幕方向的旋转(从竖屏变为横屏或者反之)、键盘可用性的改变、语言设置的变更等,系统默认会销毁并重新创建Activity。
  • 但是,如果在Activity中重写了onConfigurationChanged()方法,就可以在配置改变时避免Activity的重建,而是在原有Activity实例中处理配置变化。

1. 具体使用场景 - 屏幕方向改变

当用户将设备从竖屏旋转到横屏,或者从横屏旋转到竖屏时,系统会检测到屏幕方向的配置变化。在这种情况下,onConfigurationChanged方法会被调用,使得开发者可以在该方法中对布局进行重新调整,以适应新的屏幕方向。例如,对于一个新闻阅读应用,竖屏时文章内容可能以单列形式显示,而在横屏时可以将文章内容和相关图片以双列形式更好地呈现。

  1. 在AndroidManifest.xml文件中配置
    • 首先,需要在AndroidManifest.xml文件中的相应Activity标签中添加android:configChanges属性。如果只想在屏幕方向改变时自己处理配置变化,而不重建Activity,可以添加android:configChanges = "orientation"
    • 例如,对于一个简单的Activity定义如下:
    <activity
        android:name=".MainActivity"
        android:configChanges="orientation">
        <intent - filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent - filter>
    </activity>
    
  2. 在Activity类中重写onConfigurationChanged方法
    • 在Activity类中重写onConfigurationChanged方法来处理屏幕方向改变后的逻辑。以下是一个简单的示例代码:
    import android.content.res.Configuration;
    import android.os.Bundle;
    import android.app.Activity;
    public class MainActivity extends Activity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
        @Override
        public void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
            // 检查屏幕方向是否改变
            if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
                // 在这里处理横屏模式下的布局调整
            } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
                // 在这里处理竖屏模式下的布局调整
            }
        }
    }
    
    • 在上述代码中,当屏幕方向改变时,onConfigurationChanged方法会被调用。通过检查newConfig.orientation的值,可以确定是横屏还是竖屏模式,然后在对应的分支中进行布局调整等操作。

2. 具体使用场景 - 键盘可用性改变

包括软键盘和外接键盘。当软键盘弹出或收起时,或者外接键盘插入或拔出时,系统会认为这是一种配置变化。例如,在一个聊天应用中,当软键盘弹出时,消息列表可能会被压缩,输入框和发送按钮会调整到合适的位置,方便用户进行输入操作。当外接键盘插入后,应用可能会隐藏软键盘相关的界面元素,并重新布局文本输入区域,以更好地利用外接键盘进行输入。

  1. 在AndroidManifest.xml文件中设置
    • 要防止Activity在键盘可用性改变时重建,需要在AndroidManifest.xml文件中的Activity标签内设置android:configChanges属性。当只想处理键盘可用性改变(软键盘弹出或收起、外接键盘插入或拔出)时,可以添加android:configChanges="keyboardHidden|keyboard"
    • keyboard 属性有用的但是没查到单独用途
    • 示例代码如下:
    <activity
        android:name=".YourActivityName"
        android:configChanges="keyboardHidden">
        <intent - filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent - filter>
    </activity>
    
  2. 在Activity类中重写onConfigurationChanged方法
    • 同时,需要在Activity类中重写onConfigurationChanged方法来处理键盘可用性改变后的操作。例如:
    import android.content.res.Configuration;
    import android.os.Bundle;
    import android.app.Activity;
    public class YourActivityName extends Activity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.your_layout_name);
        }
        @Override
        public void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
            if (newConfig.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO) {
                // 键盘现在可见,执行相关操作,如调整布局
                // 例如,重新排列视图元素,为键盘腾出空间
            } else if (newConfig.keyboardHidden == Configuration.KEYBOARDHIDDEN_YES) {
                // 键盘现在隐藏,执行相应操作
                // 比如,恢复视图元素的原始布局
            }
        }
    }
    
    • 在上述代码中,通过检查newConfig.keyboardHidden的值来判断键盘是隐藏还是可见。Configuration.KEYBOARDHIDDEN_NO表示键盘可见,Configuration.KEYBOARDHIDDEN_YES表示键盘隐藏。根据键盘的状态,可以在对应的条件分支中调整视图布局或执行其他相关操作。

3. 具体使用场景 - 语言设置变更

当用户在设备的系统设置中更改语言后,应用需要更新界面上的文字显示来匹配新的语言环境。此时onConfigurationChanged方法会被调用,开发者可以在这个方法中重新加载相应语言的字符串资源,确保应用的菜单、按钮标签、提示信息等文字内容能够以正确的语言呈现给用户。例如,一个国际化的电商应用,当语言从英语切换到法语后,商品名称、价格标签、购物流程中的提示文字等都需要在onConfigurationChanged方法的处理下更新为法语。

  1. 在AndroidManifest.xml中配置
    • 要阻止Activity在语言设置变更时重建,需要在对应的Activity标签内的android:configChanges属性中添加locale。例如:
    <activity
        android:name=".YourActivityName"
        android:configChanges="locale">
        <intent - filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent - filter>
    </activity>
    
  2. 在Activity类中重写onConfigurationChanged方法
    • 接着,在Activity类中重写onConfigurationChanged方法来处理语言变更后的操作。可以在这个方法中重新加载语言相关的资源,以更新界面上的文字显示。以下是一个简单的示例:
    import android.content.res.Configuration;
    import android.os.Bundle;
    import android.app.Activity;
    import android.content.res.Resources;
    import java.util.Locale;
    public class YourActivityName extends Activity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.your_layout_name);
        }
        @Override
        public void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
            if (newConfig.locale!= null) {
                // 语言设置已改变
                Locale locale = newConfig.locale;
                Resources resources = getResources();
                Configuration configuration = resources.getConfiguration();
                configuration.setLocale(locale);
                resources.updateConfiguration(configuration, resources.getDisplayMetrics());
                // 重新加载布局,使文字以新语言显示
                setContentView(R.layout.your_layout_name);
            }
        }
    }
    
    • 在上述代码中,首先获取新的语言设置(Locale)。然后,通过getResources()获取Resources对象,再获取当前的Configuration对象。接着,将新的语言设置应用到Configuration对象中,并使用updateConfiguration方法更新资源配置。最后,重新加载布局,这样界面上的文字就会以新的语言显示。

4. 具体使用场景 - 屏幕密度变化

用户可能会在设备设置中手动调整屏幕分辨率,这会导致屏幕密度改变。另外,当设备连接到不同的外部显示器时,屏幕密度也可能发生变化。在这种情况下,onConfigurationChanged方法可以被用于重新调整图像资源的加载和显示方式、布局尺寸的缩放等。例如,对于一个图标密集型的应用,当屏幕密度变高时,可以在onConfigurationChanged方法中加载更高分辨率的图标,以保证图标在高密度屏幕上的清晰度。

  1. 在AndroidManifest.xml中进行配置
    • 要防止Activity在屏幕密度变化时重建,需要在AndroidManifest.xml文件中的Activity标签内设置android:configChanges属性。对于屏幕密度变化,需要添加density
    • 示例代码如下:
    <activity
        android:name=".YourActivityName"
        android:configChanges="density">
        <intent - filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent - filter>
    </activity>
    
  2. 在Activity类中重写onConfigurationChanged方法
    • 在Activity类中重写onConfigurationChanged方法来处理屏幕密度变化后的操作。可以在这个方法中调整与屏幕密度相关的资源加载和布局。例如,处理图像资源的加载方式,以适应新的屏幕密度。
    import android.content.res.Configuration;
    import android.os.Bundle;
    import android.app.Activity;
    public class YourActivityName extends Activity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.your_layout_name);
        }
        @Override
        public void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
            if (newConfig.densityDpi!= 0) {
                // 屏幕密度已改变,根据新的密度DPI进行操作
                int newDensityDpi = newConfig.densityDpi;
                // 例如,重新加载合适分辨率的图像资源
                // 假设你有根据不同密度存储图像的逻辑
                // 可以在这里调用相关方法来加载正确的图像
            }
        }
    }
    
    • 在上述代码中,通过检查newConfig.densityDpi的值来确定屏幕密度是否改变。如果屏幕密度改变了(newConfig.densityDpi不为0),可以获取新的屏幕密度值(newDensityDpi),并根据这个值来调整资源加载。例如,如果有针对不同屏幕密度的图像资源文件夹(如drawable - ldpidrawable - mdpidrawable - hdpi等),可以在这里编写逻辑来加载适合新屏幕密度的图像。

5. 具体使用场景 - 字体大小改变

许多Android设备允许用户调整系统字体大小。当用户改变字体缩放比例后,系统会触发配置变化,调用onConfigurationChanged方法。在这个方法中,开发者可以对文本相关的视图进行调整,如重新计算文本的大小、行间距、边距等。例如,在一个电子书应用中,当用户增大字体缩放比例后,onConfigurationChanged方法可以调整每页显示的文字数量和排版方式,以确保文字仍然能够清晰可读。

  1. 在AndroidManifest.xml文件中配置
    • 首先,在AndroidManifest.xml中对应的Activity标签里添加android:configChanges属性。为了防止Activity在字体大小改变时重建,需要添加fontScale。示例如下:
    <activity
        android:name=".YourActivityName"
        android:configChanges="fontScale">
        <intent - filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent - filter>
    </activity>
    
  2. 在Activity类中重写onConfigurationChanged方法
    • 接着,在Activity类中重写onConfigurationChanged方法来处理字体大小改变后的情况。主要是对文本相关的视图进行调整,比如重新计算文本大小、行间距等。
    import android.content.res.Configuration;
    import android.os.Bundle;
    import android.app.Activity;
    import android.util.TypedValue;
    import android.view.View;
    import android.widget.TextView;
    public class YourActivityName extends Activity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.your_layout_name);
        }
        @Override
        public void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
            if (newConfig.fontScale!= 1.0f) {
                // 字体缩放比例发生改变
                float newFontScale = newConfig.fontScale;
                // 遍历所有的TextView并调整文本大小
                View rootView = findViewById(android.R.id.content);
                adjustTextViewFontSize(rootView, newFontScale);
            }
        }
        private void adjustTextViewFontSize(View view, float fontScale) {
            if (view instanceof TextView) {
                TextView textView = (TextView) view;
                float originalTextSize = textView.getTextSize();
                float newTextSize = originalTextSize * fontScale;
                textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, newTextSize);
            } else if (view instanceof ViewGroup) {
                ViewGroup viewGroup = (ViewGroup) view;
                for (int i = 0; i < viewGroup.getChildCount(); i++) {
                    View childView = viewGroup.getChildAt(i);
                    adjustTextViewFontSize(childView, fontScale);
                }
            }
        }
    }
    
    • 在上述代码中,当字体缩放比例(newConfig.fontScale)不等于1.0f时,表示字体大小发生了改变。获取新的字体缩放比例后,通过adjustTextViewFontSize方法来遍历布局中的所有TextView。在这个方法中,如果视图是TextView,则获取其原始文本大小,根据新的字体缩放比例计算新的文本大小,然后设置TextView的文本大小。如果视图是ViewGroup,则递归地调用adjustTextViewFontSize方法来处理子视图。

6. 具体使用场景 - 屏幕尺寸变化(多窗口模式等)

在支持多窗口模式的设备上,当应用从全屏模式切换到分屏模式或者画中画模式时,屏幕尺寸会发生变化。这种情况下,onConfigurationChanged方法会被触发。应用可以在这个方法中重新布局视图,以充分利用新的屏幕空间。例如,在一个文档编辑应用中,当进入分屏模式时,可以在onConfigurationChanged方法中调整文档编辑区域和工具菜单区域的大小和位置,以便用户可以同时查看其他应用内容并进行文档编辑。

  1. 在AndroidManifest.xml文件中配置
    • 为了防止Activity在屏幕尺寸变化(如进入多窗口模式)时重建,需要在AndroidManifest.xml文件中的Activity标签内设置android:configChanges属性。对于屏幕尺寸相关的变化,应该添加screenSizesmallestScreenSize。此外,如果涉及屏幕方向变化也需要同时处理(因为在多窗口模式下屏幕方向也可能改变),还需要添加orientation
    • 示例代码如下:
    <activity
        android:name=".YourActivityName"
        android:configChanges="screenSize|smallestScreenSize|orientation">
        <intent - filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent - filter>
    </activity>
    
  2. 在Activity类中重写onConfigurationChanged方法
    • 在Activity类中重写onConfigurationChanged方法来处理屏幕尺寸变化后的操作。可以通过获取新的屏幕尺寸信息来重新布局视图,以充分利用新的屏幕空间。
    import android.content.res.Configuration;
    import android.os.Bundle;
    import android.app.Activity;
    import android.view.View;
    import android.widget.LinearLayout;
    public class YourActivityName extends Activity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.your_layout_name);
        }
        @Override
        public void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
            if (newConfig.screenWidthDp!= 0 && newConfig.screenHeightDp!= 0) {
                // 屏幕尺寸已改变,获取新的屏幕尺寸
                int newScreenWidthDp = newConfig.screenWidthDp;
                int newScreenHeightDp = newConfig.screenHeightDp;
                // 例如,重新布局LinearLayout中的视图
                LinearLayout linearLayout = findViewById(R.id.your_linear_layout_id);
                if (linearLayout!= null) {
                    // 根据新的屏幕尺寸调整视图布局
                    View childView = linearLayout.getChildAt(0);
                    LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) childView.getLayoutParams();
                    layoutParams.width = newScreenWidthDp / 2;
                    layoutParams.height = newScreenHeightDp / 3;
                    childView.setLayoutParams(layoutParams);
                }
            }
        }
    }
    
    • 在上述代码中,首先通过检查newConfig.screenWidthDpnewConfig.screenHeightDp来确定屏幕尺寸是否改变。如果改变了,获取新的屏幕宽度和高度(单位为dp)。然后,以LinearLayout为例,找到其中的一个子视图,获取它的布局参数,根据新的屏幕尺寸调整视图的宽度和高度,最后重新设置子视图的布局参数。这只是一个简单的示例,实际应用中可能需要根据具体的布局和功能需求进行更复杂的布局调整。

7. 具体使用场景 - 设备主题变化

当用户在设备的系统设置中更改主题(如从亮色主题切换到暗色主题,或者反之),这也会导致配置改变。onConfigurationChanged方法可以用来更新应用的界面主题相关元素,如视图的背景颜色、文本颜色等。例如,在一个具有夜间模式功能的应用中,当系统主题切换到暗色主题时,onConfigurationChanged方法可以将应用的界面整体色调调整为暗色,减少眼睛疲劳,同时确保界面元素的对比度合适,便于用户查看。

  1. 在AndroidManifest.xml文件中配置

    • 为避免Activity在设备主题变化时重建,需要在AndroidManifest.xml中对应的Activity标签里添加android:configChanges属性。对于设备主题变化,要添加uiMode
    • 示例代码如下:
    <activity
        android:name=".YourActivityName"
        android:configChanges="uiMode">
        <intent - filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent - filter>
    </activity>
    
  2. 在Activity类中重写onConfigurationChanged方法

    • 在Activity类中重写onConfigurationChanged方法来处理设备主题变化后的情况。主要是更新应用的界面主题相关元素,如视图的背景颜色、文本颜色等。
    import android.content.res.Configuration;
    import android.os.Bundle;
    import android.app.Activity;
    import android.view.View;
    import android.widget.TextView;
    import android.graphics.Color;
    public class YourActivityName extends Activity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.your_layout_name);
        }
        @Override
        public void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
            if ((newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES) {
                // 主题变为夜间模式
                View rootView = findViewById(android.R.id.content);
                updateViewColorsForNightMode(rootView);
            } else {
                // 主题变为白天模式或其他非夜间模式
                View rootView = findViewById(android.R.id.content);
                updateViewColorsForDayMode(rootView);
            }
        }
        private void updateViewColorsForNightMode(View view) {
            if (view instanceof TextView) {
                TextView textView = (TextView) view;
                textView.setTextColor(Color.WHITE);
            }
            view.setBackgroundColor(Color.BLACK);
            if (view instanceof ViewGroup) {
                ViewGroup viewGroup = (ViewGroup) view;
                for (int i = 0; i < viewGroup.getChildCount(); i++) {
                    View childView = viewGroup.getChildAt(i);
                    updateViewColorsForNightMode(childView);
                }
            }
        }
        private void updateViewColorsForDayMode(View view) {
            if (view instanceof TextView) {
                TextView textView = (TextView) view;
                textView.setTextColor(Color.BLACK);
            }
            view.setBackgroundColor(Color.WHITE);
            if (view instanceof ViewGroup) {
                ViewGroup viewGroup = (ViewGroup) view;
                for (int i = 0; i < viewGroup.getChildCount(); i++) {
                    View childView = viewGroup.getChildAt(i);
                    updateViewColorsForDayMode(childView);
                }
        }
    }
    
    • 在上述代码中,通过检查newConfig.uiModeConfiguration.UI_MODE_NIGHT_MASK来判断是否为夜间模式。如果是夜间模式,调用updateViewColorsForNightMode方法来更新视图颜色;如果不是夜间模式,调用updateViewColorsForDayMode方法。这些方法会遍历视图树,对于TextView更新文本颜色,对于视图设置背景颜色,并且如果是ViewGroup会递归地更新子视图的颜色。
  3. 偶现onConfigurationChanged 内setBackgroundColor 颜色错误

    • 资源文件的加载过程确实会发生在主线程上,并且通常是同步的。然而,在某些情况下,你可能会遇到在onConfigurationChanged方法内取出颜色值错误的问题。这可能是由于以下几个原因造成的:

      1. 资源加载未完成
        尽管资源加载通常是同步的,但在某些极端情况下,特别是在资源较多或设备性能较差的情况下,资源加载可能会有一些延迟。如果你在资源加载尚未完全完成时尝试获取颜色值,可能会得到错误的结果。
      1. 主题未正确应用
        如果你在onConfigurationChanged方法中手动设置了新的主题,但没有正确地重新创建视图或更新UI,可能会导致资源未能正确加载。确保你调用了recreate()方法来重新创建Activity,或者手动更新了所有相关的视图。
      1. 缓存问题
        有时,资源可能被缓存,导致你获取到的是旧的资源值。尽管这种情况比较少见,但你可以尝试清除资源缓存或强制重新加载资源。
      1. 代码执行顺序
        如果你在onConfigurationChanged方法中直接获取颜色值,但资源加载尚未完成,可能会导致获取到错误的颜色值。你可以通过以下方法来确保资源加载完成后再获取颜色值:
      1. 检查资源文件
        确保你的资源文件(如colors.xml)在不同配置文件夹中(如res/values/res/values-night/)正确配置,并且资源名称一致。
      1. 调试和日志
        添加日志来调试资源加载过程,确保在onConfigurationChanged方法中获取到的颜色值是正确的。
  • 使用post方法 解决4
    你可以使用post方法来确保在下一个UI线程的可运行时刻执行资源获取和UI更新操作。这样可以给资源加载留出足够的时间。

    如果你希望主题的切换完全由AndroidManifest.xml配置,并且系统自动处理,那么你不需要在onConfigurationChanged方法中手动设置主题或调用recreate()。系统会自动应用新的主题,并重新加载资源。你只需要确保在onConfigurationChanged方法中处理UI的更新。

  • 修改 AndroidManifest.xml
    AndroidManifest.xml中为你的Activity添加android:configChanges="uiMode"属性,并设置默认的主题。这样,系统会在UI模式变化时自动应用正确的主题。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        
        <activity
            android:name=".MyActivity"
            android:configChanges="uiMode"
            android:label="@string/app_name"
            android:theme="@style/AppTheme">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>
  • 定义主题
    res/values/styles.xmlres/values-night/styles.xml中定义你的日间和夜间主题。

    • res/values/styles.xml
<resources>
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryVariant">@color/colorPrimaryVariant</item>
        <item name="colorOnPrimary">@color/colorOnPrimary</item>
        <item name="colorBackground">@color/white</item>
        <!-- Other attributes... -->
    </style>
</resources>
  • res/values-night/styles.xml
<resources>
    <!-- Base application theme for night mode. -->
    <style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimaryNight</item>
        <item name="colorPrimaryVariant">@color/colorPrimaryVariantNight</item>
        <item name="colorOnPrimary">@color/colorOnPrimaryNight</item>
        <item name="colorBackground">@color/black</item>
        <!-- Other attributes... -->
    </style>
</resources>
  • 修改 onConfigurationChanged 方法
    onConfigurationChanged方法中,只需处理UI的更新,不需要手动设置主题或调用recreate()
import android.content.res.Configuration;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import android.view.View;

public class MyActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);

        // 使用post方法确保资源加载完成后再更新UI
        final View rootView = findViewById(android.R.id.content).getRootView();
        rootView.post(new Runnable() {
            @Override
            public void run() {
                // 更新UI的代码
                int backgroundColor = ContextCompat.getColor(MyActivity.this, R.color.colorBackground);
                rootView.setBackgroundColor(backgroundColor);
                // 其他UI更新操作
            }
        });
    }
}
  • 解释
  1. AndroidManifest.xml

    • <activity>标签中添加了android:configChanges="uiMode",这样当UI模式发生变化时,系统会调用onConfigurationChanged方法而不是重启Activity。
    • 设置了默认的主题@style/AppTheme,系统会根据当前的UI模式自动选择正确的主题。
  2. 主题定义

    • res/values/styles.xml中定义了日间模式的主题。
    • res/values-night/styles.xml中定义了夜间模式的主题。
  3. onConfigurationChanged方法

    • 调用super.onConfigurationChanged(newConfig)以确保父类的处理逻辑被执行。
    • 使用post方法确保在资源加载完成后更新UI,从而避免获取到错误的颜色值。

通过这种方式,系统会自动处理主题的切换,并且你只需要在onConfigurationChanged方法中处理UI的更新。这样可以简化代码,并确保资源加载和UI更新的正确性。

8. 具体使用场景 - 传感器配置改变(部分情况)

虽然不是所有的传感器配置改变都会触发onConfigurationChanged,但在某些特定场景下会。例如,当设备支持的传感器精度发生改变(如从低精度的运动传感器模式切换到高精度模式),并且这种改变被系统认为是一种配置变化时,onConfigurationChanged方法可以被用来重新初始化与传感器相关的操作。例如,在一个运动监测应用中,如果传感器精度提高,可以在onConfigurationChanged方法中调整数据采集的频率或者更新数据处理的算法,以利用更精确的传感器数据来提供更准确的运动监测。

9. 具体使用场景 - 触摸屏模式改变(极少见)

在一些特殊设备或者特定的系统设置下,触摸屏模式可能会发生改变,例如从电容式触摸屏的多点触控模式变为单点触控模式。这种情况下,如果系统将其视为配置变化,onConfigurationChanged方法会被调用。开发者可以在这个方法中调整应用中与触摸操作相关的逻辑,例如重新定义手势操作的响应方式,确保应用在新的触摸屏模式下依然能够正常使用。

  1. 基本概念

    • touchscreen属性主要用于处理与触摸屏相关的配置变化。在Android设备中,触摸屏是主要的输入方式之一,这个属性可以帮助应用在触摸屏的特性发生改变时做出适当的响应。这些改变可能包括触摸屏技术的升级、触摸屏灵敏度的调整,或者是从一种触摸屏模式转换到另一种模式(例如从普通触摸模式转换到手套触摸模式)。
  2. 配置变化场景

    • 触摸屏灵敏度变化:用户可以在设备设置中调整触摸屏的灵敏度。当灵敏度改变时,touchscreen属性可以帮助检测到这种变化。例如,在一些绘图应用中,如果触摸屏变得更灵敏,应用可能需要调整画笔的笔触大小或者绘制的精度,以适应新的触摸输入特性。同样,在游戏应用中,更高的触摸屏灵敏度可能需要调整游戏角色的移动速度或者操作响应的阈值。
    • 触摸屏模式转换:某些设备支持特殊的触摸屏模式。比如,一些手机具有手套触摸模式,当开启这个模式时,即使用户戴着手套也能操作触摸屏。从正常触摸模式转换到手套触摸模式或者反之,这是一种配置变化。在这种情况下,应用可能需要调整触摸事件的处理方式。例如,在手套触摸模式下,触摸的精度可能会降低,应用可以增大触摸操作的有效区域范围,或者对触摸事件进行更宽松的过滤,以确保用户仍然能够方便地进行操作。
  3. 在代码中的处理示例

    • 以下是一个简单的示例,展示在onConfigurationChanged方法中处理touchscreen相关变化的思路:
    import android.content.res.Configuration;
    import android.os.Bundle;
    import android.app.Activity;
    public class MainActivity extends Activity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
        @Override
        public void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
            if (newConfig.touchscreen!= Configuration.TOUCHSCREEN_NOTOUCH) {
                // 触摸屏相关配置发生变化
                if (newConfig.touchscreenSensitivityChanged) {
                    // 触摸屏灵敏度发生变化
                    int newSensitivityLevel = newConfig.touchscreenSensitivityLevel;
                    handleSensitivityChange(newSensitivityLevel);
                }
                if (newConfig.touchscreenModeChanged) {
                    // 触摸屏模式发生变化
                    int newMode = newConfig.touchscreenMode;
                    handleModeChange(newMode);
                }
            }
        }
        private void handleSensitivityChange(int sensitivityLevel) {
            // 根据灵敏度级别调整应用功能
            if (sensitivityLevel > 50) {
                // 假设灵敏度级别大于50为高灵敏度
                adjustForHighSensitivity();
            } else {
                // 假设灵敏度级别小于等于50为低灵敏度
                adjustForLowSensitivity();
            }
        }
        private void adjustForHighSensitivity() {
            // 在高灵敏度下调整绘图应用中画笔笔触大小
            // 或者在游戏应用中调整角色移动速度等操作
            // 例如,在绘图应用中减小画笔笔触大小
        }
        private void adjustForLowSensitivity() {
            // 在低灵敏度下调整绘图应用中画笔笔触大小
            // 或者在游戏应用中调整角色移动速度等操作
            // 例如,在绘图应用中增大画笔笔触大小
        }
        private void handleModeChange(int mode) {
            // 根据触摸屏模式调整应用功能
            if (mode == Configuration.TOUCHSCREEN_MODE_GLOVE) {
                // 手套触摸模式
                adjustForGloveMode();
            } else {
                // 正常触摸模式
                adjustForNormalMode();
            }
        }
        private void adjustForGloveMode() {
            // 增大触摸操作的有效区域范围
            // 或者对触摸事件进行更宽松的过滤
        }
        private void adjustForNormalMode() {
            // 恢复正常触摸操作的有效区域范围
            // 或者恢复正常的触摸事件过滤方式
        }
    }
    
    • 在上述代码中,在onConfigurationChanged方法中,当检测到触摸屏相关配置发生变化(newConfig.touchscreen不为Configuration.TOUCHSCREEN_NOTOUCH)时,进一步检查是灵敏度变化还是模式变化。如果是灵敏度变化,通过handleSensitivityChange方法根据新的灵敏度级别来调整应用功能;如果是模式变化,通过handleModeChange方法根据新的模式来调整应用功能。这些调整操作只是示例,实际应用中需要根据具体的应用场景和需求进行更精确的设计。

10. 具体使用场景 - 音频输出设备改变

当用户将音频输出从内置扬声器切换到蓝牙耳机,或者在多个音频输出设备之间切换时,系统可能会触发配置变化并调用onConfigurationChanged方法。在这种情况下,应用可以在这个方法中重新配置音频相关的功能,例如调整音量控制逻辑,或者根据新的音频输出设备的特性(如蓝牙耳机的声道平衡等)进行音频播放的优化。

<activity
    android:name=".YourActivityName"
    android:configChanges="audioOutputDeviceChanged">
    <intent - filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent - filter>
</activity>

未查证到此信息。

11. 具体使用场景 - 辅助功能设置改变

当用户对设备的辅助功能进行设置更改时,如开启或关闭屏幕阅读器、调整颜色反转等辅助功能选项,系统可能会触发配置变化,进而调用onConfigurationChanged方法。对于应用来说,在这种场景下,可能需要调整界面元素的显示方式或者交互逻辑。例如,当屏幕阅读器开启后,应用可能需要确保视图的内容能够被正确地朗读出来,这就需要在onConfigurationChanged方法中对可访问性相关的属性进行设置,比如为按钮添加合适的内容描述,方便视障用户理解按钮的功能。

<activity
    android:name=".YourActivityName"
    android:configChanges="accessibility">
    <intent - filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent - filter>
</activity>

未查证到此信息。

12. 具体使用场景 - 模拟位置设置改变

如果用户在开发者选项或者某些特定的系统设置中更改了模拟位置的设置,这可能会被视为一种配置变化。在这种情况下,onConfigurationChanged方法可以被调用。对于一些基于位置服务的应用,如地图应用或者基于位置的社交应用,当模拟位置设置改变时,可能需要在onConfigurationChanged方法中重新评估位置信息的获取和使用方式。例如,重新确定是否使用模拟位置数据进行地图定位展示或者基于位置的推荐服务。

<activity
    android:name=".YourActivityName"
    android:configChanges="mockLocationSettingsChanged">
    <intent - filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent - filter>
</activity>

未查证到此信息。

13. 具体使用场景 - 系统显示模式改变(如夜间模式、护眼模式)

除了设备主题变化外,系统可能有专门的显示模式设置,如夜间模式和护眼模式。当用户开启或关闭这些模式时,会引起屏幕的颜色、亮度等显示参数的改变。onConfigurationChanged方法可以用来调整应用内的显示设置,以更好地适应这些变化。例如,在护眼模式下,可能需要降低屏幕的蓝光强度,应用可以在onConfigurationChanged方法中通过调整颜色滤镜或者降低某些颜色通道的强度来实现。

<activity
    android:name=".YourActivityName"
    android:configChanges="uiMode">
    <intent - filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent - filter>
</activity>

14. 具体使用场景 - 应用安装/卸载外部插件或组件

如果应用支持外部插件或组件的安装和卸载,当有此类操作发生时,系统可能将其视为一种配置变化。例如,一个具有插件扩展功能的媒体播放器应用,当用户安装了一个新的音频解码插件或者卸载了一个视频滤镜插件时,onConfigurationChanged方法可以被调用。在这个方法中,应用可以重新扫描可用的插件列表,更新相关的功能菜单,或者重新初始化某些依赖于插件的功能模块,以确保应用能够正常运行并提供完整的功能。

  1. 在AndroidManifest.xml中配置

    • 对于应用安装/卸载外部插件或组件这种情况,没有专门用于此场景的预定义android:configChanges属性值。不过,你可以使用自定义的配置名称来处理这种情况。
    • 假设我们定义一个自定义的配置变化名称为pluginInstallationOrUninstallation,在AndroidManifest.xml中的Activity标签内添加如下配置:
    <activity
        android:name=".YourActivityName"
        android:configChanges="pluginInstallationOrUninstallation">
        <intent - filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent - filter>
    </activity>
    
    • 为了让这个自定义配置生效,需要在应用内部建立一种机制来检测插件或组件的安装/卸载事件,并将其视为配置变化。这通常需要结合广播接收器来实现。
  2. 使用广播接收器检测插件或组件变化并通知系统(关键步骤)

    • 当外部插件或组件安装或卸载时,系统会发送广播。可以创建一个广播接收器来捕获这些广播,然后通知系统这是一个自定义的配置变化。
    • 例如,对于应用内插件(假设插件是通过APK文件安装),可以监听android.intent.action.PACKAGE_ADDEDandroid.intent.action.PACKAGE_REMOVED广播。
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.content.pm.PackageManager;
    public class PluginChangeReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (action.equals(Intent.ACTION_PACKAGE_ADDED) || action.equals(Intent.ACTION_PACKAGE_REMOVED)) {
                // 检查是否是插件相关的包
                String packageName = intent.getData().getSchemeSpecificPart();
                if (isPluginPackage(packageName)) {
                    // 通知系统这是一个自定义的配置变化
                    notifyConfigurationChange(context);
                }
            }
        }
        private boolean isPluginPackage(String packageName) {
            // 这里需要实现一个逻辑来判断packageName是否是插件包
            // 例如,可以通过检查包名是否在已知的插件包名列表中
            PackageManager packageManager = context.getPackageManager();
            try {
                // 检查包的签名、来源或者其他自定义的规则来判断是否是插件
                packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
                return true;  // 假设获取到包信息就认为是插件(实际需要更严格的判断)
            } catch (PackageManager.NameNotFoundException e) {
                return false;
            }
        }
        private void notifyConfigurationChange(Context context) {
            // 通过某种方式通知系统这是一个自定义的配置变化
            // 一种可能的方式是发送一个粘性广播(这种方式可能有一些限制和兼容性问题)
            Intent configChangeIntent = new Intent("your.custom.config.change.action");
            context.sendStickyBroadcast(configChangeIntent);
        }
    }
    
  3. 在Activity类中重写onConfigurationChanged方法处理变化

    • Activity类中重写onConfigurationChanged方法来处理插件或组件安装/卸载后的操作。
    import android.content.res.Configuration;
    import android.os.Bundle;
    import android.app.Activity;
    public class YourActivityName extends Activity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.your_layout_name);
        }
        @Override
        public void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
            if (newConfig.pluginInstallationOrUninstallation) {
                // 处理插件或组件安装/卸载后的操作
                if (isPluginInstalled()) {
                    // 插件安装后的操作,比如加载插件功能
                    loadPluginFunction();
                } else {
                    // 插件卸载后的操作,比如清理与插件相关的资源
                    cleanUpPluginResources();
                }
            }
        }
        private boolean isPluginInstalled() {
            // 检查插件是否安装的逻辑,例如检查插件的包是否存在
            return false;
        }
        private void loadPluginFunction() {
            // 加载插件功能的具体逻辑,例如初始化插件的入口类等
        }
        private void cleanUpPluginResources() {
            // 清理与插件相关资源的具体逻辑,例如释放插件占用的内存、清除缓存等
        }
    }
    
    • 在上述代码中,onConfigurationChanged方法在检测到自定义的配置变化(插件或组件安装/卸载)后,通过isPluginInstalled方法检查插件是否安装,然后根据情况分别执行loadPluginFunction(插件安装后加载功能)或cleanUpPluginResources(插件卸载后清理资源)操作。
  4. 注册广播接收器

    • 最后,需要在Activity(或者在应用的其他合适的地方,如Application类)中注册广播接收器,以便能够捕获插件或组件安装/卸载广播。
    import android.content.IntentFilter;
    public class YourActivityName extends Activity {
        private PluginChangeReceiver pluginChangeReceiver;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.your_layout_name);
            // 注册广播接收器
            pluginChangeReceiver = new PluginChangeReceiver();
            IntentFilter filter = new IntentFilter();
            filter.addAction(Intent.ACTION_PACKAGE_ADDED);
            filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
            filter.addDataScheme("package");
            registerReceiver(pluginChangeReceiver, filter);
        }
        @Override
        protected void onDestroy() {
            super.onDestroy();
            // 注销广播接收器
            unregisterReceiver(pluginChangeReceiver);
        }
    }
    
    • 这样,当外部插件或组件安装或卸载时,广播接收器会捕获到相关广播,通知系统这是一个自定义的配置变化,然后ActivityonConfigurationChanged方法会处理相应的操作,并且避免了Activity的重建。不过,这种方法涉及到自定义配置变化和广播接收器的使用,需要注意兼容性和可能出现的问题,如粘性广播的正确使用、插件包的准确判断等。

16. 具体使用场景 - 系统更新后配置变化

当设备完成系统更新,一些系统级别的设置或者功能可能会发生改变。这可能会导致配置的变更,从而调用onConfigurationChanged方法。例如,系统更新后可能改变了权限管理的方式,或者对某些传感器的默认精度进行了调整。应用可以在这个方法中检查新的系统环境,重新请求必要的权限或者重新校准与传感器相关的功能,以适应系统更新后的变化。

17. 具体使用场景 - 虚拟内存设置改变

在一些高级的设备设置中,用户可以调整虚拟内存的大小或使用方式。当这种设置发生变化时,系统可能将其视为配置改变。对于占用内存较大的应用,如大型游戏或图形处理软件,在onConfigurationChanged方法中可以根据新的虚拟内存设置来优化内存使用策略。例如,当虚拟内存增大时,应用可以适当增加缓存的大小,以提高性能。

18. 具体使用场景 - 设备存储空间状态改变

如果设备的存储空间从充足变为不足(例如存储快要满了)或者反之,这可能会引起配置变化。在onConfigurationChanged方法中,应用可以对数据存储相关的操作进行调整。例如,对于一个具有本地缓存功能的应用,当存储空间不足时,可以在该方法中清理部分缓存文件,或者调整缓存策略,优先删除较旧或较大的文件,以释放空间并确保应用正常运行。

广播会发过来,正常不走 onConfigurationChanged

19. 具体使用场景 - 设备电源模式改变

当用户在设备上切换电源模式,如从高性能模式切换到节能模式,或者从普通模式切换到超级省电模式时,系统可能会触发配置变化。对于资源密集型的应用,如3D游戏或视频编辑应用,在onConfigurationChanged方法中可以根据新的电源模式来调整性能策略。例如,在节能模式下,降低图形渲染质量或者减少后台数据同步的频率,以降低功耗。

20. 具体使用场景 - 多用户配置切换(设备支持多用户)

在支持多用户的设备上,当用户切换不同的用户账户时,系统会重新配置应用的环境。onConfigurationChanged方法可以被调用,应用可以在这个方法中更新用户相关的数据显示和权限设置。例如,一个笔记应用可以在该方法中加载当前用户账户下的笔记内容,并且根据新用户的权限设置来调整是否允许编辑等操作。

21. 具体使用场景 - 布局方向切换

  1. 布局文本方向的控制
    • layoutDirection主要用于控制布局内文本和视图元素的方向。在从左到右(LTR)的布局方向中,文本通常从左向右流动,视图元素(如按钮、文本框等)的排列顺序也是从左到右。例如,在一个表单布局中,标签和输入框会按照从左到右的顺序依次排列。而在从右到左(RTL)的布局方向下,这些元素的排列顺序则相反。
    • 这一属性对于处理多语言文本的应用尤为重要。比如,对于阿拉伯语或希伯来语等从右到左书写的语言,layoutDirection可以确保界面元素(如菜单选项、对话框内容等)的布局符合语言习惯,提高用户体验。
  2. 与视图布局的关系
    • 在布局文件(如XML布局)中,layoutDirection属性会影响整个视图层次结构的布局。它可以应用于各种布局容器,如LinearLayout、RelativeLayout等。
    • 以LinearLayout为例,如果layoutDirection设置为LTR,并且orientation(方向)设置为水平,那么添加到LinearLayout中的子视图将从左到右依次排列。相反,如果layoutDirection是RTL,子视图则从右到左排列。对于RelativeLayout,layoutDirection会影响视图之间相对位置的规则。例如,在RTL布局下,“toRightOf”规则可能会根据从右到左的方向进行解释,从而调整视图的位置。
  3. 动态更新布局方向
    • 可以通过代码动态地改变layoutDirection属性来响应用户操作或系统配置变化。在Activity的onConfigurationChanged方法中,可以根据新的配置信息来更新布局方向。
    • 例如,当用户在设备上更改语言设置,并且新语言的布局方向与当前不同时,系统会触发配置变化。在onConfigurationChanged方法中,可以检查layoutDirection的变化,并相应地更新布局。
    import android.content.res.Configuration;
    import android.os.Bundle;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.TextView;
    import androidx.appcompat.app.AppCompatActivity;
    public class MainActivity extends AppCompatActivity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
        @Override
        public void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
            if (newConfig.layoutDirection == View.LAYOUT_DIRECTION_RTL) {
                // 遍历所有的TextView并设置文本方向为RTL
                ViewGroup rootView = findViewById(android.R.id.content);
                setRTLTextDirection(rootView);
            } else if (newConfig.layoutDirection == View.LAYOUT_DIRECTION_LTR) {
                // 遍历所有的TextView并设置文本方向为LTR
                ViewGroup rootView = findViewById(android.R.id.content);
                setLTRTextDirection(rootView);
            }
        }
        private void setRTLTextDirection(ViewGroup viewGroup) {
            for (int i = 0; i < viewGroup.getChildCount(); i++) {
                View childView = viewGroup.getChildAt(i);
                if (childView instanceof TextView) {
                    ((TextView) childView).setTextDirection(View.TEXT_DIRECTION_RTL);
                } else if (childView instanceof ViewGroup) {
                    setRTLTextDirection((ViewGroup) childView);
                }
            }
        }
        private void setLTRTextDirection(ViewGroup viewGroup) {
            for (int i = 0; i < viewGroup.getChildCount(); i++) {
                View childView = viewGroup.getChildAt(i);
                if (childView instanceof TextView) {
                    ((TextView) childView).setTextDirection(View.TEXT_DIRECTION_LTR);
                } else if (childView instanceof ViewGroup) {
                    setLTRTextDirection((ViewGroup) childView);
                }
            }
    }
    
    • 上述代码在onConfigurationChanged方法中,根据layoutDirection的变化,通过setRTLTextDirectionsetLTRTextDirection方法遍历布局中的所有TextView,并相应地设置文本方向,以确保文本的显示符合布局方向。
  4. 适配不同地区文化习惯
    • layoutDirection属性是实现应用本地化和国际化的重要工具。不同地区和文化有不同的阅读和书写习惯,通过正确配置和使用layoutDirection,可以使应用在全球范围内提供更加友好和符合习惯的用户界面。
    • 除了语言相关的布局方向变化,有些应用可能还会根据用户的个性化设置(如用户手动选择布局方向)来使用layoutDirection属性,以提供更加灵活的界面布局选项。

22. 具体使用场景 - 屏幕布局相关配置变化(复合场景)

  1. 基本含义与用途
    • screenLayout是一个用于处理屏幕布局相关配置变化的属性。它主要用于在android:configChanges属性中指定当屏幕布局发生变化时,Activity应该如何响应。这些屏幕布局变化包括但不限于屏幕尺寸改变、屏幕密度变化、显示模式(如多窗口模式)的改变等情况。
  2. 与屏幕尺寸和方向的关系
    • 屏幕尺寸变化:当设备从一种屏幕尺寸(如手机屏幕)切换到另一种屏幕尺寸(如连接到外部显示器,或者在可折叠设备展开/折叠时),系统会检测到屏幕布局的改变。通过在android:configChanges中包含screenLayout,可以让Activity在这种情况下不被重建,而是在onConfigurationChanged方法中处理布局调整。例如,在一个支持外部显示器的应用中,当连接到外部显示器后,应用可以根据新的屏幕尺寸(通过screenLayout相关的配置信息来获取),在onConfigurationChanged方法中重新布局视图,如将原本在手机屏幕上紧凑显示的内容,在大屏幕上以更宽松、分栏的方式展示。
    • 屏幕方向改变:屏幕方向改变也会导致屏幕布局的变化。虽然单独处理屏幕方向改变可以使用orientation属性,但screenLayout也可以用于捕获这种变化并提供更全面的布局调整方案。例如,在横屏和竖屏模式下,不仅视图的方向会改变,而且可能需要根据屏幕的长宽比例重新分配空间给不同的视图。使用screenLayout可以在onConfigurationChanged方法中同时考虑屏幕方向和其他布局因素,如重新计算布局中的边距、间距,调整视图的大小和位置,以达到更好的视觉效果。
  3. 与屏幕密度和显示模式的关联
    • 屏幕密度变化:当屏幕密度改变时(如用户在设备设置中调整了屏幕分辨率,或者设备连接到不同密度的外部显示器),这也会影响屏幕布局。screenLayout可以帮助检测这种变化,并且在onConfigurationChanged方法中,可以根据新的屏幕密度来调整资源的加载和显示方式。例如,对于图像资源,根据新的屏幕密度加载合适分辨率的图像,对于文本内容,调整字体大小或行间距等,以确保在不同屏幕密度下布局的合理性和可读性。
    • 显示模式改变:在支持多窗口模式、画中画模式等特殊显示模式的设备上,屏幕布局会发生显著变化。screenLayout属性能够识别这些显示模式的改变。例如,当应用进入多窗口模式时,应用的窗口尺寸会变小,并且可能需要与其他应用共享屏幕空间。通过在android:configChanges中指定screenLayout,Activity可以在onConfigurationChanged方法中重新调整布局,如缩小视图尺寸、改变视图的堆叠顺序,或者调整某些功能的显示方式(如隐藏一些次要的视图元素,以节省空间),以适应新的显示模式。
  4. 在代码中的处理示例
    • 以下是一个简单的示例,展示在onConfigurationChanged方法中处理screenLayout相关变化的基本思路:
    import android.content.res.Configuration;
    import android.os.Bundle;
    import android.app.Activity;
    import android.util.DisplayMetrics;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.TextView;
    public class MainActivity extends Activity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
        @Override
        public void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
            if (newConfig.screenLayout!= Configuration.SCREENLAYOUT_SIZE_UNCHANGED) {
                // 屏幕布局发生变化
                if (newConfig.screenWidthDp!= 0 && newConfig.screenHeightDp!= 0) {
                    // 根据新的屏幕尺寸调整布局
                    int newScreenWidthDp = newConfig.screenWidthDp;
                    int newScreenHeightDp = newConfig.screenHeightDp;
                    ViewGroup rootView = findViewById(android.R.id.content);
                    adjustLayout(rootView, newScreenWidthDp, newScreenHeightDp);
                }
                if (newConfig.densityDpi!= 0) {
                    // 根据新的屏幕密度调整资源加载和显示
                    int newDensityDpi = newConfig.densityDpi;
                    adjustResourcesForDensity(newDensityDpi);
                }
                if ((newConfig.uiMode & Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_TELEVISION) {
                    // 如果是电视模式(一种特殊显示模式),进行相应调整
                    adjustForTelevisionMode();
                }
            }
        }
        private void adjustLayout(ViewGroup viewGroup, int newScreenWidthDp, int newScreenHeightDp) {
            for (int i = 0; i < viewGroup.getChildCount(); i++) {
                View childView = viewGroup.getChildAt(i);
                if (childView instanceof TextView) {
                    // 简单示例:调整TextView的宽度和高度
                    TextView textView = (TextView) childView;
                    ViewGroup.LayoutParams layoutParams = textView.getLayoutParams();
                    layoutParams.width = newScreenWidthDp / 2;
                    layoutParams.height = newScreenHeightDp / 4;
                    textView.setLayoutParams(layoutParams);
                } else if (childView instanceof ViewGroup) {
                    adjustLayout((ViewGroup) childView, newScreenWidthDp, newScreenHeightDp);
                }
            }
        }
        private void adjustResourcesForDensity(int newDensityDpi) {
            // 这里可以添加根据屏幕密度调整资源的逻辑
            // 例如,重新加载合适分辨率的图像资源
        }
        private void adjustForTelevisionMode() {
            // 这里可以添加在电视模式下调整布局或功能的逻辑
            // 例如,放大某些重要视图,隐藏不适合电视显示的元素
        }
    }
    
    • 在上述代码中,在onConfigurationChanged方法中首先检查screenLayout是否发生变化。如果变化了,进一步检查屏幕尺寸、屏幕密度和显示模式相关的属性。根据这些变化,通过adjustLayout方法调整视图布局,通过adjustResourcesForDensity方法处理资源与屏幕密度的适配,通过adjustForTelevisionMode方法处理特殊显示模式(电视模式)下的布局和功能调整。这只是一个简单的示例,实际应用中可能需要根据具体的应用需求进行更复杂的布局调整和资源管理。

23. 具体使用场景 - 设备的导航方式切换

  1. 基本概念与用途
    • 在Android开发中,navigation属性主要与设备的导航方式有关。它用于处理当设备的导航相关配置发生变化时,Activity如何响应的情况。这些导航配置变化可能包括虚拟导航栏(如屏幕底部的导航栏)的显示或隐藏、硬件导航按键(如实体按键)的可用性改变等。
  2. 与虚拟导航栏的关联
    • 在许多Android设备上,用户可以选择显示或隐藏虚拟导航栏。当用户在设备设置中进行这样的操作时,系统会认为这是一种配置变化。通过在android:configChanges中包含navigation属性,Activity可以在这种导航栏显示状态改变时不被重建,而是在onConfigurationChanged方法中处理布局调整。
    • 例如,当虚拟导航栏隐藏时,应用的可视区域会增大。在onConfigurationChanged方法中,应用可以利用这个额外的空间,如将原本位于屏幕底部可能被导航栏遮挡的视图(如一些操作按钮)重新布局,使其在新的可视区域内更好地展示,或者调整内容视图的大小,以填充更多的屏幕空间。
  3. 硬件导航按键可用性变化
    • 对于一些具有实体导航按键的设备,或者在某些特殊的设备模式下(如连接外部键盘时,可能会改变导航按键的使用方式),硬件导航按键的可用性可能会发生变化。navigation属性可以帮助检测这种变化。
    • 例如,当硬件导航按键不可用时,应用可能需要在屏幕上提供替代的导航方式(如通过在界面上显示虚拟的返回、主页等按钮)。在onConfigurationChanged方法中,根据导航按键可用性的改变,可以动态地显示或隐藏这些替代导航按钮,以确保用户始终能够方便地在应用内进行导航操作。
  4. 在代码中的处理示例
    • 以下是一个简单的示例,展示在onConfigurationChanged方法中处理navigation相关变化的思路:
    import android.content.res.Configuration;
    import android.os.Bundle;
    import android.app.Activity;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.Button;
    public class MainActivity extends Activity {
        private Button backButton;
        private Button homeButton;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            backButton = findViewById(R.id.back_button);
            homeButton = findViewById(R.id.home_button);
            // 初始时,根据硬件导航按键可用性设置按钮的可见性
            updateNavigationButtonsVisibility();
        }
        @Override
        public void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
            if (newConfig.navigation!= Configuration.NAVIGATION_NONAV) {
                // 导航相关配置发生变化
                if (newConfig.navigationHidden == Configuration.NAVIGATIONHIDDEN_YES) {
                    // 导航栏隐藏,调整布局
                    ViewGroup rootView = findViewById(android.R.id.content);
                    adjustLayoutForNavigationHidden(rootView);
                }
                // 根据硬件导航按键可用性更新按钮可见性
                updateNavigationButtonsVisibility();
            }
        }
        private void adjustLayoutForNavigationHidden(ViewGroup rootView) {
            // 简单示例:将底部的视图向上移动一点
            for (int i = 0; i < rootView.getChildCount(); i++) {
                View childView = rootView.getChildAt(i);
                if (childView.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
                    ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) childView.getLayoutParams();
                    layoutParams.bottomMargin = 0;
                    childView.setLayoutParams(layoutParams);
                }
            }
        }
        private void updateNavigationButtonsVisibility() {
            if (hasHardwareNavigationKeys()) {
                // 如果有硬件导航按键,隐藏虚拟导航按钮
                backButton.setVisibility(View.GONE);
                homeButton.setVisibility(View.GONE);
            } else {
                // 如果没有硬件导航按键,显示虚拟导航按钮
                backButton.setVisibility(View.VISIBLE);
                homeButton.setVisibility(View.VISIBLE);
            }
        }
        private boolean hasHardwareNavigationKeys() {
            // 检查设备是否有硬件导航按键的逻辑
            // 这可能需要根据设备的特定属性或通过系统API来确定
            return false;
        }
    }
    
    • 在上述代码中,在onCreate方法中初始化了用于虚拟导航的按钮,并根据硬件导航按键的可用性设置了它们的初始可见性。在onConfigurationChanged方法中,当navigation相关配置发生变化时,首先检查导航栏是否隐藏,如果隐藏,则通过adjustLayoutForNavigationHidden方法调整布局(这里只是简单地将底部视图的下边缘距设置为0)。然后,通过updateNavigationButtonsVisibility方法根据硬件导航按键的可用性更新虚拟导航按钮的可见性。需要注意的是,hasHardwareNavigationKeys方法中的检查设备是否有硬件导航按键的逻辑可能需要根据实际设备情况和系统API进行完善。

23. 具体使用场景 - 设备颜色模式相关的配置变化

  1. 基本含义与用途

    • colorMode属性主要用于处理设备颜色模式相关的配置变化。它用于在android:configChanges中指定当设备的颜色模式发生改变时,Activity应该如何响应。颜色模式变化包括系统主题中的颜色方案改变(如亮色模式和暗色模式的切换)、色彩增强或减弱模式(例如一些设备的护眼模式可能涉及颜色调整)等情况。
  2. 与系统主题颜色方案的关联

    • 亮色/暗色模式切换:在现代Android系统中,用户可以在设备设置中选择亮色主题或暗色主题。当这种主题切换发生时,系统会触发颜色模式的变化。如果在android:configChanges中包含colorMode,Activity可以在onConfigurationChanged方法中处理这种变化,而不是被重建。例如,在亮色模式下,应用的背景可能是白色,文本是黑色;而在暗色模式下,背景变为黑色,文本变为白色。在onConfigurationChanged方法中,可以遍历布局中的视图,根据新的颜色模式来调整视图的背景颜色、文本颜色等属性,以确保应用的界面在不同颜色模式下都具有良好的可读性和视觉效果。
    • 自定义主题颜色变化:除了系统提供的亮色/暗色模式,应用本身也可能支持自定义主题颜色。当用户在应用内更改主题颜色或者系统主题颜色与应用主题颜色相互影响时,colorMode可以帮助捕获这种变化。例如,一个具有多彩主题的应用,当用户从一种主题颜色切换到另一种主题颜色时,通过在onConfigurationChanged方法中处理colorMode相关的变化,可以更新界面上所有相关视图的颜色,使整个应用的界面风格保持一致。
  3. 与护眼模式及色彩调整功能的关系

    • 护眼模式启用/停用:许多设备都提供护眼模式,该模式通常会减少屏幕发出的蓝光,使屏幕颜色看起来更暖。当用户开启或关闭护眼模式时,这也会导致颜色模式的改变。通过处理colorMode的变化,应用可以调整颜色滤镜或者对某些颜色通道进行补偿,以适应护眼模式下的颜色显示。例如,在一个阅读应用中,当护眼模式开启时,可以适当降低白色背景的亮度,使文字看起来更加柔和,减轻眼睛疲劳。
    • 色彩增强/减弱功能:有些设备允许用户在系统设置中增强或减弱屏幕颜色的饱和度、对比度等参数。当这些设置发生变化时,colorMode属性可以帮助应用检测到这种变化,并在onConfigurationChanged方法中对界面颜色进行相应的调整。例如,对于一个图像编辑应用,当屏幕颜色饱和度增强时,应用内部的调色工具可能需要重新校准,以确保用户看到的颜色调整效果与实际应用的效果一致。
  4. 在代码中的处理示例

    • 以下是一个简单的示例,展示在onConfigurationChanged方法中处理colorMode相关变化的思路:
    import android.content.res.Configuration;
    import android.os.Bundle;
    import android.app.Activity;
    import android.view.View;
    import android.widget.TextView;
    import android.graphics.Color;
    public class MainActivity extends Activity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
        @Override
        public void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
            if (newConfig.colorMode!= Configuration.COLOR_MODE_DEFAULT) {
                // 颜色模式发生变化
                if ((newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES) {
                    // 假设夜间模式(暗色主题)开启
                    adjustForDarkMode();
                } else {
                    // 假设非夜间模式(亮色主题)开启
                    adjustForLightMode();
                }
                if (isEyeCareModeEnabled(newConfig)) {
                    // 假设护眼模式开启
                    adjustForEyeCareMode();
                }
            }
        }
        private void adjustForDarkMode() {
            View rootView = findViewById(android.R.id.content);
            adjustViewColorsForDarkMode(rootView);
        }
        private void adjustForLightMode() {
            View rootView = findViewById(android.R.id.content);
            adjustViewColorsForLightMode(rootView);
        }
        private void adjustViewColorsForDarkMode(View view) {
            if (view instanceof TextView) {
                TextView textView = (TextView) view;
                textView.setTextColor(Color.WHITE);
            }
            view.setBackgroundColor(Color.BLACK);
            if (view instanceof ViewGroup) {
                ViewGroup viewGroup = (ViewGroup) view;
                for (int i = 0; i < viewGroup.getChildCount(); i++) {
                    View childView = viewGroup.getChildAt(i);
                    adjustViewColorsForDarkMode(childView);
                }
            }
        }
        private void adjustViewColorsForLightMode(View view) {
            if (view instanceof TextView) {
                TextView textView = (TextView) view;
                textView.setTextColor(Color.BLACK);
            }
            view.setBackgroundColor(Color.WHITE);
            if (view instanceof ViewGroup) {
                ViewGroup viewGroup = (ViewGroup) view;
                for (int i = 0; i < viewGroup.getChildCount(); i++) {
                    View childView = viewGroup.getChildAt(i);
                    adjustViewColorsForLightMode(childView);
                }
        }
        private boolean isEyeCareModeEnabled(Configuration config) {
            // 检查护眼模式是否开启的逻辑
            // 这可能需要根据设备的特定属性或通过系统API来确定
            return false;
        }
        private void adjustForEyeCareMode() {
            // 调整颜色以适应护眼模式的逻辑
            // 例如,降低蓝色通道的强度
        }
    }
    
    • 在上述代码中,在onConfigurationChanged方法中首先检查colorMode是否发生变化。如果变化了,进一步检查是否是夜间模式(暗色主题)或护眼模式开启。根据不同的情况,通过adjustForDarkModeadjustForLightModeadjustForEyeCareMode方法来调整视图的颜色,以适应颜色模式的变化。需要注意的是,isEyeCareModeEnabled方法中的检查护眼模式是否开启的逻辑可能需要根据实际设备情况和系统API进行完善,adjustForEyeCareMode方法中的颜色调整逻辑也需要根据具体的护眼模式效果进行设计。

24. 具体使用场景 - 移动网络国家码相关的配置变化

  1. 基本概念
    • mcc是“Mobile Country Code(移动国家码)”的缩写。在移动网络中,它是用于识别移动用户所属国家的代码。在Android开发中,mcc属性用于处理与移动网络国家码相关的配置变化。这种变化通常是由于用户跨越国界,手机连接到不同国家的移动网络导致的。
  2. 配置变化场景
    • 网络漫游场景:当用户带着移动设备出国旅行并开启数据漫游时,设备会连接到当地的移动网络。此时,移动国家码(mcc)就会发生改变。如果在android:configChanges中配置了mcc,Activity可以在onConfigurationChanged方法中处理这种因国家码变化而带来的影响。例如,应用可能需要根据不同国家的法律法规、服务条款或商业策略,对某些功能进行调整。比如,对于一些受版权或地域限制的内容服务(如在线音乐、视频等),可能需要根据新的国家码来检查用户是否有访问权限,或者调整内容推荐策略以适应当地用户的喜好。
    • 双卡双待设备场景:在双卡双待设备中,当用户切换使用不同国家运营商的SIM卡用于数据连接时,也会导致mcc的改变。这可能会影响应用中与网络相关的操作,如网络请求的路由、根据运营商提供的增值服务来调整应用内的广告投放策略等。例如,某些广告商可能在不同国家有不同的合作运营商,应用可以根据mcc的变化来选择合适的广告合作伙伴。
  3. 在代码中的处理示例
    • 以下是一个简单的示例,展示在onConfigurationChanged方法中处理mcc变化的思路:
    import android.content.res.Configuration;
    import android.os.Bundle;
    import android.app.Activity;
    import android.telephony.TelephonyManager;
    public class MainActivity extends Activity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
        @Override
        public void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
            if (newConfig.mcc!= 0) {
                // mcc发生变化
                int newMcc = newConfig.mcc;
                // 根据新的mcc进行操作
                handleMccChange(newMcc);
            }
        }
        private void handleMccChange(int mcc) {
            TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
            String countryIso = telephonyManager.getNetworkCountryIso();
            // 根据国家码(mcc)和国家ISO代码进行功能调整
            if (mcc == 123) {  // 假设123是某个国家的mcc
                // 禁止某些功能
                disableSomeFeatures();
            } else if (mcc == 456) {  // 假设456是另一个国家的mcc
                // 启用某些增值服务
                enableValueAddedServices();
            }
        }
        private void disableSomeFeatures() {
            // 这里是禁止某些功能的具体逻辑
            // 例如,隐藏应用内的某些付费内容购买按钮
        }
        private void enableValueAddedServices() {
            // 这里是启用增值服务的具体逻辑
            // 例如,开启与当地运营商合作的流量提醒服务
        }
    }
    
    • 在上述代码中,在onConfigurationChanged方法中,当检测到mcc发生变化(newConfig.mcc不为0)时,通过handleMccChange方法来处理这种变化。在handleMccChange方法中,首先获取网络国家ISO代码,然后根据新的mcc值(这里只是简单地通过假设的mcc值来演示)来决定是禁止某些功能还是启用某些增值服务。实际应用中,需要根据真实的mcc分配情况以及应用的具体业务需求来进行更复杂的处理。

25. 具体使用场景 - 移动网络运营商变化

  1. 概念解释
    • mnc是“Mobile Network Code(移动网络码)”的缩写。它与mcc(移动国家码)一起用于识别移动用户所属的移动网络运营商。在一个国家(由mcc确定)内部,不同的移动网络运营商有不同的mnc。例如,在某个国家可能有多家移动运营商,如运营商A的mnc是01,运营商B的mnc是02等。
  2. 配置变化场景
    • 运营商网络切换:在单卡设备上,当用户手动切换移动网络运营商(比如从一家信号不好的运营商网络切换到另一家)或者由于网络信号覆盖等原因自动切换运营商网络时,mnc会发生改变。在双卡双待设备中,当用户在两个不同mnc的运营商卡之间切换用于数据连接的卡时,同样会导致mnc变化。如果在android:configChanges中配置了mnc,Activity可以在onConfigurationChanged方法中处理这种变化。
    • 网络优化和服务调整:不同的移动运营商可能提供不同的网络服务质量、网络速度以及增值服务。当mnc改变,应用可以根据新的运营商网络来优化网络请求策略。例如,对于一些对网络带宽要求较高的应用(如视频流应用),如果切换到一个网络速度更快的运营商网络(通过mnc识别),可以适当提高视频的分辨率;反之,如果切换到网络速度较慢的运营商,降低视频分辨率以避免卡顿。另外,运营商可能提供不同的短信网关、彩信服务等,应用中的消息发送功能可能需要根据mnc来调整发送参数。
  3. 与应用功能的关联及代码示例
    • 广告投放和计费策略调整:很多应用会根据用户的运营商来调整广告投放策略或者计费方式。例如,应用可能与某些运营商有合作,当用户接入这些合作运营商的网络(通过mnc识别)时,会展示特定的广告内容或者提供特殊的计费套餐(如通过运营商代扣费)。
    • 以下是一个简单的代码示例,展示在onConfigurationChanged方法中处理mnc变化的思路:
    import android.content.res.Configuration;
    import android.os.Bundle;
    import android.app.Activity;
    import android.telephony.TelephonyManager;
    public class MainActivity extends Activity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
        @Override
        public void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
            if (newConfig.mnc!= 0) {
                int newMnc = newConfig.mnc;
                handleMncChange(newMnc);
            }
        }
        private void handleMncChange(int mnc) {
            TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
            String networkOperator = telephonyManager.getNetworkOperator();
            // 根据mnc和网络运营商名称进行功能调整
            if (mnc == 1) {
                // 假设mnc为1是运营商A
                adjustForOperatorA();
            } else if (mnc == 2) {
                // 假设mnc为2是运营商B
                adjustForOperatorB();
            }
        }
        private void adjustForOperatorA() {
            // 针对运营商A调整广告投放策略
            changeAdvertisementStrategy("OperatorA");
            // 调整网络请求策略,例如提高网络请求优先级
            adjustNetworkRequestPriority("higher");
        }
        private void adjustForOperatorB() {
            // 针对运营商B调整广告投放策略
            changeAdvertisementStrategy("OperatorB");
            // 调整网络请求策略,例如降低网络请求优先级
            adjustNetworkRequestPriority("lower");
        }
        private void changeAdvertisementStrategy(String operator) {
            // 根据运营商改变广告投放策略的具体逻辑
            // 例如,加载与运营商相关的广告素材
        }
        private void adjustNetworkRequestPriority(String priority) {
            // 调整网络请求优先级的具体逻辑
            // 例如,设置网络请求的线程优先级
        }
    }
    
    • 在上述代码中,当onConfigurationChanged方法检测到mnc发生变化(newConfig.mnc不为0)时,通过handleMncChange方法处理这种变化。在handleMncChange方法中,获取网络运营商名称后,根据mnc的值(这里通过假设的mnc值来演示)来分别针对不同运营商(通过adjustForOperatorAadjustForOperatorB方法)调整广告投放策略和网络请求优先级等应用功能。实际应用中,需要根据真实的mnc分配情况以及应用与运营商的合作关系等因素来进行更细致的处理。

一般场景下使用需要配置

android:configChanges="orientation|keyboardHidden|navigation|screenSize|locale|layoutDirection|uiMode"
  1. orientation
    • 含义:用于处理屏幕方向的变化。在Android设备中,屏幕方向可以是竖屏(PORTRAIT)或横屏(LANDSCAPE)。当用户旋转设备时,屏幕方向会发生改变。
  2. keyboardHidden
    • 含义:主要用于处理键盘(特别是软键盘)的隐藏和显示状态的变化。当用户点击输入框,软键盘弹出;当用户完成输入或者点击返回键,软键盘隐藏。
  3. navigation
    • 含义:与设备的导航方式相关。这包括虚拟导航栏(屏幕底部的导航栏)的显示或隐藏,以及硬件导航按键可用性的改变。
  4. screenSize
    • 含义:用于处理屏幕大小的变化。这种变化可能是由于设备旋转(因为旋转后屏幕的物理尺寸在横纵方向上的利用方式改变),也可能是因为设备连接到外部显示器等情况导致。
  5. locale
    • 含义:与设备的语言区域设置有关。当用户在设备上更改语言设置时,locale配置会发生变化。
  6. layoutDirection
    • 含义:用于控制布局内文本和视图元素的方向,主要是从左到右(LTR)或从右到左(RTL)的布局方向。它与locale密切相关,因为不同的语言区域通常有不同的布局方向习惯。
  7. uiMode
    • 含义:用于处理用户界面模式的变化。这包括日间/夜间模式(亮色/暗色主题)的切换,以及设备可能处于的不同使用模式(如电视模式、车载模式等)。

参考地址

豆包AI 和 通义AI


原文地址:https://blog.csdn.net/weixin_35691921/article/details/143673878

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!