getString fuera de un contexto o actividad

260

He encontrado lo R.stringincreíble para mantener las cadenas codificadas fuera de mi código, y me gustaría seguir usándolo en una clase de utilidad que funciona con modelos en mi aplicación para generar resultados. Por ejemplo, en este caso estoy generando un correo electrónico desde un modelo fuera de la actividad.

¿Es posible usar getStringfuera de un ContextoActivity ? Supongo que podría pasar la actividad actual, pero parece innecesario. ¡Por favor corrígeme si estoy equivocado!

Editar: ¿Podemos acceder a los recursos sin usar Context?

ZafiroSun
fuente
44
Al pasar el contexto a la clase que va a usar la cadena, también está pasando información sobre qué idioma (en, es, etc.) está utilizando la aplicación. Entonces, si tiene dos strings.xml, sabrá cuál usar
deportes

Respuestas:

440

Sí, podemos acceder a los recursos sin usar `Context`

Puedes usar:

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

... en todas partes en su aplicación, incluso en declaraciones de constantes estáticas. Desafortunadamente, solo admite los recursos del sistema .

Para recursos locales, use esta solución . No es trivial, pero funciona.

Gangnus
fuente
17
¿Qué se entiende por recursos del sistema? ¿strings.xml es un recurso del sistema o no? Para mí no funciona, dice que no puede encontrar recursos.
kirhgoff
66
Los recursos del sistema pertenecen a Android en el dispositivo. strings.xml pertenece solo a su aplicación. Busque la solución stackoverflow.com/a/4391811/715269
Gangnus
3
Esta es una solución elegante para esas clases Factory al acceder a cadenas. No me gusta pasar Context a todas partes. Eso es un desorden innecesario para casos en los que realmente solo queremos una cadena almacenada globalmente.
Jay Snayder
1
¿Es esto más eficiente que pasar el contexto a una clase y usarlo?
SoliQuiD
55
me sale este errorandroid.content.res.Resources$NotFoundException: String resource ID #0x7f0f0061
Ebrahim Karimi
108

Desafortunadamente, la única forma en que puede acceder a cualquiera de los recursos de cadena es con un Context(es decir, un Activityo Service). Lo que generalmente he hecho en este caso es simplemente requerir que la persona que llama pase en el contexto.

Erich Douglass
fuente
44
¡Gracias por el consejo! Acabo de intentar esto, pero por alguna razón recibí un error de compilación cuando lo intenté:ctx.getString(ctx.R.string.blah);
SapphireSun el
Haría el argumento de los métodos de tipo util Contextpara que pueda usarlo desde una Actividad o un Servicio.
MatrixFrog
2
No necesita ctx.R.string.blah, solo useR.string.blah
Pentium10
2
No estoy seguro de dónde symbol not found errorviene, pero asegúrese de que haya Rimportado en la parte superior de la clase.
Pentium10
11
La respuesta es FALSA. Vis el siguiente. :-)
Gangnus
33

En MyApplication, que se extiende Application:

public static Resources resources;

En MyApplications onCreate:

resources = getResources();

Ahora puede usar este campo desde cualquier lugar de su aplicación.

konmik
fuente
¿Funcionaría a través del servicio? (Especialmente cuando Android mata la aplicación y solo inicia el servicio)
Atul
1
Sí, Android comienza a ejecutar su código llamando a Application.onCreate y luego ejecuta su servicio.
konmik
23

Por cierto, una de las razones del error de símbolo no encontrado puede ser que su IDE importó android.R; clase en lugar de la tuya. Simplemente cambie import android.R; para importar your.namespace.R;

Entonces, 2 cosas básicas para hacer que la cadena sea visible en la clase diferente:

//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);
}
Jan Naruszkiewicz
fuente
19

Enfoque único

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

Esto funcionará en todas partes en la aplicación. ( Clase de utilidad, diálogo, fragmento o cualquier clase en su aplicación )

(1) Cree o edite (si ya existe) su Applicationclase.

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 getResourses() {
        return res;
    }

}

(2) Agregue el campo de nombre a su manifest.xml <applicationetiqueta.

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

Ahora estás listo para irte. Úselo App.getRes().getString(R.string.some_id)en cualquier lugar de la aplicación.

