上下文或活动之外的 getString

Posted

技术标签:

【中文标题】上下文或活动之外的 getString【英文标题】:getString Outside of a Context or Activity 【发布时间】:2011-05-14 06:59:41 【问题描述】:

我发现R.string 非常棒,可以将硬编码字符串排除在我的代码之外,我想继续在一个实用程序类中使用它,该实用程序类与我的应用程序中的模型一起生成输出。例如,在这种情况下,我正在从活动之外的模型生成一封电子邮件。

是否可以在ContextActivity 之外使用getString?我想我可以通过当前活动,但这似乎没有必要。如果我错了,请纠正我!

编辑:我们可以使用Context访问资源吗?

【问题讨论】:

通过将上下文传递给将要使用该字符串的类,您还可以传递有关应用程序正在使用哪种语言(en、es 等)的信息。所以如果你有两个strings.xml,它会知道使用哪一个 【参考方案1】:

是的,我们可以不使用`Context`访问资源

你可以使用:

Resources.getSystem().getString(android.R.string.somecommonstuff)

... 在您的应用程序中的任何地方,即使是在静态常量声明中。 不幸的是,它只支持系统资源

对于本地资源,请使用this solution。这不是微不足道的,但它确实有效。

【讨论】:

系统资源是什么意思? strings.xml 是否是系统资源?对我来说它不起作用,说找不到资源。 设备上系统资源属于Android。 strings.xml 仅属于您的应用程序。寻找***.com/a/4391811/715269解决方案 对于那些访问字符串的工厂类来说,这是一个优雅的解决方案。我不喜欢到处传递上下文。对于我们真正想要全局存储字符串的情况,这只是不必要的混乱。 这比将上下文传递给一个类并使用它更有效吗?? 我收到此错误android.content.res.Resources$NotFoundException: String resource ID #0x7f0f0061【参考方案2】:

不幸的是,访问任何字符串资源的唯一方法是使用Context(即ActivityService)。在这种情况下,我通常所做的就是简单地要求调用者传入上下文。

【讨论】:

感谢您的提示!我刚试过这个,但由于某种原因,我在尝试时遇到了编译错误:ctx.getString(ctx.R.string.blah); 我会将参数设置为 Context 类型的 util 方法,以便您可以从 Activity 或 Service 中使用它。 您不需要ctx.R.string.blah,只需使用R.string.blah 我不确定symbol not found error 来自哪里,但请确保您已将R 导入到类的顶部。 答案是错误的。看下一个。 :-)【参考方案3】:

MyApplication,扩展Application

public static Resources resources;

MyApplicationonCreate

resources = getResources();

现在您可以在应用程序的任何位置使用此字段。

【讨论】:

它会通过服务工作吗? (特别是当 Android 杀死应用程序并只启动服务时) 是的,Android 通过调用 Application.onCreate 开始执行您的代码,然后运行您的服务。【参考方案4】:

##独特的方法

##App.getRes().getString(R.string.some_id)

这将适用于应用程序的任何地方。 (Util 类、Dialog、Fragment 或 您应用中的任何类)

(1) 创建或编辑(如果已经存在)您的 Application 类。

import android.app.Application;
import android.content.res.Resources;

public class App extends Application 
    private static App mInstance;
    private static Resources res;


    @Override
    public void onCreate() 
        super.onCreate();
        mInstance = this;
        res = getResources();
    

    public static App getInstance() 
        return mInstance;
    

    public static Resources getRes() 
        return res;
    


(2) 将名称字段添加到您的 manifest.xml <application 标记。

<application
        android:name=".App"
        ...
        >
        ...
    </application>

现在你可以走了。在应用中的任何位置使用App.getRes().getString(R.string.some_id)

【讨论】:

这已在 2010/2014 年 ***.com/a/4391811/2823074 中提出过建议 @Mikaelblomkvissson 应该删除吗? 其实,没有。有细微差别。与原始解决方案相反,您的解决方案不太容易发生内存泄漏。第一眼没注意到。【参考方案5】:

