getString al di fuori di un contesto o attività


260

Ho trovato il R.stringfantastico per tenere le stringhe hardcoded fuori dal mio codice e mi piacerebbe continuare a usarlo in una classe di utilità che funziona con i modelli nella mia applicazione per generare output. Ad esempio, in questo caso sto generando un'email da un modello esterno all'attività.

È possibile utilizzare getStringal di fuori di un ContextoActivity ? Suppongo che potrei passare l'attività corrente, ma sembra inutile. Per favore correggimi se sbaglio!

Modifica: possiamo accedere alle risorse senza usare Context?


4
Passando il contesto alla classe che utilizzerà la stringa, si passano anche informazioni su quale lingua (en, es, ecc.) Viene utilizzata dall'app. Quindi, se hai due stringhe.xml, saprà quale usare
sport

Risposte:


440

Sì, possiamo accedere alle risorse senza usare "Contesto"

Puoi usare:

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

... ovunque nell'applicazione, anche nelle dichiarazioni di costanti statiche. Sfortunatamente, supporta solo le risorse di sistema .

Per le risorse locali utilizzare questa soluzione . Non è banale, ma funziona.


17
cosa si intende per risorse di sistema? strings.xml è una risorsa di sistema o no? Per me non funziona, dice non riesco a trovare risorse.
Kirhgoff,

6
Le risorse di sistema appartengono ad Android sul dispositivo. strings.xml appartiene solo alla tua applicazione. Cercare stackoverflow.com/a/4391811/715269 soluzione
Gangnus

3
Questa è una soluzione elegante per quelle classi Factory quando si accede alle stringhe. Non mi piace passare il contesto ovunque. Questo è solo un ingombro inutile per i casi in cui vogliamo davvero solo una stringa memorizzata a livello globale.
Jay Snayder,

1
è più efficace che passare il contesto a una classe e usarlo ??
SoliQuiD,

5
ottengo questo erroreandroid.content.res.Resources$NotFoundException: String resource ID #0x7f0f0061
Ebrahim Karimi,

108

Sfortunatamente, l'unico modo per accedere a una qualsiasi delle risorse della stringa è con un Context(cioè un Activityo Service). Quello che di solito ho fatto in questo caso, è semplicemente richiedere al chiamante di passare nel contesto.


4
Grazie per il consiglio! Ho appena provato questo, ma per qualche motivo ho avuto un errore di compilazione quando ho provato:ctx.getString(ctx.R.string.blah);
SapphireSun

Vorrei fare l'argomento ai metodi util di tipo in Contextmodo da poterlo utilizzare da un'attività o da un servizio.
MatrixFrog,

2
Non è necessario il ctx.R.string.blah, basta usareR.string.blah
Pentium10

2
Non sono sicuro da dove symbol not found errorprovenga, ma assicurati di aver Rimportato in cima alla classe.
Pentium10,

11
La risposta è FALSO. Vis il prossimo. :-)
Gangnus,

33

In MyApplication, che si estende Application:

public static Resources resources;

In MyApplication's onCreate:

resources = getResources();

Ora puoi utilizzare questo campo da qualsiasi parte dell'applicazione.


Funzionerebbe attraverso il servizio? (Soprattutto quando Android uccide l'app e avvia solo il servizio)
Atul,

1
Sì, Android inizia a eseguire il codice chiamando Application.onCreate e successivamente esegue il tuo servizio.
Konmik,

23

A proposito, uno dei motivi dell'errore di simbolo non trovato potrebbe essere che il tuo IDE abbia importato android.R; classe invece della tua. Basta cambiare import android.R; per importare your.namespace.R;

Quindi 2 cose di base per rendere visibile la stringa nella diversa classe:

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

Approccio unico

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

Funzionerà ovunque nell'app. ( Util class, Dialog, Fragment o qualunque classe nella tua app )

(1) Crea o modifica (se già esiste) la tua 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) Aggiungi il campo del nome al tuo manifest.xml <applicationtag.

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

