简体   繁体   English

如何知道 Activity 上哪些配置已更改?

[英]How to know which configuration has been changed on an Activity?

onConfigurationChanged method get called on an Activity by the system when there is(are) any changes in the configuration.当配置中有任何更改时,系统会在Activity上调用onConfigurationChanged方法。 This method only get called for those configurations which are defined in the manifest by the configChanges attribute.此方法仅在清单中由configChanges属性定义的那些配置中调用。

I have multiple configurations (orientation|screenSize) defined in this configChanges attribute and I want to detect which configuration(s) has been changed so that I can do some work based on that change, how can I achieve this?我在此configChanges属性中定义了多个配置 (orientation|screenSize),我想检测哪些配置已更改,以便我可以根据该更改做一些工作,我该如何实现?

To solve this I have following code snippet:为了解决这个问题,我有以下代码片段:

public class MyActivity extends AppCompatActivity {
    private final String TAG = "my-activity";

    private Configuration prevConfig;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    protected void onResume () {
        super.onResume();
        prevConfig = new Configuration(getResources().getConfiguration());
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        int diff = newConfig.diff(prevConfig);

        if(((diff & ActivityInfo.CONFIG_ORIENTATION) != 0)
                || ((diff & ActivityInfo.CONFIG_SCREEN_SIZE) != 0)) {
            Log.d(TAG, "Orientation or Screen size has been changed.");
        }

        // other configuration change checking goes here

        prevConfig = new Configuration(newConfig);
    }
}

By this I can detect which configuration has been changed.通过这个我可以检测到哪个配置被改变了。

I want to know if this is the best way to achieve the goal?我想知道这是否是实现目标的最佳方式?

How to know which configuration has been changed on an Activity?如何知道 Activity 上哪些配置已更改?

To simplify the problem.为了简化问题。 You don't have to define configChanges in AndroidManifest.xml if you don't want to take control yourself when configurations changed.如果您不想在配置更改时自行控制,则不必在 AndroidManifest.xml 中定义configChanges

The way I used is just override the onSaveInstanceState to store the Configuration before the activity being killed, and then restore it to a property like yours as prevConfig .我使用的方式只是覆盖onSaveInstanceState以在活动被杀死之前存储配置,然后将其恢复到像你这样的属性prevConfig Since android.content.res.Configuration is a kind of Parcelable.由于android.content.res.Configuration是一种 Parcelable。 It is very easy to put it into the Bundle by calling putParcelable and recover it on onCreate .通过调用putParcelable将其放入Bundle并在onCreate上恢复它非常容易。

By doing so, You will get two Configuration in onCreate() .通过这样做,您将在onCreate()中获得两个Configuration You get the previous one from the Bundle savedInstanceState and the current the from Activity.getResources().getConfiguration() .您从 Bundle savedInstanceState获得前一个,从Activity.getResources().getConfiguration()获得当前。 The Configuration has a public method diff , which we can use it to return a bit mask of the differences between them. Configuration有一个公共方法diff ,我们可以使用它来返回它们之间差异的位掩码。

To me, the most important thing is how to distinguish the bit mask easily.对我来说,最重要的是如何轻松区分位掩码。 Fortunately, there is a method from the official repo we can referenced.幸运的是,我们可以参考官方 repo 中的一种方法 It's static and also public.它是 static 并且也是公开的。 But we can't call it because of the hide annotation in JavaDoc.但是由于JavaDoc中的hide注解,我们不能调用它。 So, my first try was using reflection to invoke the method.所以,我的第一次尝试是使用反射来调用该方法。 It seems like the method is completely removed from the SDK due to the exception that occurred.由于发生的异常,该方法似乎已从 SDK 中完全删除。 After looking at the source.看了源码之后。 I just copy it to my own sources.我只是将它复制到我自己的来源。 Coping seems like a bad idea.应对似乎是个坏主意。 But, again.但是,再一次。 It's a public static method, So it is not too difficult to copy and easy to maintain.是一个公开的static方法,所以复制起来并不难,而且容易维护。

Here is my solution written in Kotlin.这是我用 Kotlin 编写的解决方案。

package com.example.android.configchangeapp

import android.content.pm.ActivityInfo
import android.content.res.Configuration
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity

class MainActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val config = resources.configuration
        val prevConfig = savedInstanceState?.getParcelable<Configuration>("config")
        if (prevConfig != null) {
            val diff = config.diff(prevConfig)
            val diffString = configurationDiffToString(diff)
            Log.d(TAG, "diff: $diffString")
        }
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        outState.putParcelable("config", resources.configuration)
    }

    companion object {
        const val TAG = "MainActivity"

        fun configurationDiffToString(diff: Int): String {
            val list = ArrayList<String>()
            if (diff and ActivityInfo.CONFIG_MCC != 0) {
                list.add("CONFIG_MCC")
            }
            if (diff and ActivityInfo.CONFIG_MNC != 0) {
                list.add("CONFIG_MNC")
            }
            if (diff and ActivityInfo.CONFIG_LOCALE != 0) {
                list.add("CONFIG_LOCALE")
            }
            if (diff and ActivityInfo.CONFIG_TOUCHSCREEN != 0) {
                list.add("CONFIG_TOUCHSCREEN")
            }
            if (diff and ActivityInfo.CONFIG_KEYBOARD != 0) {
                list.add("CONFIG_KEYBOARD")
            }
            if (diff and ActivityInfo.CONFIG_KEYBOARD_HIDDEN != 0) {
                list.add("CONFIG_KEYBOARD_HIDDEN")
            }
            if (diff and ActivityInfo.CONFIG_NAVIGATION != 0) {
                list.add("CONFIG_NAVIGATION")
            }
            if (diff and ActivityInfo.CONFIG_ORIENTATION != 0) {
                list.add("CONFIG_ORIENTATION")
            }
            if (diff and ActivityInfo.CONFIG_SCREEN_LAYOUT != 0) {
                list.add("CONFIG_SCREEN_LAYOUT")
            }
            if (diff and ActivityInfo.CONFIG_COLOR_MODE != 0) {
                list.add("CONFIG_COLOR_MODE")
            }
            if (diff and ActivityInfo.CONFIG_UI_MODE != 0) {
                list.add("CONFIG_UI_MODE")
            }
            if (diff and ActivityInfo.CONFIG_SCREEN_SIZE != 0) {
                list.add("CONFIG_SCREEN_SIZE")
            }
            if (diff and ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE != 0) {
                list.add("CONFIG_SMALLEST_SCREEN_SIZE")
            }
            if (diff and ActivityInfo.CONFIG_DENSITY != 0) {
                list.add("CONFIG_DENSITY")
            }
            if (diff and ActivityInfo.CONFIG_LAYOUT_DIRECTION != 0) {
                list.add("CONFIG_LAYOUT_DIRECTION")
            }
            if (diff and ActivityInfo.CONFIG_FONT_SCALE != 0) {
                list.add("CONFIG_FONT_SCALE")
            }
            if (diff and ActivityInfo.CONFIG_FONT_WEIGHT_ADJUSTMENT != 0) {
                list.add("CONFIG_AUTO_BOLD_TEXT")
            }

            return buildString {
                append("{")
                append(list.joinToString(", "))
                append("}")
            }
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM