getString вне контекста или действия

Я обнаружил, что R.string довольно здорово убирает жестко запрограммированные строки из моего кода, и я хотел бы продолжать использовать его в служебном классе, который работает с моделями в моем приложении для генерации вывода. Например, в этом случае я создаю электронное письмо из модели вне деятельности.

Можно ли использовать getString вне Context или Activity? Полагаю, я мог бы передать текущее действие, но это кажется ненужным. Пожалуйста, поправьте меня, если я ошибаюсь!

Изменить: можем ли мы получить доступ к ресурсам без с помощью Context?


person SapphireSun    schedule 23.11.2010    source источник
comment
Передавая контекст классу, который будет использовать строку, вы также передаете информацию о том, какой язык (en, es и т. Д.) Используется приложением. Итак, если у вас есть два strings.xml, он будет знать, какой из них использовать   -  person sports    schedule 10.08.2014


Ответы (12)


Да, мы можем получить доступ к ресурсам без использования контекста.

Ты можешь использовать:

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

... везде в вашем приложении, даже в объявлениях статических констант. К сожалению, он поддерживает только системные ресурсы.

Для местных ресурсов используйте это решение. Это нетривиально, но работает.

person Gangnus    schedule 06.01.2012
comment
что подразумевается под системными ресурсами? strings.xml - это системный ресурс или нет? У меня не работает, говорит, что не могу найти ресурс. - person kirhgoff; 15.03.2013
comment
Системные ресурсы на устройстве принадлежат Android. strings.xml принадлежит только вашему приложению. Найдите решение stackoverflow.com/a/4391811/715269 - person Gangnus; 15.03.2013
comment
Это элегантное решение для тех классов Factory при доступе к строкам. Мне не нравится распространять Контекст везде. Это просто ненужный беспорядок для случаев, когда мы действительно хотим, чтобы строка сохранялась глобально. - person Jay Snayder; 19.04.2013
comment
gracias за то, что позволили мне не бросать программирование на Android, когда мы привыкли к вспомогательным классам - person Arsalan Saleem; 09.03.2015
comment
это более эффективно, чем передача контекста классу и его использование ?? - person SoliQuiD; 28.10.2015
comment
@SoliQuiD Точно, о чем ты говоришь? Я упоминаю два способа - для системных ресурсов и для пользовательских ресурсов. Если первое - однозначно, наиболее действенное. Если вы имеете в виду второе - у него такая же эффективность, но гораздо удобнее, если вы занимаетесь чем-то более серьезным, чем школьное домашнее задание. Основная причина в том, что при любом изменении в организации ресурсов становится все меньше на что смотреть. - person Gangnus; 28.10.2015
comment
@SoliQuiD А как вы хотите передавать контент в разные классы? Основная проблема, о которой мы говорим, заключается в том, что мы слишком поздно получили эти ресурсы. Какой объект вы хотите им передать? Один из классов? Тогда какая польза от вашего решения вообще? - person Gangnus; 28.10.2015
comment
я получаю эту ошибку android.content.res.Resources$NotFoundException: String resource ID #0x7f0f0061 - person Ebrahim Karimi; 16.08.2019
comment
@EbrahimKarimi Итак, этого ресурса нет в списке общих ресурсов. Если не помогло, задайте вопрос в виде вопроса, с примерами и точнее. - person Gangnus; 17.08.2019
comment
Это не работает в статических контекстах. Я получаю исключение в ошибке инициализатора при использовании его в статическом методе. - person VanessaF; 17.09.2020
comment
@VanessaF Простите, это должно работать. В противном случае у вас особая проблема. Если вы не видите причину этого, задайте новый вопрос. - person Gangnus; 18.09.2020
comment
у меня не сработало :( обходной путь - передача контекста служебному классу - person San Askaruly; 19.07.2021

К сожалению, единственный способ получить доступ к любому из строковых ресурсов - использовать Context (т.е. Activity или Service). В этом случае я обычно просто требую от вызывающего передать контекст.

person Erich Douglass    schedule 23.11.2010
comment
Спасибо за совет! Я просто пробовал это, но по какой-то причине при попытке компиляции у меня возникла ошибка: ctx.getString(ctx.R.string.blah); - person SapphireSun; 23.11.2010
comment
Я бы привел аргумент в пользу методов util типа Context, чтобы вы могли использовать его как в Activity, так и в службе. - person MatrixFrog; 23.11.2010
comment
Вам не нужен ctx.R.string.blah, просто используйте R.string.blah - person Pentium10; 23.11.2010
comment
@ Pentium10: это дало мне ошибку "символ не найден" для R.string.blah, потому что класс не является контекстом. :( - person SapphireSun; 23.11.2010
comment
Полагаю, я мог бы пройти и в R, но это кажется очень неуклюжим. - person SapphireSun; 23.11.2010
comment
Я не уверен, откуда берется symbol not found error, но убедитесь, что вы импортировали R поверх класса. - person Pentium10; 23.11.2010
comment
Хех, я получал ошибку "символ не найден", потому что я использовал import basepackage.* для всех моих других классов и забыл сделать это в этом случае. - person SapphireSun; 23.11.2010
comment
Ответ - ЛОЖЬ. Посетил следующий. :-) - person Gangnus; 07.01.2012
comment
Это неверный ответ, обновите его, пожалуйста. Или, по крайней мере, измените первую строку ответа — «К сожалению, единственный способ получить доступ к любому из строковых ресурсов — это контекст» — см. ответ @Gangnus. - person Shirish Herwade; 26.02.2018

В MyApplication, который расширяет Application:

public static Resources resources;

In MyApplication's onCreate:

resources = getResources();

Теперь вы можете использовать это поле из любого места в вашем приложении.

person konmik    schedule 10.03.2015
comment
Будет ли это работать через службу? (Особенно, когда Android убивает приложение и запускает только службу) - person Atul; 17.04.2016
comment
Да, Android начинает выполнять ваш код, вызывая Application.onCreate, а после этого запускает вашу службу. - person konmik; 18.04.2016

## Уникальный подход

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

Это будет работать везде в приложении. (Класс Util, Dialog, Fragment или любой другой класс в вашем приложении)

(1) Создайте или отредактируйте (если уже существует) ваш Application класс.

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

}