Ora sei a posto. Utilizza App.getRes().getString(R.string.some_id)ovunque in app.


1
Personalmente mi piace questo approccio. Comodo per ottenere risorse di stringa personalizzate da qualsiasi parte del codice.
checkmate711

Ci sono problemi di sicurezza con questa soluzione?
nibbana,

@ user1823280 No, non credo.
Khemraj,

Soluzione perfetta
Yasiru Nayanajith

4

Se hai una classe che usi in un'attività e vuoi avere accesso alla risorsa in quella classe, ti consiglio di definire un contesto come variabile privata in classe e inizializzarlo nel costruttore:

public class MyClass (){
    private Context context;

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

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

Fare un istante di classe nella tua attività:

MyClass m=new MyClass(this);

0

Questo dovrebbe consentirti di accedere applicationContextda qualsiasi luogo, permettendoti di arrivare applicationContextovunque tu possa utilizzarlo; 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;
    }

}

Inizializza Singleton nella Applicationsottoclasse:

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

Se non sbaglio, questo ti dà un gancio per applicationContext ovunque, chiamalo con ApplicationContextSingleton.getInstance.getApplicationContext(); Non dovresti cancellarlo in nessun momento, come quando l'applicazione si chiude, questo va comunque con esso.

Ricorda di aggiornare AndroidManifest.xmlper utilizzare questa Applicationsottoclasse:

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

Per favore fatemi sapere se vedete qualcosa di sbagliato qui, grazie. :)


0

L'approccio migliore dalla risposta di Khemraj:

Classe di 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
    }

}

Dichiarazione nel manifest

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

Classe di costanti

class Localizations {

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

}

utilizzando

textView.text = Localizations.info

0

È meglio usare qualcosa di simile senza contesto e attività :

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

0

In qualche modo non sono piaciute le soluzioni confuse di memorizzazione dei valori statici, quindi ne è uscito un po 'più a lungo ma una versione pulita che può anche essere testata.

Trovati 2 modi possibili per farlo-

  1. Passare context.resources come parametro alla classe in cui si desidera la risorsa stringa. Abbastanza semplice. Se non è possibile passare come parametro, utilizzare il setter.

per esempio

data class MyModel(val resources: Resources) {
    fun getNameString(): String {
        resources.getString(R.string.someString)
    }
}
  1. Usa l'associazione dati (richiede però frammento / attività)

Prima di leggere: utilizza questa versione 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>

Attività / Fragment-

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

A volte, è necessario modificare il testo in base a un campo in un modello. Quindi assoceresti anche quel modello e poiché la tua attività / frammento conosce il modello, puoi recuperare molto bene il valore e quindi legare i dati alla stringa in base a quello.


0

Puoi farlo in Kotlin creando una classe che estende l'applicazione e quindi usa il suo contesto per chiamare le risorse ovunque nel tuo codice

La tua classe App sarà simile a questa

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

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

Dichiara la tua classe di applicazione in AndroidManifest.xml (molto 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>

Per accedere, ad esempio, a un file di stringa, utilizzare il seguente codice

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

Questo non funzionerà se si modificano le impostazioni locali a livello di programmazione durante il runtime perché il contesto dell'applicazione è un singleton e inizializzato all'avvio del processo.
Szörényi Ádám

-2

Ecco cosa ho fatto, in MainActivity, ho creato una variabile statica per il contesto, come mostrato di seguito:

public static Context mContext;

e in onCreate () inizializzare mContext a questo;

mContext = this;

Quindi, nel file in cui si desidera accedere al contesto, dire:

private Context context = MainActivity.mContext;

Ora puoi ottenere una risorsa stringa nel modo seguente,

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

-8

Ho usato getContext().getApplicationContext().getString(R.string.nameOfString); Funziona per me.


14
Pensi che getContext()sia disponibile ovunque ?!
Hamzeh Soboh,

1
Questo non fornisce una risposta alla domanda perché getContext () disponibile solo nelle classi di attività e frammenti
Umar Ata,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.