当有许多模块时,Locale确实可以工作。
上下文:
-
我们使用Crowdin(这个库在上下文之上应用包装器(
-
当只有一个模块时,该应用程序可以完美工作
-
使用Appcompat:1.2
-
当更改区域设置工作时
但是,当我在app
中添加新模块时,更改区域设置确实有效。implementation project(":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.java368行。还有第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);
}
}
解决方法是在你的基础活动中超越getDelegate
,如下所示:
private var baseContextWrappingDelegate: AppCompatDelegate? = null
override fun getDelegate() = baseContextWrappingDelegate ?: BaseContextWrappingDelegate(super.getDelegate()).apply {
baseContextWrappingDelegate = this
}
您还需要以下类(请参阅:迁移到Androidx后更改Locale不起作用(。
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
}
}
参考文献
https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx master dev/appcompat/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegateImpl.java#368
迁移到Androidx 后更改区域设置不起作用
https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx master dev/appcompat/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegateImpl.java#368