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.