getString en dehors d'un contexte ou d'une activité


260

J'ai trouvé R.stringassez génial pour garder les chaînes codées en dur hors de mon code, et j'aimerais continuer à l'utiliser dans une classe utilitaire qui fonctionne avec les modèles de mon application pour générer une sortie. Par exemple, dans ce cas, je génère un e-mail à partir d'un modèle en dehors de l'activité.

Est-il possible d'utiliser en getStringdehors d'un ContextouActivity ? Je suppose que je pourrais passer dans l'activité actuelle, mais cela semble inutile. Corrigez-moi si j'ai tort, s'il-vous plait!

Edit: pouvons-nous accéder aux ressources sans utiliser Context?


4
En passant le contexte à la classe qui va utiliser la chaîne, vous transmettez également des informations sur la langue (en, es, etc.) utilisée par l'application. Donc, si vous avez deux strings.xml, il saura lequel utiliser
sports

Réponses:


441

Oui, nous pouvons accéder aux ressources sans utiliser `Context`

Vous pouvez utiliser:

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

... partout dans votre application, même dans les déclarations de constantes statiques. Malheureusement, il prend uniquement en charge les ressources système .

Pour les ressources locales, utilisez cette solution . Ce n'est pas anodin, mais cela fonctionne.


17
qu'entend-on par ressources système? le strings.xml est une ressource système ou non? Pour moi, cela ne fonctionne pas, dit ne peut pas trouver de ressources.
kirhgoff

6
Les ressources système appartiennent à Android sur l'appareil. strings.xml n'appartient qu'à votre application. Recherchez la solution stackoverflow.com/a/4391811/715269
Gangnus

3
Il s'agit d'une solution élégante pour ces classes Factory lors de l'accès aux chaînes. Je n'aime pas passer le Context partout. C'est juste un encombrement inutile dans les cas où nous voulons vraiment qu'une chaîne soit stockée globalement.
Jay Snayder

1
est-ce plus efficace que de passer le contexte à une classe et de l'utiliser ??
SoliQuiD

5
je reçois cette erreurandroid.content.res.Resources$NotFoundException: String resource ID #0x7f0f0061
Ebrahim Karimi

108

Malheureusement, la seule façon d'accéder à l'une des ressources de chaîne est d'utiliser un Context(c'est-à-dire un Activityou Service). Ce que j'ai l'habitude de faire dans ce cas, c'est d'exiger simplement que l'appelant passe dans le contexte.


4
Merci pour le conseil! Je viens d'essayer cela, mais pour une raison quelconque, j'ai eu une erreur de compilation lorsque j'ai essayé:ctx.getString(ctx.R.string.blah);
SapphireSun

Je ferais l'argument des méthodes de type util Contextafin que vous puissiez l'utiliser à partir d'une activité ou d'un service.
MatrixFrog

2
Vous n'avez pas besoin de ctx.R.string.blah, utilisez simplementR.string.blah
Pentium10

2
Je ne sais pas d'où symbol not found errorvient le produit, mais assurez-vous que vous avez Rimporté en haut de la classe.
Pentium10

11
La réponse est FAUX. Vis le suivant. :-)
Gangnus

33

Dans MyApplication, qui s'étend Application:

public static Resources resources;

Dans MyApplication« s onCreate:

resources = getResources();

Vous pouvez maintenant utiliser ce champ depuis n'importe où dans votre application.


Cela fonctionnerait-il par le service? (Surtout quand Android tue l'application et démarre uniquement le service)
Atul

1
Oui, Android commence à exécuter votre code en appelant Application.onCreate et après cela, il exécute votre service.
konmik

23

BTW, l'une des raisons de l' erreur de symbole non trouvé peut être que votre IDE a importé android.R; classe au lieu de la vôtre. Il suffit de modifier l' importation android.R; à importer your.namespace.R;

Donc 2 choses de base pour rendre la chaîne visible dans les différentes classes:

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

19

Approche unique

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

Cela fonctionnera partout dans l'application. ( Utilisez la classe, la boîte de dialogue, le fragment ou n'importe quelle classe de votre application )

(1) Créez ou modifiez (s'il existe déjà) votre Applicationclasse.

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) Ajoutez un champ de nom à votre manifest.xml <applicationtag.

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

Vous êtes maintenant prêt à partir. Utilisez App.getRes().getString(R.string.some_id)n'importe où dans l'application.


