getString 在上下文或 Activity 之外

getString Outside of a Context or Activity

提问人:SapphireSun 提问时间:11/23/2010 最后编辑:StackExchange What The HeckSapphireSun 更新时间:11/17/2023 访问量:226040

问:

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

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

编辑:我们可以在不使用的情况下访问资源吗?Context

java 字符串 android-resources android-context

评论

5赞 sports 8/11/2014
通过将上下文传递给将要使用该字符串的类,还可以传递有关应用正在使用的语言(en、es 等)的信息。因此,如果您有两个字符串.xml,它将知道使用哪一个

答:

114赞 Erich Douglass 11/23/2010 #1

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

评论

4赞 SapphireSun 11/23/2010
谢谢你的提示!我刚刚尝试过这个,但由于某种原因,我在尝试时遇到了编译错误:ctx.getString(ctx.R.string.blah);
0赞 Tyler 11/23/2010
我会将参数设置为类型的 util 方法,以便您可以从 Activity 或 Service 中使用它。Context
3赞 Pentium10 11/23/2010
你不需要 ,只需使用ctx.R.string.blahR.string.blah
2赞 Pentium10 11/23/2010
我不确定从哪里来,但请确保您已在类中导入。symbol not found errorR
11赞 Gangnus 1/7/2012
答案是假的。是下一个。:-)
570赞 Gangnus 1/7/2012 #2

是的,我们可以在不使用“上下文”的情况下访问资源

您可以使用:

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

...在应用程序的任何位置,甚至在静态常量声明中。 不幸的是,它仅支持系统资源

对于本地资源,请使用此解决方案。这不是微不足道的,但它是有效的。

评论

33赞 kirhgoff 3/15/2013
系统资源是什么意思?字符串.xml是否是系统资源?对我来说,它不起作用,说找不到资源。
10赞 Gangnus 3/15/2013
系统资源属于设备上的 Android。字符串.xml 仅属于您的应用程序。寻找 stackoverflow.com/a/4391811/715269 解决方案
4赞 Jay Snayder 4/19/2013
对于访问字符串时的 Factory 类,这是一个优雅的解决方案。我不喜欢到处传递 Context。对于我们实际上只想全局存储字符串的情况来说,这只是不必要的混乱。
1赞 SoliQuiD 10/28/2015
这是否比将上下文传递给类并使用它更有效?
16赞 Ebrahim Karimi 8/16/2019
我收到此错误android.content.res.Resources$NotFoundException: String resource ID #0x7f0f0061
26赞 Jan Naruszkiewicz 5/24/2012 #3

顺便说一句,找不到符号错误的原因之一可能是您的 IDE 导入了 android。R;类而不是你的类。只需更改导入android即可。R;导入 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);
}
-11赞 vivynz 2/16/2015 #4

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

评论

18赞 Hamzeh Soboh 6/27/2015
你认为到处都可以使用吗?!getContext()
1赞 Umar Ata 1/19/2017
这并不能提供问题的答案,因为 getContext() 仅在 activites 和 fragments 类中可用
43赞 konmik 3/11/2015 #5

在 中,它扩展了:MyApplicationApplication

public static Resources resources;

在 的 :MyApplicationonCreate

resources = getResources();

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

评论

0赞 Atul 4/17/2016
它会通过服务起作用吗?(尤其是当Android杀死应用程序并仅启动服务时)
1赞 konmik 4/18/2016
是的,Android 通过调用 Application.onCreate 开始执行您的代码,然后运行您的服务。
1赞 Versa 9/25/2015 #6

这应该可以让您从任何地方访问,从而让您到达任何可以使用它的地方;等。applicationContextapplicationContextToastgetString()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;
    }

}

初始化子类中的 Singleton: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.xmlApplication

<?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"
    >

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

4赞 Malus Jan 3/13/2016 #7

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

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);
33赞 Khemraj Sharma 7/11/2018 #8

##独特的方法

##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)

评论

0赞 Mikaelblomkvistsson 3/16/2021
这在2010/2014年已经提出 stackoverflow.com/a/4391811/2823074
0赞 Khemraj Sharma 3/17/2021
@Mikaelblomkvistsson 应该删除吗?
0赞 Mikaelblomkvistsson 3/19/2021
其实不然。略有不同。与原始解决方案相反,您的解决方案不太容易发生内存泄漏。我乍一看没有注意到它。
6赞 Mickael Belhassen 2/14/2019 #9

