android - 添加许多模块时,区域设置的更改确实有效

标签 android kotlin locale android-context crowdin

当有很多模块时,Locale 确实有效。

上下文:

  • 我们使用 Crowdin(这个库在上下文之上应用了一个包装器)

  • 当只有一个模块时,该应用程序可以完美运行

  • 使用 Appcompat:1.2

  • 何时更改语言环境有效

但是,当我在 app 中添加一个新模块时,更改语言环境确实有效。 实现项目(":newmodule")

什么时候是单模块:

  • BaseContext = CrowdinContextWrapper

什么时候是多模块:

  • BaseContext = ContextThemeWrapper

Activity 扩展 BaseActivity

class MainActivity : BaseActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        Crowdin.forceUpdate(context = this)
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}
open class BaseActivity : AppCompatActivity() {
    override fun attachBaseContext(newBase: Context) {
        super.attachBaseContext(Crowdin.wrapContext(Localization.wrap(context = newBase)))
    }
}
class Localization(base: Context) : ContextThemeWrapper(base, R.style.AppTheme) {
    companion object {

        fun wrap(context: Context, language: String = "es", country: String = "MX"): ContextThemeWrapper {
            var ctx = context
            val config = context.resources.configuration

            if (language != "") {
                val locale = Locale(language, country)
                Locale.setDefault(locale)
                config.setLocale(locale)
                // Used setLayoutDirection for RTL and LTR
                config.setLayoutDirection(locale)
                ctx = context.createConfigurationContext(config)

            }

            return Localization(ctx)
        }
    }
}

最佳答案

解释

问题与 Appcompat 有关。根据 AppCompat 的版本,有两种不同的修复方法。由于您使用的是 1.2.0,因此您必须实现该版本。

AppCompatDelegateImpl 最终删除了语言环境,因为本质上是一个 ContextThemeWrapper包裹你的 ContextWrapper .查看实现 @ AppCompatDelegateImpl.java line 368 .也行 388 , 和 480 .

try {
                ContextThemeWrapperCompatApi17Impl.applyOverrideConfiguration(
                        (android.view.ContextThemeWrapper) baseContext, config);
                return baseContext;
            } catch (IllegalStateException e) {
                if (DEBUG) {
                    Log.d(TAG, "Failed to apply configuration to base context", e);
                }
            }

解决方法是在您的 Base Activity 中覆盖 getDelegate,如下所示:

private var baseContextWrappingDelegate: AppCompatDelegate? = null

override fun getDelegate() = baseContextWrappingDelegate ?: BaseContextWrappingDelegate(super.getDelegate()).apply {
    baseContextWrappingDelegate = this
}

并且您还需要以下类(参见:Change Locale not work after migrate to Androidx)。

package androidx.appcompat.app

import android.content.Context
import android.content.res.Configuration
import android.os.Bundle
import android.util.AttributeSet
import android.view.MenuInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.view.ActionMode
import androidx.appcompat.widget.Toolbar

class BaseContextWrappingDelegate(private val superDelegate: AppCompatDelegate) : AppCompatDelegate() {

    override fun getSupportActionBar() = superDelegate.supportActionBar

    override fun setSupportActionBar(toolbar: Toolbar?) = superDelegate.setSupportActionBar(toolbar)

    override fun getMenuInflater(): MenuInflater? = superDelegate.menuInflater

    override fun onCreate(savedInstanceState: Bundle?) {
        superDelegate.onCreate(savedInstanceState)
        removeActivityDelegate(superDelegate)
        addActiveDelegate(this)
    }

    override fun onPostCreate(savedInstanceState: Bundle?) = superDelegate.onPostCreate(savedInstanceState)

    override fun onConfigurationChanged(newConfig: Configuration?) = superDelegate.onConfigurationChanged(newConfig)

    override fun onStart() = superDelegate.onStart()

    override fun onStop() = superDelegate.onStop()

    override fun onPostResume() = superDelegate.onPostResume()

    override fun setTheme(themeResId: Int) = superDelegate.setTheme(themeResId)

    override fun <T : View?> findViewById(id: Int) = superDelegate.findViewById<T>(id)

    override fun setContentView(v: View?) = superDelegate.setContentView(v)

    override fun setContentView(resId: Int) = superDelegate.setContentView(resId)

    override fun setContentView(v: View?, lp: ViewGroup.LayoutParams?) = superDelegate.setContentView(v, lp)

    override fun addContentView(v: View?, lp: ViewGroup.LayoutParams?) = superDelegate.addContentView(v, lp)

    override fun attachBaseContext2(context: Context) = wrap(superDelegate.attachBaseContext2(super.attachBaseContext2(context)))

    override fun setTitle(title: CharSequence?) = superDelegate.setTitle(title)

    override fun invalidateOptionsMenu() = superDelegate.invalidateOptionsMenu()

    override fun onDestroy() {
        superDelegate.onDestroy()
        removeActivityDelegate(this)
    }

    override fun getDrawerToggleDelegate() = superDelegate.drawerToggleDelegate

    override fun requestWindowFeature(featureId: Int) = superDelegate.requestWindowFeature(featureId)

    override fun hasWindowFeature(featureId: Int) = superDelegate.hasWindowFeature(featureId)

    override fun startSupportActionMode(callback: ActionMode.Callback) = superDelegate.startSupportActionMode(callback)

    override fun installViewFactory() = superDelegate.installViewFactory()

    override fun createView(parent: View?, name: String?, context: Context, attrs: AttributeSet): View? = superDelegate.createView(parent, name, context, attrs)

    override fun setHandleNativeActionModesEnabled(enabled: Boolean) {
        superDelegate.isHandleNativeActionModesEnabled = enabled
    }

    override fun isHandleNativeActionModesEnabled() = superDelegate.isHandleNativeActionModesEnabled

    override fun onSaveInstanceState(outState: Bundle?) = superDelegate.onSaveInstanceState(outState)

    override fun applyDayNight() = superDelegate.applyDayNight()

    override fun setLocalNightMode(mode: Int) {
        superDelegate.localNightMode = mode
    }

    override fun getLocalNightMode() = superDelegate.localNightMode

    private fun wrap(context: Context): Context {
        //Put wrapping implementation here
    }
}

引用资料

  1. https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-master-dev/appcompat/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegateImpl.java#368

  2. Change Locale not work after migrate to Androidx

  3. https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-master-dev/appcompat/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegateImpl.java#368

关于android - 添加许多模块时,区域设置的更改确实有效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64452898/

相关文章:

types - Kotlin赋值运算符重载和类型转换

android - 在 Android 应用程序中使用自定义语言环境

java - 如何将Java中的 "1,234.56"解析为Double?

java - 如何获取 Android 中的所有联系人并忽略仅电子邮件联系人

android - 创建 Facebook session 对象并从中记录

Kotlin 在最后一个空格分割字符串

java - 无法在服务中接收用户区域设置

android - 如何在不降低分辨率的情况下避免位图上的内存不足错误

android - Windows 根本无法识别 Galaxy S2

generics - Kotlin 反射/解析泛型模板参数的原始类型