Khemraj
fuente
1
Personalmente me gusta este enfoque. Conveniente para obtener recursos de cadena personalizados desde cualquier parte del código.
checkmate711
¿Hay algún problema de seguridad con esta solución?
nibbana
@ user1823280 No, no lo creo.
Khemraj
Solución perfecta
Yasiru Nayanajith
4

Si tiene una clase que usa en una actividad y desea tener acceso al recurso en esa clase, le recomiendo que defina un contexto como una variable privada en la clase y lo inicialice en el constructor:

public class MyClass (){
    private Context context;

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

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

Hacer un instante de clase en tu actividad:

MyClass m=new MyClass(this);
Malus Jan
fuente
0

Esto debería applicationContextpermitirle acceder desde cualquier lugar, permitiéndole llegar a applicationContextcualquier lugar que pueda usarlo; Toast, getString(), sharedPreferences, Etc.

El singleton:

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;
    }

}

Inicialice el Singleton en su Applicationsubclase:

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);
    }
}

Si no me equivoco, esto le da un gancho a applicationContext en todas partes, ApplicationContextSingleton.getInstance.getApplicationContext(); llámelo con No debería tener que borrar esto en ningún momento, ya que cuando la aplicación se cierra, esto va con ella de todos modos.

Recuerde actualizar AndroidManifest.xmlpara usar esta Applicationsubclase:

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

Avísame si ves algo mal aquí, gracias. :)

Versa
fuente
0

El mejor enfoque de la respuesta de Khemraj:

Clase de aplicación

class App : Application() {

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


    // MARK: - Lifecycle

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

}

Declaración en el manifiesto

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

Clase de constantes

class Localizations {

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

}

Utilizando

textView.text = Localizations.info
Mickael Belhassen
fuente
0

Es mejor usar algo como esto sin contexto y actividad :

Resources.getSystem().getString(R.string.my_text)
reza_khalafi
fuente
0

De alguna manera no me gustaron las soluciones hacky de almacenar valores estáticos, así que se me ocurrió un poco más, pero una versión limpia que también se puede probar.

Encontramos 2 formas posibles de hacerlo

  1. Pase context.resources como parámetro a su clase donde desea el recurso de cadena. Bastante sencillo. Si no es posible pasar como parámetro, use el setter.

p.ej

data class MyModel(val resources: Resources) {
    fun getNameString(): String {
        resources.getString(R.string.someString)
    }
}
  1. Utilice el enlace de datos (aunque requiere fragmento / actividad)

Antes de leer: Esta versión usa 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>

Actividad / Fragmento

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

A veces, debe cambiar el texto en función de un campo en un modelo. Por lo tanto, también vincularía ese modelo con datos y, dado que su actividad / fragmento conoce el modelo, puede recuperar el valor y luego vincular la cadena con los datos en función de eso.

Rajkiran
fuente
0

Puede hacer esto en Kotlin creando una clase que extienda la aplicación y luego use su contexto para llamar a los recursos en cualquier parte de su código

Tu clase de aplicación se verá así

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

    companion object {
        var context: Context? = null
            private set
    }
}

Declare su clase de aplicación en AndroidManifest.xml (muy importante)

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

Para acceder, por ejemplo, a un archivo de cadena, use el siguiente código

App.context?.resources?.getText(R.string.mystring)
Ahmed Raza
fuente
Esto no funcionará si cambia la configuración regional mediante programación durante el tiempo de ejecución porque el contexto de la aplicación es un singleton y se inicializa cuando se inicia el proceso.
Szörényi Ádám
-2

Esto es lo que hice, en su actividad principal, crear una variable estática para el contexto como se muestra a continuación:

public static Context mContext;

y en onCreate () inicialice mContext a esto;

mContext = this;

Luego, en el archivo donde desea acceder al contexto, diga:

private Context context = MainActivity.mContext;

Ahora, puede obtener un recurso de cadena de la siguiente manera,

String myString = context.getResources().getString(R.string.resource_id);
Soham Chari
fuente
-8

Solía getContext().getApplicationContext().getString(R.string.nameOfString); funcionar para mí.

vivynz
fuente
14
¿Crees que getContext()está disponible en todas partes?
Hamzeh Soboh
1
Esto no proporciona una respuesta a la pregunta porque getContext () solo está disponible en actividades y clases de fragmentos
Umar Ata