Khemraj 回应的最佳方法:

App 类

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>     

Constants 类

class Localizations {

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

}

textView.text = Localizations.info

评论

0赞 jonadv 7/19/2021
你能放大'android:name='吗?App“的部分?Android Studio 提示“在布局文件中发现意外文本:”android:name=”。应用程序“”。此外,在运行该应用程序时,它说“kotlin。UninitializedPropertyAccessException:日志中尚未初始化 lateinit 属性实例。
0赞 Rajkiran 12/19/2019 #10

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

找到了 2 种可能的方法来做到这一点——

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

例如

data class MyModel(val resources: Resources) {
    fun getNameString(): String {
        resources.getString(R.string.someString)
    }
}
  1. 使用数据绑定(但需要片段/活动)

阅读前:此版本使用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_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@{someStringFetchedFromRes}" />
</layout>

活动/片段-

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

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

3赞 Ahmed Raza 12/29/2019 #11

您可以在 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)

评论

0赞 Szörényi Ádám 1/31/2020
如果在运行时以编程方式更改区域设置,这将不起作用,因为应用程序上下文是单一实例,并在进程启动时初始化。
-4赞 Владислав Шестернин 3/3/2021 #12
  • AppCompatActivity
  • Companion 对象

活动代码:

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)

评论

5赞 r4zzz4k 3/3/2021
此解决方案会导致内存泄漏,因为将 Activity(或任何其他系统组件)保存到静态变量中会不允许垃圾回收器正确释放它。这被认为是一种不好的做法。
0赞 MANISH 12/24/2021 #13

如果要在上下文或 Activity 之外使用 getString,则应在构造函数或方法参数中具有上下文,以便可以访问 getstring() 方法。 特别是在 Fragment 中,您应该确保 getActivity() 或 getContext() 未提供 null 值。 要避免 Fragment 中 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();
3赞 Maddy Sharma 6/24/2022 #14

内部活动:

Text(text = getString(android.R.string.yes))

内部非活动 :

Text(text = Resources.getSystem().getString(android.R.string.yes))

                          OR

Text(text = stringResource(android.R.string.yes))
1赞 Florian Reisinger 7/21/2022 #15

如果你使用的是 Hilt,你实际上可以注入上下文:

@Module
@InstallIn(SingletonComponent::class)
interface ResourceProvider {

    companion object {
    
    @Provides
    @Singleton
    @MyQualifier
    fun providesBaseUrl(@ApplicationContext context: Context): String = with(context) {
      getString(R.string.my_value)
    }
  }
}
2赞 Mike Schvedov 8/23/2022 #16

根据 Khemraj Sharma 的回答,这是 Kotlin 版本,并附带了额外的扩展作为奖励:

class App: Application() {

    override fun onCreate() {
        super.onCreate()
        mInstance = this
        res = resources
    }
    companion object{

        private var mInstance: App? = null
        private var res: Resources? = null

        fun getInstance(): App? {
            return mInstance
        }

        fun getRes(): Resources? {
            return res
        }
    }
}

然后我们可以创建一个扩展:

fun Int.resourceToString(): String {
    return App.getRes()?.getString(this) ?: "Not Found"
}

并直接在任何资源 ID 上使用扩展:

var asString = R.string.my_string.resourceToString()
0赞 Mohsinali 7/7/2023 #17

若要在没有上下文的情况下访问字符串资源,可以创建一个单独的实用程序类,并将应用程序上下文传递给它。下面是一个示例:

创建一个名为 ResourceUtils 的类:

   object ResourceUtils {
        private var applicationContext: Context? = null
    
        fun initialize(context: Context) {
            applicationContext = context.applicationContext
        }
    
        fun getString(resId: Int): String {
            applicationContext?.let {
                return it.resources.getString(resId)
            }
            throw IllegalStateException("ResourceUtils not initialized with application context")
        }
    }

在 Application 类中,使用应用程序上下文初始化 ResourceUtils:

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        ResourceUtils.initialize(this)
    }
}

现在,您可以使用 ResourceUtils.getString() 在没有上下文的情况下访问字符串资源:

val appName = ResourceUtils.getString(R.string.app_name)
0赞 Roel Leal 11/17/2023 #18

我用这段代码解决了这个问题

holder.btnAddFriend.setOnClickListener(v -> {
        // Obtener el nombre del usuario del elemento actual

        String username = user.getUsername();
        String id = v.getContext().getResources().getString(R.string.idusd);
 }