getString นอกบริบทหรือกิจกรรม


260

ฉันได้พบสิ่งที่ยอดเยี่ยมR.stringมากสำหรับการป้องกันรหัส hardcoded และฉันต้องการใช้มันในคลาสยูทิลิตี้ที่ทำงานกับรุ่นในแอปพลิเคชันของฉันเพื่อสร้างผลลัพธ์ ตัวอย่างเช่นในกรณีนี้ฉันกำลังสร้างอีเมลจากโมเดลภายนอกกิจกรรม

มันเป็นไปได้ที่จะใช้getStringที่อยู่นอกContextหรือActivity ? ฉันคิดว่าฉันสามารถผ่านในกิจกรรมปัจจุบัน แต่ดูเหมือนว่าไม่จำเป็น โปรดแก้ไขให้ฉันถ้าฉันผิด!

แก้ไข: เราสามารถเข้าถึงทรัพยากรโดยไม่ใช้Contextหรือไม่


4
โดยการส่งบริบทไปยังคลาสที่จะใช้สตริงคุณจะส่งข้อมูลเกี่ยวกับแอปที่ใช้ภาษา (en, es, etc) ที่ใช้ภาษา (en, es, ฯลฯ ) ดังนั้นถ้าคุณมีสอง strings.xml มันจะรู้ว่าควรใช้อันไหน
กีฬา

คำตอบ:


440

ใช่เราสามารถเข้าถึงทรัพยากรโดยไม่ต้องใช้ "บริบท"

คุณสามารถใช้ได้:

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

... ทุกที่ในแอปพลิเคชันของคุณแม้ในการประกาศคงที่ แต่น่าเสียดายที่จะสนับสนุนทรัพยากรระบบเท่านั้น

สำหรับทรัพยากรในท้องถิ่นให้ใช้วิธีนี้ มันไม่สำคัญ แต่ใช้งานได้


17
ทรัพยากรระบบหมายถึงอะไร? strings.xml เป็นทรัพยากรระบบหรือไม่ สำหรับฉันมันใช้งานไม่ได้พูดว่าหาทรัพยากรไม่ได้
kirhgoff

6
ทรัพยากรระบบเป็นของ Android บนอุปกรณ์ strings.xml เป็นของแอปพลิเคชันของคุณเท่านั้น ค้นหาstackoverflow.com/a/4391811/715269โซลูชัน
Gangnus

3
นี่เป็นโซลูชันที่สง่างามสำหรับคลาส Factory เหล่านั้นเมื่อเข้าถึงสตริง ฉันไม่สนุกกับการผ่านตามบริบททุกที่ นั่นเป็นเพียงความยุ่งเหยิงที่ไม่จำเป็นสำหรับกรณีที่เราเพียงแค่ต้องการสตริงที่จัดเก็บทั่วโลก
Jay Snayder

1
สิ่งนี้มีประสิทธิภาพมากกว่าการส่งบริบทไปยังชั้นเรียนและใช้มันหรือไม่?
SoliQuiD

5
ฉันได้รับข้อผิดพลาดนี้android.content.res.Resources$NotFoundException: String resource ID #0x7f0f0061
Ebrahim Karimi

108

น่าเสียดายที่วิธีเดียวที่คุณสามารถเข้าถึงทรัพยากรสตริงได้คือContext(เช่นActivityหรือService) สิ่งที่ฉันมักจะทำในกรณีนี้คือเพียงต้องการให้ผู้โทรผ่านในบริบท


4
ขอบคุณสำหรับทิป! ฉันพยายามนี้ แต่ด้วยเหตุผลบางอย่างฉันได้รวบรวมข้อผิดพลาดเมื่อฉันพยายาม:ctx.getString(ctx.R.string.blah);
SapphireSun

ฉันจะโต้แย้งวิธีการใช้ประเภทContextเพื่อให้คุณสามารถใช้จากกิจกรรมหรือบริการ
MatrixFrog

2
คุณไม่จำเป็นต้องctx.R.string.blahใช้R.string.blah
Pentium10

2
ฉันไม่แน่ใจว่ามาจากไหนsymbol not found errorแต่ให้แน่ใจว่าคุณได้Rนำเข้าชั้นเรียน
Pentium10

11
คำตอบคือ FALSE เยี่ยมชมอันต่อไป :-)
Gangnus

33

ในMyApplicationซึ่งขยายApplication:

public static Resources resources;

ในMyApplication's onCreate:

resources = getResources();

ตอนนี้คุณสามารถใช้ฟิลด์นี้จากที่ใดก็ได้ในแอปพลิเคชันของคุณ


มันจะทำงานผ่านบริการหรือไม่ (โดยเฉพาะอย่างยิ่งเมื่อ Android ฆ่าแอพและเริ่มให้บริการเท่านั้น)
Atul

1
ใช่ Android เริ่มรันโค้ดของคุณโดยเรียก Application.onCreate และหลังจากนั้นก็รันบริการของคุณ
konmik

23

BTW หนึ่งในเหตุผลของสัญลักษณ์ไม่พบข้อผิดพลาดอาจเป็นได้ว่า IDE ของคุณนำเข้า android.R; เรียนแทนคุณคนเดียว เพียงแค่เปลี่ยนการนำเข้า android.R; เพื่อนำเข้า your.namespace.R;