顺便说一句,symbol not found错误的原因之一可能是你的IDE导入了android.R;类而不是你的类。只需将 import android.R; 更改为 import your.namespace.R;

所以要让字符串在不同的类中可见的 2 件基本事情:

//make sure you are importing the right R class
import your.namespace.R;

//don't forget about the context
public void some_method(Context context) 
   context.getString(R.string.YOUR_STRING);

【讨论】:

【参考方案6】:

如果您有一个在活动中使用的类,并且希望访问该类中的资源,我建议您将上下文定义为类中的私有变量并在构造函数中对其进行初始化:

public class MyClass ()
    private Context context;

    public MyClass(Context context)
       this.context=context;
    

    public testResource()
       String s=context.getString(R.string.testString).toString();
    

在您的活动中立即上课:

MyClass m=new MyClass(this);

【讨论】:

【参考方案7】:

Khemraj 回应的最佳方法:

应用类

class App : Application() 

    companion object 
        lateinit var instance: Application
        lateinit var resourses: Resources
    


    // MARK: - Lifecycle

    override fun onCreate() 
        super.onCreate()
        instance = this
        resourses = resources
    


清单中的声明

<application
        android:name=".App"
        ...>
</application>     

常量类

class Localizations 

    companion object 
        val info = App.resourses.getString(R.string.info)
    


使用

textView.text = Localizations.info

【讨论】:

能否请您放大 'android:name=".App"' 部分? Android Studio 给出提示“在布局文件中发现意外文本:“android:name=".App"”。此外,在运行应用程序时,它在日志中显示“kotlin.UninitializedPropertyAccessException:lateinit 属性实例尚未初始化”。 【参考方案8】:

这应该可以让您从任何地方访问applicationContext,让您可以在任何可以使用它的地方获得applicationContextToastgetString()sharedPreferences

单身人士:

package com.domain.packagename;

import android.content.Context;

/**
 * Created by Versa on 10.09.15.
 */
public class ApplicationContextSingleton 
    private static PrefsContextSingleton mInstance;
    private Context context;

    public static ApplicationContextSingleton getInstance() 
        if (mInstance == null) mInstance = getSync();
        return mInstance;
    

    private static synchronized ApplicationContextSingleton getSync() 
        if (mInstance == null) mInstance = new PrefsContextSingleton();
        return mInstance;
    

    public void initialize(Context context) 
        this.context = context;
    

    public Context getApplicationContext() 
        return context;
    


Application 子类中初始化单例:

package com.domain.packagename;

import android.app.Application;

/**
 * Created by Versa on 25.08.15.
 */
public class mApplication extends Application 

    @Override
    public void onCreate() 
        super.onCreate();
        ApplicationContextSingleton.getInstance().initialize(this);
    

如果我没记错的话,这会给你一个到处都是 applicationContext 的钩子,用ApplicationContextSingleton.getInstance.getApplicationContext(); 调用它 您不需要在任何时候清除它,因为当应用程序关闭时,它无论如何都会随之而来。

记得更新AndroidManifest.xml 以使用这个Application 子类:

<?xml version="1.0" encoding="utf-8"?>

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

<application
    android:allowBackup="true"
    android:name=".mApplication" <!-- This is the important line -->
    android:label="@string/app_name"
    android:theme="@style/AppTheme"
    android:icon="@drawable/app_icon"
    >

如果您在这里发现任何问题,请告诉我,谢谢。 :)

【讨论】:

【参考方案9】:

您可以在 Kotlin 中执行此操作,方法是创建一个扩展 Application 的类,然后使用其上下文在代码中的任何位置调用资源

您的 App 类将如下所示

 class App : Application() 
    override fun onCreate() 
        super.onCreate()
        context = this
    

    companion object 
        var context: Context? = null
            private set
    

在 AndroidManifest.xml 中声明您的 Application 类(非常重要)

