getString fora de um contexto ou atividade

260

Eu achei o R.stringincrível para manter as strings codificadas fora do meu código e gostaria de continuar usando-a em uma classe de utilitário que funciona com modelos no meu aplicativo para gerar saída. Por exemplo, neste caso, estou gerando um email de um modelo fora da atividade.

É possível usar getStringfora de um ContextouActivity ? Suponho que poderia passar na atividade atual, mas parece desnecessário. Por favor me corrija se eu estiver errado!

Edit: Podemos acessar os recursos sem usar Context?

SapphireSun
fonte
4
Ao passar o contexto para a classe que usará a string, você também está transmitindo informações sobre qual idioma (en, es, etc) está sendo usado pelo aplicativo. Então se você tem dois strings.xml, ele vai saber qual usar
esportes

Respostas:

440

Sim, podemos acessar recursos sem usar o `Contexto`

Você pode usar:

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

... em qualquer lugar do seu aplicativo, mesmo em declarações de constantes estáticas. Infelizmente, ele suporta apenas os recursos do sistema .

Para recursos locais, use esta solução . Não é trivial, mas funciona.

Gangnus
fonte
17
o que se entende por recursos do sistema? o strings.xml é um recurso do sistema ou não? Para mim, não funciona, diz que não consegue encontrar recursos.
kirhgoff
6
Os recursos do sistema pertencem ao Android no dispositivo. strings.xml pertencem apenas ao seu aplicativo. Procure stackoverflow.com/a/4391811/715269 solução
Gangnus
3
Essa é uma solução elegante para essas classes de fábrica ao acessar cadeias de caracteres. Não gosto de passar o Contexto para todo o lado. Isso é apenas uma bagunça desnecessária para casos em que realmente queremos apenas uma string armazenada globalmente.
perfil completo de Jay Snayder
1
isso é mais eficiente do que passar o contexto para uma classe e usá-lo?
SoliQuiD
5
eu recebo este erroandroid.content.res.Resources$NotFoundException: String resource ID #0x7f0f0061
Ebrahim Karimi
108

Infelizmente, a única maneira de acessar qualquer um dos recursos de string é com um Context(ou seja, um Activityou Service). O que geralmente faço neste caso é simplesmente exigir que o chamador passe no contexto.

Erich Douglass
fonte
4
Obrigado pela dica! Eu apenas tentei isso, mas por alguma razão eu tenho um erro de compilação quando eu tentei:ctx.getString(ctx.R.string.blah);
SapphireSun
Eu argumentaria com os métodos util do tipo, Contextpara que você possa usá-lo em uma Atividade ou em um Serviço.
MatrixFrog
2
Você não precisa o ctx.R.string.blah, basta usarR.string.blah
Pentium10
2
Não sei de onde symbol not found errorvem, mas verifique se Rimportou na parte superior da classe.
usar o seguinte comando
11
A resposta é FALSA. Vis o próximo. :-)
Gangnus
33

Em MyApplication, que se estende Application:

public static Resources resources;

In MyApplication's onCreate:

resources = getResources();

Agora você pode usar este campo de qualquer lugar no seu aplicativo.

konmik
fonte
Funcionaria através do serviço? (Especialmente quando o Android mata o aplicativo e inicia apenas o serviço)
Atul
1
Sim, o Android começa a executar seu código chamando Application.onCreate e depois executa seu serviço.
precisa saber é o seguinte
23

Aliás, um dos motivos do erro de símbolo não encontrado pode ser que o seu IDE importou o android.R; classe em vez da sua. Basta alterar import android.R; para importar your.namespace.R;

Então, duas coisas básicas para obter a string visível nas diferentes 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);
}
Jan Naruszkiewicz
fonte
19

Abordagem única

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

Isso funcionará em qualquer lugar no aplicativo. ( Classe Util, Diálogo, Fragmento ou qualquer classe no seu aplicativo )

(1) Crie ou edite (se já existir) sua Applicationturma.

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) Adicione um campo de nome à sua manifest.xml <applicationtag.

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

Agora você está pronto para ir. Use App.getRes().getString(R.string.some_id)em qualquer lugar do aplicativo.