(2) Добавьте поле имени в свой тег manifest.xml <application.

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

Теперь можно идти. Используйте App.getRes().getString(R.string.some_id) в любом месте приложения.

person Khemraj Sharma    schedule 11.07.2018
comment
Мне лично нравится такой подход. Удобно получать настраиваемые строковые ресурсы из любого места кода. - person checkmate711; 24.11.2018
comment
Есть ли проблемы с безопасностью при использовании этого решения? - person nibbana; 22.04.2019
comment
@ user1823280 Нет, не думаю. - person Khemraj Sharma; 22.04.2019
comment
Идеальное решение - person Yasiru Nayanajith; 14.08.2019
comment
Это уже предлагалось в 2010/2014 гг. В stackoverflow.com/a/4391811/2823074 - person Mikaelblomkvistsson; 16.03.2021
comment
@Mikaelblomkvistsson Следует удалить? - person Khemraj Sharma; 17.03.2021
comment
Вообще-то, нет. Есть небольшая разница. Ваше решение менее подвержено утечкам памяти, в отличие от исходного. Я этого не заметил с первого взгляда. - person Mikaelblomkvistsson; 18.03.2021

Кстати, одна из причин ошибки не найден символ может заключаться в том, что ваша IDE импортировала android.R; класс вместо твоего. Просто измените import android.R; на import your.namespace.R;

Итак, две основные вещи, чтобы сделать строку видимой в другом классе:

//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);
}
person Jan Naruszkiewicz    schedule 24.05.2012

Если у вас есть класс, который вы используете в действии, и вы хотите иметь доступ к ресурсу в этом классе, я рекомендую вам определить контекст как частную переменную в классе и инициализировать его в конструкторе:

public class MyClass (){
    private Context context;

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

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

Сделайте урок классным в своей деятельности:

MyClass m=new MyClass(this);
person Malus Jan    schedule 13.03.2016

Лучший подход из ответа Хемраджа:

Класс приложения

class App : Application() {

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


