- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我有一个支持多语言的旧项目。我要升级支持库和目标平台,在迁移到 Androidx
之前一切正常,但现在更改语言不起作用!
我使用此代码更改 App 的默认语言环境
private static Context updateResources(Context context, String language)
{
Locale locale = new Locale(language);
Locale.setDefault(locale);
Configuration configuration = context.getResources().getConfiguration();
configuration.setLocale(locale);
return context.createConfigurationContext(configuration);
}
attachBaseContext
在每个 Activity 上调用此方法像这样:
@Override
protected void attachBaseContext(Context newBase)
{
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
String language = preferences.getString(SELECTED_LANGUAGE, "fa");
super.attachBaseContext(updateResources(newBase, language));
}
getActivity().getBaseContext().getString
工作和
getActivity().getString
不行。甚至下面的代码也不起作用并且总是显示
app_name
默认资源 string.xml 中的值。
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/app_name"/>
getActivity()..getResources().getIdentifier
不起作用,总是返回 0!
最佳答案
2020 年 8 月 21 日更新:
AppCompat 1.2.0 终于发布了。如果您不使用 ContextWrapper
或 ContextThemeWrapper
根本没有其他事情可做,您应该能够从 1.1.0 中删除任何解决方法!
如果您确实使用 ContextWrapper
或 ContextThemeWrapper
里面 attachBaseContext
, 语言环境更改将中断,因为当您将包装的上下文传递给 super 时,
AppCompatActivity
进行内部调用,将您的 ContextWrapper
包装起来在另一个 ContextThemeWrapper
, ContextThemeWrapper
,将其配置覆盖为空白,类似于 1.1.0 中发生的情况。 AppCompatDelegateImpl
总是以剥离语言环境而告终。最大的障碍是,与 1.1.0 不同,
applyOverrideConfiguration
在您的基本上下文而不是您的主机 Activity 上调用,因此您不能像在 1.1.0 中那样在 Activity 中覆盖该方法并修复语言环境。我知道的唯一可行的解决方案是通过覆盖
getDelegate()
来反转包装。确保您的包装和/或语言环境覆盖在最后。首先,添加下面的类:
androidx.appcompat.app
包内,因为唯一现有的
AppCompatDelegate
构造函数是包私有(private)的)
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 {
TODO("your wrapping implementation here")
}
}
然后在我们的基本 Activity 类中删除所有 1.1.0 解决方法并简单地添加:
private var baseContextWrappingDelegate: AppCompatDelegate? = null
override fun getDelegate() = baseContextWrappingDelegate ?: BaseContextWrappingDelegate(super.getDelegate()).apply {
baseContextWrappingDelegate = this
}
取决于
ContextWrapper
您正在使用的实现,配置更改可能会破坏主题或语言环境的更改。要解决此问题,请另外添加以下内容:
override fun createConfigurationContext(overrideConfiguration: Configuration) : Context {
val context = super.createConfigurationContext(overrideConfiguration)
TODO("your wrapping implementation here")
}
而且你很好!您可以期待 Google 在 1.3.0 中再次打破这一点。我会在那里修好它……再见,太空牛仔!
attachBaseContext
中正确设置了配置时,
AppCompatDelegateImpl
然后将配置覆盖为没有语言环境的全新配置:
final Configuration conf = new Configuration();
conf.uiMode = newNightMode | (conf.uiMode & ~Configuration.UI_MODE_NIGHT_MASK);
try {
...
((android.view.ContextThemeWrapper) mHost).applyOverrideConfiguration(conf);
handled = true;
} catch (IllegalStateException e) {
...
}
In an unreleased commit by Chris Banes这实际上是固定的:新配置是基本上下文配置的深拷贝。
final Configuration conf = new Configuration(baseConfiguration);
conf.uiMode = newNightMode | (conf.uiMode & ~Configuration.UI_MODE_NIGHT_MASK);
try {
...
((android.view.ContextThemeWrapper) mHost).applyOverrideConfiguration(conf);
handled = true;
} catch (IllegalStateException e) {
...
}
在此版本发布之前,可以手动执行完全相同的操作。要继续使用 1.1.0 版,请将其添加到您的
attachBaseContext
下方。 :
override fun applyOverrideConfiguration(overrideConfiguration: Configuration?) {
if (overrideConfiguration != null) {
val uiMode = overrideConfiguration.uiMode
overrideConfiguration.setTo(baseContext.resources.configuration)
overrideConfiguration.uiMode = uiMode
}
super.applyOverrideConfiguration(overrideConfiguration)
}
Java解决方案
@Override
public void applyOverrideConfiguration(Configuration overrideConfiguration) {
if (overrideConfiguration != null) {
int uiMode = overrideConfiguration.uiMode;
overrideConfiguration.setTo(getBaseContext().getResources().getConfiguration());
overrideConfiguration.uiMode = uiMode;
}
super.applyOverrideConfiguration(overrideConfiguration);
}
这段代码的作用与
Configuration(baseConfiguration)
完全相同。确实在引擎盖下,但是因为我们是在
AppCompatDelegate
之后做的已经设置了正确的
uiMode
,我们必须确保采用被覆盖的
uiMode
在我们修复它之后结束,这样我们就不会丢失暗/亮模式设置。
configChanges="uiMode"
,这只会自行起作用在你的 list 里面。如果你这样做了,那么还有另一个错误:内部
onConfigurationChanged
newConfig.uiMode
不会被
AppCompatDelegateImpl
设置的
onConfigurationChanged
.如果您复制所有代码
AppCompatDelegateImpl
,也可以修复此问题。用于计算当前夜间模式到您的基本 Activity 代码,然后在
super.onConfigurationChanged
之前覆盖它称呼。在 Kotlin 中,它看起来像这样:
private var activityHandlesUiMode = false
private var activityHandlesUiModeChecked = false
private val isActivityManifestHandlingUiMode: Boolean
get() {
if (!activityHandlesUiModeChecked) {
val pm = packageManager ?: return false
activityHandlesUiMode = try {
val info = pm.getActivityInfo(ComponentName(this, javaClass), 0)
info.configChanges and ActivityInfo.CONFIG_UI_MODE != 0
} catch (e: PackageManager.NameNotFoundException) {
false
}
}
activityHandlesUiModeChecked = true
return activityHandlesUiMode
}
override fun onConfigurationChanged(newConfig: Configuration) {
if (isActivityManifestHandlingUiMode) {
val nightMode = if (delegate.localNightMode != AppCompatDelegate.MODE_NIGHT_UNSPECIFIED)
delegate.localNightMode
else
AppCompatDelegate.getDefaultNightMode()
val configNightMode = when (nightMode) {
AppCompatDelegate.MODE_NIGHT_YES -> Configuration.UI_MODE_NIGHT_YES
AppCompatDelegate.MODE_NIGHT_NO -> Configuration.UI_MODE_NIGHT_NO
else -> applicationContext.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
}
newConfig.uiMode = configNightMode or (newConfig.uiMode and Configuration.UI_MODE_NIGHT_MASK.inv())
}
super.onConfigurationChanged(newConfig)
}
关于android - 迁移到 Androidx 后更改区域设置不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55265834/
我最近开始从事一个 Sails 项目。它目前在迁移表下具有以下格式的迁移。 20160826122004-create_users_table.js 'use strict'; module.expo
当我尝试迁移时 doctrine:migrations:migrate ,我收到此异常:“元数据存储不是最新的,请运行 sync-metadata-storage 命令来解决此问题。”。这仅在尝试在生
我在 ec2 linux 7 上有一个 MarkLogic 服务器。我想将它迁移到 linux 6。我将 ebs 移动到新的 linux 6 并将其安装在 /var/opt/MarkLogic . 我
我对 OpenID 很好奇。虽然我同意统一凭证的想法很棒,但我有一些保留意见。什么是防止 OpenID 提供商发疯并持有他们拥有的 OpenID 帐户直到您支付 n 美元?如果我决定不喜欢这个提供商,
使用 SQL 很容易做到这一点,但我需要编写一个我不熟悉的 Knex 迁移脚本。以下代码在 order 表中行的末尾添加了 order_id 列。我想在 id 之后添加 order_id。我该怎么做?
使用 SQL 很容易做到这一点,但我需要编写一个我不熟悉的 Knex 迁移脚本。以下代码在 order 表中行的末尾添加了 order_id 列。我想在 id 之后添加 order_id。我该怎么做?
我想通过在 Yii2 中的迁移添加一个新列,使用以下代码: public function up() { $this->addColumn('news', 'priority', $this-
我正在尝试在 SQLDelight 的表中添加更多列。我做了一个迁移文件 1.sqm .在迁移文件中,它给出了找不到表的错误。 我的 build.gradle.kts: sqldelight {
我有一个与 Flyway DB 迁移相关的问题。通常如何管理处理相同 DB 模式的多个项目(微服务)。每个项目中的 Flyway 迁移脚本如果被其他项目修改,则不允许启动。他们是否有任何文档或最佳实践
我是 Laravel 的新手。我做了一份待办事项申请作为一项学校作业。我们必须使用迁移来创建我们的数据库。 我使用迁移创建了 2 个表。我的问题是:如果你第一次在你的电脑上运行这个项目,有没有办法自动
我正在尝试在 Laravel 中创建外键,但是当我使用 artisan 迁移表时,出现以下错误: [Illuminate\Database\QueryException] SQLSTATE[HY000
我从 Django 1.7 升级到 Django 1.9。我有多次迁移。升级后我无法再创建新的数据库。 问题是“django manage.py migrate”运行检查。检查导入应用程序 URL。这
我在创建数据迁移方面遇到了困难。我的应用程序使用两个数据库。我在 settings.py 中配置了数据库,并创建了一个像 Django docs 中一样的路由器. # settings.py DB_H
我有一个像这样的sql结构: CREATE TABLE resources ( id SERIAL PRIMARY KEY, title TEXT NOT NULL, created_at
我正在尝试使用模式构建器向表添加枚举选项(不丢失当前数据集)。 我真正能够找到的关于列更改的唯一信息是 http://www.flipflops.org/2013/05/25/modify-an-ex
我尝试转移到一些 CMake 程序中,并且有一个从 xml 生成头文件的函数。 生成文件.am adaptor_glue.hpp: dbus_introspect.xml $(DBUSXX_X
我想将文件移至我的 iOS 应用程序的 CoreData 存储 ../Library/Application Support/MyApp/ 至 ../Documents/Stores/ 我可以使用 N
有没有人对数据迁移进出 NetSuite 有丰富的经验?我必须将 DB2 表导出到 MySQL,处理数据,然后导出到一个 CSV 文件中。然后获取帐户的 CSV 文件并再次操作数据以使帐户从我们的旧系
我正在尝试在 Django 上建立一个博客。我已经走到了创建模型的地步。他们在这里: from django.db import models import uuid class Users(mode
我最近使用 bluehost 上的 AutoSSL 工具将网站迁移到 HTTPS。我在内容中看到一些失真,例如缺少背景颜色、表格位移、缺少_logos 等。 有谁知道 HTTPS 迁移效果如何影响样式
我是一名优秀的程序员,十分优秀!