<application
        android:allowBackup="true"
        android:name=".App" //<--Your declaration Here
        ...>
        <activity
            android:name=".SplashActivity"  android:theme="@style/SplashTheme">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity android:name=".MainActivity"/>
    </application>

访问例如字符串文件使用以下代码

App.context?.resources?.getText(R.string.mystring)

【讨论】:

如果您在运行时以编程方式更改语言环境,这将不起作用,因为应用程序上下文是单例并且在您的进程启动时初始化。【参考方案10】:

不知何故不喜欢存储静态值的 hacky 解决方案,所以想出了一个更长但也可以测试的干净版本。

找到了两种可能的方法-

    将 context.resources 作为参数传递给您想要字符串资源的类。相当简单。如果无法作为参数传递,请使用 setter。

例如

data class MyModel(val resources: Resources) 
    fun getNameString(): String 
        resources.getString(R.string.someString)
    

    使用数据绑定(虽然需要片段/活动)

阅读前:本版本使用Data binding

XML-

<?xml version="1.0" encoding="utf-8"?>

<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">

<data>
    <variable
        name="someStringFetchedFromRes"
        type="String" />
</data>

<TextView
        android:layout_
        android:layout_
        android:text="@someStringFetchedFromRes" />
</layout>

活动/片段-

val binding = NameOfYourBinding.inflate(inflater)
binding.someStringFetchedFromRes = resources.getString(R.string.someStringFetchedFromRes)

有时,您需要根据模型中的字段更改文本。因此,您也可以对该模型进行数据绑定,并且由于您的活动/片段知道该模型,因此您可以很好地获取该值,然后基于该值对字符串进行数据绑定。

【讨论】:

【参考方案11】:

如果您想在上下文或活动之外使用 getString,您应该在构造函数或方法参数中包含上下文,以便您可以访问 getstring() 方法。 特别是在 Fragment 你应该确保 getActivity() 或 getContext() 不提供空值。 要避免片段中的 getActivity() 或 getContext() 出现 null,请尝试以下操作: 声明一个变量:

Context mContext;

现在覆盖 Fragment 的 onAttach 和 onDetach 方法:

@Override
public void onAttach(Context context) 
    super.onAttach(context);
    mContext = context;


@Override
public void onDetach() 
    super.onDetach();
    mContext = null;

现在在使用 getString() 方法的任何地方使用 mContext。 例如:

        Toast.makeText(mContext,  mContext.getString(R.string.sample_toast_from_string_file), Toast.LENGTH_SHORT).show();

【讨论】:

【参考方案12】:

Kotlin:完美决定 02.03.2021


AppCompatActivity 伴随对象

活动代码:

class MainActivity : AppCompatActivity() 

    companion object 
        lateinit var instance: AppCompatActivity
            private set
    

    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        instance = this
    


从 AnyWhere 获取资源:

val text = MainActivity.instance.getString(R.string.task_1)

P.S Vel_daN: 爱你所做的。

【讨论】:

此解决方案会导致内存泄漏,因为将 Activity(或任何其他系统组件)保存到静态变量中不允许垃圾收集器正确释放它。这被认为是一种不好的做法。【参考方案13】:

我用过 getContext().getApplicationContext().getString(R.string.nameOfString); 它对我有用。

【讨论】:

你认为getContext() 无处不在吗?! 这没有提供问题的答案,因为 getContext() 仅在活动和片段类中可用

以上是关于上下文或活动之外的 getString的主要内容,如果未能解决你的问题,请参考以下文章

类 [] 上的方法在 Grails 应用程序之外使用。如果在使用模拟 API 或引导 Grails 的测试上下文中正确运行

如何在回收站视图的 onBindViewHolder() 方法中调用 getString()?

为啥 Perl 文件 glob() 不能在标量上下文中的循环之外工作?

ApplicationContext或Activity Context是否适合Adapter?

从非活动类中获取上下文

如何正确调用上下文以启动 Activity