Khemraj
fonte
1
Eu pessoalmente gosto dessa abordagem. Conveniente para obter recursos de string personalizados de qualquer lugar do código.
checkmate711
Existem problemas de segurança com esta solução?
Nibbana
@ user1823280 Não, eu não acho.
Khemraj
Solução perfeita
Yasiru Nayanajith
4

Se você tem uma classe que você usa em uma atividade e deseja acessar o recurso nessa classe, recomendo que você defina um contexto como uma variável privada na classe e inicialize-a no construtor:

public class MyClass (){
    private Context context;

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

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

Fazendo um instante de aula em sua atividade:

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

Isso deve applicationContextpermitir o acesso de qualquer lugar, permitindo chegar a applicationContextqualquer lugar que possa usá-lo; Toast, getString(), sharedPreferences, Etc.

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

}

Inicialize o Singleton na sua Applicationsubclasse:

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 não estou errado, isso dá a você um gancho para o applicationContext em todos os lugares, chame-o com ApplicationContextSingleton.getInstance.getApplicationContext(); Você não precisa limpar isso a qualquer momento, pois quando o aplicativo é fechado, isso também acontece com ele.

Lembre-se de atualizar AndroidManifest.xmlpara usar esta Applicationsubclasse:

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

Avise-me se vir algo errado aqui, obrigado. :)

Versa
fonte
0

A melhor abordagem da resposta do Khemraj:

Classe de aplicativo

class App : Application() {

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


    // MARK: - Lifecycle

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

}

Declaração no manifesto

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

Classe de constantes

class Localizations {

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

}

Usando

textView.text = Localizations.info
Mickael Belhassen
fonte
0

É melhor usar algo assim sem contexto e atividade :

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

De alguma forma, não gostou das soluções hacky de armazenamento de valores estáticos, por isso surgiu um pouco mais, mas uma versão limpa que também pode ser testada.

Foram encontradas 2 maneiras possíveis de fazer isso-

  1. Passe context.resources como um parâmetro para sua classe onde você deseja o recurso de string. Relativamente simples. Se não for possível passar como parâmetro, use o setter.

por exemplo

data class MyModel(val resources: Resources) {
    fun getNameString(): String {
        resources.getString(R.string.someString)
    }
}
  1. Use a ligação de dados (embora exija atividade / fragmento)

Antes de ler: Esta versão 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>

Atividade / Fragmento-

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

Às vezes, você precisa alterar o texto com base em um campo em um modelo. Portanto, você também vincularia dados a esse modelo e, como sua atividade / fragmento conhece o modelo, é possível buscar muito bem o valor e vincular a sequência com base nisso.

Rajkiran
fonte
0

Você pode fazer isso no Kotlin , criando uma classe que estende o Application e use seu contexto para chamar os recursos em qualquer lugar do seu código

Sua turma de aplicativos ficará assim

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

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

Declare sua classe de aplicativo no AndroidManifest.xml (muito 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 acessar, por exemplo, um arquivo de string, use o seguinte código

App.context?.resources?.getText(R.string.mystring)
Ahmed Raza
fonte
Isso não funcionará se você alterar o código de idioma programaticamente durante o tempo de execução, pois o contexto do aplicativo é um singleton e inicializado quando o processo foi iniciado.
Szörényi Ádám
-2

Aqui está o que eu fiz: Na sua MainActivity, crie uma variável estática para o contexto, como mostrado abaixo:

public static Context mContext;

e no onCreate () inicialize o mContext para isso;

mContext = this;

Em seguida, no arquivo em que você deseja acessar o contexto, diga:

private Context context = MainActivity.mContext;

Agora, você pode obter um recurso de string da seguinte maneira,

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

Eu usei getContext().getApplicationContext().getString(R.string.nameOfString); Funciona para mim.

vivynz
fonte
14
Você acha que getContext()está disponível em qualquer lugar ?!
Hamzeh Soboh
1
Isso não fornece uma resposta para a pergunta, porque o getContext () está disponível apenas nas classes de atividades e fragmentos
Umar Ata