Bir Bağlamın veya Etkinliğin Dışına getString


260

R.stringKodumdan sabit kodlu dizeleri tutmak için oldukça harika buldum ve çıktı oluşturmak için uygulamamdaki modellerle çalışan bir yardımcı program sınıfında kullanmaya devam etmek istiyorum. Örneğin, bu durumda, faaliyetin dışındaki bir modelden bir e-posta oluşturuyorum.

getStringA Contextveya dışında kullanılabilirActivity mi? Mevcut etkinliğe geçebileceğimi düşünüyorum, ama gereksiz görünüyor. Yanılıyorsam lütfen beni düzeltin!

Düzenleme: Biz kaynaklara erişebilir olmadan kullanan Context?


4
Bağlamı, dizeyi kullanacak sınıfa aktararak, uygulama tarafından hangi dilin (en, es, vb.) Kullanıldığına dair bilgi de aktarıyorsunuz. Yani iki dizeniz varsa .xml, hangisini kullanacağınızı bilecek
spor

Yanıtlar:


442

Evet, kaynaklara `Bağlam 'kullanmadan erişebiliriz

Kullanabilirsiniz:

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

... uygulamanızın her yerinde, statik sabit bildirimlerinde bile. Ne yazık ki, yalnızca sistem kaynaklarını desteklemektedir .

Yerel kaynaklar için bu çözümü kullanın . Önemsiz değil, ama işe yarıyor.


17
sistem kaynakları ne anlama geliyor? .xml sistem kaynağı mıdır, değil mi? Benim için işe yaramıyor diyor kaynak bulamıyor.
kirhgoff

6
Sistem kaynakları cihazdaki Android'e aittir. strings.xml yalnızca uygulamanıza aittir. İçin bak stackoverflow.com/a/4391811/715269 çözümü
Gangnus

3
Bu, dizelere erişirken bu Fabrika sınıfları için zarif bir çözümdür. Her yerde Bağlamdan geçmekten hoşlanmıyorum. Bu, sadece küresel olarak bir dizenin depolanmasını istediğimiz durumlar için gereksiz bir karmaşa.
Jay Snayder

1
bağlamı bir sınıfa aktarmak ve kullanmaktan daha verimli mi?
SoliQuiD

5
Bu hatayı alıyorumandroid.content.res.Resources$NotFoundException: String resource ID #0x7f0f0061
Ebrahim Karimi

108

Ne yazık ki, dize kaynaklarından herhangi birine erişmenin tek yolu a Context(yani bir Activityveya Service) şeklindedir. Bu durumda genellikle yaptığım şey, arayanın bağlam içinde geçmesini gerektirmektir.


4
Bahşiş için teşekkürler! Ben sadece denedim, ama nedense denediğimde derleme hatası aldım:ctx.getString(ctx.R.string.blah);
SapphireSun

ContextBir Aktivite veya Hizmetten kullanabilmeniz için util tür yöntemlerine argüman yaparım .
MatrixFrog

2
İhtiyacınız yok ctx.R.string.blah, sadece kullanınR.string.blah
Pentium10 23:10

2
Nereden symbol not found errorgeldiğinden emin değilim , ancak Rsınıfın üstüne aktardığınızdan emin olun .
Pentium10

11
Cevap YANLIŞ. Bir sonrakine bak. :-)
Gangnus

33

İçinde MyApplication, uzanır Application:

public static Resources resources;

In MyApplications' onCreate:

resources = getResources();

Artık bu alanı uygulamanızın herhangi bir yerinden kullanabilirsiniz.


Hizmet yoluyla çalışır mı? (Özellikle Android uygulamayı öldürdüğünde ve sadece hizmete başladığında)
Atul

1
Evet, Android kodunuzu Application.onCreate'yi çağırarak yürütmeye başlar ve bundan sonra hizmetinizi çalıştırır.
konmik

23

BTW, sembol bulunamadı hatasının nedenlerinden biri, IDE'nizin android.R ithal etmesi olabilir; senin yerine bir sınıf. Sadece ithalat android.R değiştirmek ; için your.namespace.R içe;

Dize farklı sınıfta görünür hale getirmek için 2 temel şey:

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

Benzersiz Yaklaşım

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

Bu uygulamanın her yerinde çalışacaktır. ( Util sınıfı, İletişim Kutusu, Parça veya uygulamanızdaki herhangi bir sınıf )

(1) ApplicationSınıfınızı oluşturun veya düzenleyin (zaten varsa) .

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) manifest.xml <applicationEtiketinize ad alanı ekleyin .

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

Şimdi gitmekte fayda var. App.getRes().getString(R.string.some_id)Uygulamada herhangi bir yerde kullanın .


1
Ben şahsen bu yaklaşımı seviyorum. Kodun herhangi bir yerinden özel dize kaynakları elde etmek için uygun.
checkmate711

Bu çözümle ilgili herhangi bir güvenlik sorunu var mı?
nibbana

@ user1823280 Hayır, sanmıyorum.
Khemraj

Mükemmel çözüm
Yasiru Nayanajith

4

Bir etkinlikte kullandığınız bir sınıfınız varsa ve bu sınıftaki kaynaklara erişmek istiyorsanız, bir bağlamı sınıfta özel değişken olarak tanımlamanızı ve yapıcıda başlatmanızı öneririm:

public class MyClass (){
    private Context context;

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

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

Faaliyetinizde anında bir sınıf yaratma:

MyClass m=new MyClass(this);

1

Bu kod satırı sorunumu çözdü

Resources.getSystem().getString(R.string.name_of_string_you_want);

Resources.getSystem().getString(R.string.app_name);Uygulama_adı dizesi almak istediğinizde örnek


0

Bu applicationContext, herhangi bir yerden erişebilmeniz için , applicationContextonu kullanabileceğiniz herhangi bir yere gitmenizi sağlar ; Toast, getString(), sharedPreferencesVb

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

}

ApplicationAlt sınıfınızdaki Singleton'u başlatın :

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

Eğer yanılmıyorsam, bu, her yerde applicationContext'e bir kanca verir, onu arayın ApplicationContextSingleton.getInstance.getApplicationContext(); .

AndroidManifest.xmlBu Applicationalt sınıfı kullanmak için güncellemeyi unutmayın :

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

Burada yanlış bir şey görürseniz lütfen bize bildirin, teşekkür ederim. :)


0

Khemraj'ın tepkisinden en iyi yaklaşım:

Uygulama sınıfı

class App : Application() {

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


    // MARK: - Lifecycle

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

}

Manifestteki beyan

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

Sabitler sınıfı

class Localizations {

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

}

kullanma

textView.text = Localizations.info

0

Bağlam ve etkinlik olmadan böyle bir şey kullanmak daha iyidir :

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

0

Her nasılsa, statik değerleri depolamanın haksız çözümlerini beğenmedim, bu yüzden biraz daha uzun çıktı ama test edilebilen temiz bir versiyon.

Bunu yapmanın 2 olası yolu bulundu-

  1. Context.resources parametresini dize kaynağını istediğiniz yere sınıfınıza iletin. Oldukça basit. Param olarak geçmek mümkün değilse ayarlayıcıyı kullanın.

Örneğin

data class MyModel(val resources: Resources) {
    fun getNameString(): String {
        resources.getString(R.string.someString)
    }
}
  1. Veri bağlamayı kullanın (yine de fragman / etkinlik gerektirir)

Okumadan önce: Bu sürüm şunları kullanır: 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>

Etkinlik / Fragment-

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

Bazen metni modeldeki bir alana göre değiştirmeniz gerekebilir. Böylece bu modeli de veri bağlarsınız ve etkinliğiniz / parçanız model hakkında bilgi sahibi olduğundan, değeri çok iyi getirebilir ve ardından dizeyi buna göre veri bağlayabilirsiniz.


0

Bunu Uygulama'yı genişleten bir sınıf oluşturarak Kotlin'de yapabilir ve daha sonra içeriğini kodunuzun herhangi bir yerinde çağırmak için kullanabilirsiniz

Uygulama sınıfınız şöyle görünecek

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

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

AndroidManifest.xml'de Uygulama sınıfınızı bildirin (çok önemli)

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

Bir dize dosyasına erişmek için aşağıdaki kodu kullanın

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

Uygulama bağlamı tek birton olduğundan ve işleminiz başladığında başlatıldığından yerel ayarı çalışma sırasında programlı olarak değiştirirseniz bu çalışmaz.
Szörényi Ádám

-2

İşte yaptığım, MainActivity'de, aşağıda gösterildiği gibi bağlam için statik bir değişken oluşturun:

public static Context mContext;

ve onCreate () 'de buna mContext'i başlatın;

mContext = this;

Ardından, içeriğe erişmek istediğiniz dosyada,

private Context context = MainActivity.mContext;

Şimdi, aşağıdaki gibi bir dize kaynağı alabilirsiniz,

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

-8

Kullandım getContext().getApplicationContext().getString(R.string.nameOfString); benim için.


14
Sizce getContext()her yerde kullanılabilir mi ?!
Hamzeh Soboh

1
Bu soruya bir cevap sağlamaz çünkü getContext () sadece aktiviteler ve fragman sınıflarında mevcuttur
Umar Ata
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.