ดังนั้น 2 สิ่งพื้นฐานในการมองเห็นสตริงในคลาสอื่น:

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

วิธีการที่ไม่เหมือนใคร

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

สิ่งนี้จะใช้ได้ทุกที่ในแอป (ใช้คลาสโต้ตอบกล่องแยกส่วนหรือคลาสใด ๆ ในแอปของคุณ )

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

}

(2) เพิ่มฟิลด์ชื่อในmanifest.xml <applicationแท็กของคุณ

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

ตอนนี้คุณก็พร้อมแล้ว ใช้งานApp.getRes().getString(R.string.some_id)ได้ทุกที่ในแอป


1
ฉันชอบวิธีนี้เป็นการส่วนตัว สะดวกในการรับทรัพยากรสตริงที่กำหนดเองจากที่ใดก็ได้ในรหัส
checkmate711

มีปัญหาด้านความปลอดภัยกับโซลูชันนี้หรือไม่
นิพพาน

@ user1823280 ไม่ฉันไม่คิดว่า
Khemraj

โซลูชั่นที่สมบูรณ์แบบ
Yasiru Nayanajith

4

หากคุณมีคลาสที่คุณใช้ในกิจกรรมและคุณต้องการเข้าถึง ressource ในคลาสนั้นฉันขอแนะนำให้คุณกำหนดบริบทเป็นตัวแปรส่วนตัวในคลาสและเริ่มต้นในตัวสร้าง:

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

0

สิ่งนี้จะทำให้คุณเข้าถึงได้applicationContextจากทุกที่ช่วยให้คุณapplicationContextสามารถใช้งานได้ทุกที่ Toast, getString(), sharedPreferencesฯลฯ

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

}

เริ่มต้น Singleton ใน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);
    }
}

หากฉันไม่ผิดมันจะช่วยให้คุณเชื่อมต่อกับแอปพลิเคชันได้ทุกที่เรียกใช้ด้วย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"
    >

โปรดแจ้งให้เราทราบหากคุณเห็นสิ่งผิดปกติที่นี่ขอบคุณ :)


0

วิธีที่ดีที่สุดจากการตอบสนองของเขมราฐ:

คลาสแอป

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


0

อย่างใดไม่ชอบโซลูชันแฮ็คของการจัดเก็บค่าคงที่จึงเกิดขึ้นอีกเล็กน้อย แต่รุ่นที่สะอาดซึ่งสามารถทดสอบได้เช่นกัน

พบ 2 วิธีที่เป็นไปได้ที่จะทำ -

  1. ส่งผ่าน context.resources เป็นพารามิเตอร์ไปยังคลาสของคุณที่คุณต้องการทรัพยากรสตริง ค่อนข้างง่าย หากไม่สามารถส่งผ่านพารามิเตอร์ได้ให้ใช้ตัวตั้งค่า

เช่น

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>

กิจกรรม / Fragment-

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

บางครั้งคุณต้องเปลี่ยนข้อความตามฟิลด์ในโมเดล ดังนั้นคุณจะผูกข้อมูลโมเดลนั้นไว้เช่นกันและเนื่องจากกิจกรรม / แฟรกเมนต์ของคุณรู้เกี่ยวกับโมเดลคุณจึงสามารถดึงค่าได้เป็นอย่างดีจากนั้น data-ผูกสตริงตามนั้น


0

คุณสามารถทำได้ในKotlinโดยการสร้างคลาสที่ขยายแอปพลิเคชันจากนั้นใช้บริบทเพื่อเรียกทรัพยากรที่ใดก็ได้ในรหัสของคุณ

คลาสแอปของคุณจะมีลักษณะเช่นนี้

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

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

ประกาศคลาสแอปพลิเคชันของคุณใน 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)

สิ่งนี้จะไม่ทำงานหากคุณเปลี่ยนสถานที่โดยทางโปรแกรมในระหว่างรันไทม์เนื่องจากบริบทของแอปพลิเคชันเป็นแบบซิงเกิลและเริ่มต้นเมื่อกระบวนการของคุณเริ่มต้น
SzörényiÁdám

-2

นี่คือสิ่งที่ฉันทำใน MainActivity ของคุณสร้างตัวแปรแบบคงที่สำหรับบริบทที่แสดงด้านล่าง:

public static Context mContext;

และใน onCreate () เริ่มต้น mContext นี้;

mContext = this;

จากนั้นในไฟล์ที่คุณต้องการเข้าถึงบริบทให้พูดว่า

private Context context = MainActivity.mContext;

ตอนนี้คุณสามารถรับทรัพยากรสตริงในลักษณะดังต่อไปนี้

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

-8

ฉันใช้ getContext().getApplicationContext().getString(R.string.nameOfString); มันได้ผลกับฉัน


14
คุณคิดว่าgetContext()ใช้ได้ทุกที่หรือไม่!
Hamzeh Soboh

1
สิ่งนี้ไม่ได้ให้คำตอบสำหรับคำถามเพราะ getContext () มีเฉพาะในกิจกรรมและชั้นเรียนเศษ
Umar Ata
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.