1
J'aime personnellement cette approche. Pratique pour obtenir des ressources de chaîne personnalisées de n'importe où dans le code.
checkmate711

Y a-t-il des problèmes de sécurité avec cette solution?
nibbana

@ user1823280 Non, je ne pense pas.
Khemraj

Solution parfaite
Yasiru Nayanajith

4

Si vous avez une classe que vous utilisez dans une activité et que vous souhaitez avoir accès à la ressource dans cette classe, je vous recommande de définir un contexte comme variable privée dans la classe et de l'initier dans le constructeur:

public class MyClass (){
    private Context context;

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

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

Faire un instant de classe dans votre activité:

MyClass m=new MyClass(this);

0

Cela devrait vous permettre d'accéder à applicationContextn'importe où vous permettant d'accéder à applicationContextn'importe quel endroit qui peut l'utiliser; Toast, getString(), sharedPreferences, Etc.

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

}

Initialisez le singleton dans votre Applicationsous-classe:

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 je ne me trompe pas, cela vous donne un crochet à applicationContext partout, appelez-le avec ApplicationContextSingleton.getInstance.getApplicationContext(); Vous ne devriez pas avoir besoin d'effacer cela à tout moment, car lorsque l'application se ferme, cela va de toute façon avec elle.

N'oubliez pas de mettre à jour AndroidManifest.xmlpour utiliser cette Applicationsous - classe:

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

S'il vous plaît faites le moi savoir si vous voyez quelque chose de mal ici, merci. :)


0

La meilleure approche de la réponse de Khemraj:

Classe d'application

class App : Application() {

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


    // MARK: - Lifecycle

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

}

Déclaration dans le manifeste

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

Classe de constantes

class Localizations {

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

}

En utilisant

textView.text = Localizations.info

0

Il vaut mieux utiliser quelque chose comme ça sans contexte ni activité :

Resources.getSystem().getString(R.string.my_text)

0

D'une manière ou d'une autre, je n'aimais pas les solutions hacky de stockage de valeurs statiques, nous avons donc proposé une version un peu plus longue mais propre qui peut également être testée.

Trouvé 2 façons possibles de le faire-

  1. Passez context.resources en tant que paramètre à votre classe où vous voulez la ressource de chaîne. Assez simple. S'il n'est pas possible de passer en paramètre, utilisez le setter.

par exemple

data class MyModel(val resources: Resources) {
    fun getNameString(): String {
        resources.getString(R.string.someString)
    }
}
  1. Utiliser la liaison de données (nécessite cependant un fragment / activité)

Avant de lire: cette version utilise 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>

Activité / Fragment-

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

Parfois, vous devez modifier le texte en fonction d'un champ dans un modèle. Donc, vous lieriez également ce modèle aux données et puisque votre activité / fragment connaît le modèle, vous pouvez très bien récupérer la valeur, puis lier les données à la chaîne en fonction de cela.


0

Vous pouvez le faire dans Kotlin en créant une classe qui étend Application, puis utilisez son contexte pour appeler les ressources n'importe où dans votre code

Votre classe d'application ressemblera à ceci

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

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

Déclarez votre classe Application dans AndroidManifest.xml (très important)

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

Pour accéder par exemple à un fichier de chaîne, utilisez le code suivant

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

Cela ne fonctionnera pas si vous modifiez les paramètres régionaux par programme pendant l'exécution, car le contexte d'application est un singleton et initialisé au démarrage de votre processus.
Szörényi Ádám

-2

Voici ce que j'ai fait, dans votre activité principale, créez une variable statique pour le contexte, comme indiqué ci-dessous:

public static Context mContext;

et dans onCreate () initialiser mContext à ceci;

mContext = this;

Ensuite, dans le fichier dans lequel vous souhaitez accéder au contexte, par exemple,

private Context context = MainActivity.mContext;

Maintenant, vous pouvez obtenir une ressource de chaîne de la manière suivante,

String myString = context.getResources().getString(R.string.resource_id);

-8

J'ai utilisé getContext().getApplicationContext().getString(R.string.nameOfString); Cela fonctionne pour moi.


14
Pensez-vous qu'il getContext()est disponible partout?!
Hamzeh Soboh

1
Cela ne fournit pas de réponse à la question car getContext () n'est disponible que dans les classes d'activités et de fragments
Umar Ata
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.