    // MARK: - Lifecycle

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

}

Декларация в манифесте

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

Класс констант

class Localizations {

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

}

Использование

textView.text = Localizations.info
person Mickael Belhassen    schedule 14.02.2019
comment
это решение kotlin сработало для меня! Спасибо - person Ash; 25.06.2021
comment
не могли бы вы уточнить часть "android: name = .App"? Android Studio дает подсказку Неожиданный текст, обнаруженный в файле макета: android: name = .App. Кроме того, при запуске приложения в журнале указано kotlin.UninitializedPropertyAccessException: экземпляр свойства lateinit не был инициализирован. - person jonadv; 18.07.2021

Вы можете сделать это в Kotlin, создав класс, который расширяет Application, а затем использовать его контекст для вызова ресурсов в любом месте вашего кода.

Ваш класс приложения будет выглядеть так

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

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

Объявите свой класс Application в AndroidManifest.xml (очень важно)

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

Для доступа, например, строковый файл используйте следующий код

App.context?.resources?.getText(R.string.mystring)
person Ahmed Raza    schedule 29.12.2019
comment
Это не сработает, если вы программно измените локаль во время выполнения, потому что контекст приложения является одноэлементным и инициализируется при запуске вашего процесса. - person Szörényi Ádám; 31.01.2020

Это должно дать вам доступ к applicationContext из любого места, что позволит вам получить applicationContext из любого места, где его можно использовать; Toast, getString(), sharedPreferences и т. Д.

Синглтон:

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

}

Инициализируйте синглтон в своем подклассе Application:

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

Если я не ошибаюсь, это дает вам ловушку для applicationContext повсюду, вызывайте его с помощью ApplicationContextSingleton.getInstance.getApplicationContext();. Вам не нужно очищать это в любой момент, так как когда приложение закрывается, это все равно идет с ним.

Не забудьте обновить AndroidManifest.xml, чтобы использовать этот Application подкласс:

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

Пожалуйста, дайте мне знать, если вы видите здесь что-то не так, спасибо. :)

person Versa    schedule 25.09.2015

Почему-то не понравились хакерские решения для хранения статических значений, поэтому придумал немного более длинную, но чистую версию, которую также можно протестировать.

Нашел 2 возможных способа сделать это -

  1. Передайте context.resources в качестве параметра вашему классу, в котором вы хотите строковый ресурс. Довольно просто. Если передача в качестве параметра невозможна, используйте установщик.

e.g.

data class MyModel(val resources: Resources) {
    fun getNameString(): String {
        resources.getString(R.string.someString)
    }
}
  1. Используйте привязку данных (хотя требуется фрагмент / действие)

Прежде чем вы прочитаете: в этой версии используется 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>

Действие / Фрагмент-

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

Иногда вам нужно изменить текст на основе поля в модели. Таким образом, вы также должны привязать данные к этой модели, и поскольку ваша активность / фрагмент знает о модели, вы можете очень хорошо получить значение, а затем привязать данные к строке на основе этого.

person Rajkiran    schedule 19.12.2019

Котлин: Идеальное решение 02.03.2021


  • AppCompatActivity
  • Сопутствующий объект

Код активности:

class MainActivity : AppCompatActivity() {

    companion object {
        lateinit var instance: AppCompatActivity
            private set
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        instance = this
    }
}

Получение ресурса из AnyWhere:

val text = MainActivity.instance.getString(R.string.task_1)

P.S Vel_daN: ЛЮБИТЕ, ЧТО ВЫ ДЕЛАЕТЕ.

person Владислав Шестернин    schedule 02.03.2021
comment
Это решение вызывает утечку памяти, так как сохранение Activity (или любого другого системного компонента) в статическую переменную не позволяет сборщику мусора правильно освободить его. Это считается плохой практикой. - person r4zzz4k; 02.03.2021

Я использовал getContext().getApplicationContext().getString(R.string.nameOfString); У меня работает.

person vivynz    schedule 16.02.2015
comment
Как вы думаете, getContext() доступен везде ?! - person Hamzeh Soboh; 27.06.2015
comment
Это не дает ответа на вопрос, потому что getContext () доступен только в классах activites и fragments. - person Umar Ata; 19.01.2017