Android: Jak uzyskać ciąg z zasobów przy użyciu jego nazwy?

553

Chciałbym mieć 2 języki dla interfejsu użytkownika i osobne wartości dla nich w moim pliku zasobów res\values\strings.xml:

<string name="tab_Books_en">Books</string>
<string name="tab_Quotes_en">Quotes</string>
<string name="tab_Questions_en">Questions</string>
<string name="tab_Notes_en">Notes</string>
<string name="tab_Bookmarks_en">Bookmarks</string>

<string name="tab_Books_ru">Книги</string>
<string name="tab_Quotes_ru">Цитаты</string>
<string name="tab_Questions_ru">Вопросы</string>
<string name="tab_Notes_ru">Заметки</string>
<string name="tab_Bookmarks_ru">Закладки</string>

Teraz muszę dynamicznie pobierać te wartości w mojej aplikacji:

spec.setContent(R.id.tabPage1);
String pack = getPackageName();
String id = "tab_Books_" + Central.lang;
int i = Central.Res.getIdentifier(id, "string", pack);
String str = Central.Res.getString(i);

Mój problem jest taki i = 0.

Dlaczego w moim przypadku to nie działa?

Ivan
źródło
1
Czy jesteś pewien, że Central.lang jest albo enalbo ru?
K-ballo,
1
Potrzebne są dodatkowe informacje, aby sprawdzić kod. jaki jest stan każdej zmiennej przed uzyskaniem? W każdym razie powinieneś użyć domyślnej obsługi lokalizacji w Androidzie, aby uprościć sprawę.
Alin

Odpowiedzi:

1069

Odnośnik, do którego się odwołujesz, wydaje się działać z ciągami generowanymi w czasie wykonywania. Ciągi z pliku strings.xml nie są tworzone w czasie wykonywania. Możesz je zdobyć za pośrednictwem

String mystring = getResources().getString(R.string.mystring);

getResources()jest metodą Contextklasy. Jeśli znajdujesz się w a Activitylub Service(który rozszerza kontekst), możesz użyć go tak jak w tym fragmencie.

Należy również pamiętać, że cała zależność językowa może być rozwiązana przez platformę Android . Po prostu utwórz różne foldery dla każdego języka. Jeśli angielski jest Twoim domyślnym językiem, po prostu wstaw ciągi angielskie res/values/strings.xml. Następnie utwórz nowy folder values-rui umieść w nim rosyjskie łańcuchy o identycznych nazwach res/values-ru/strings.xml. Od tego momentu Android wybiera właściwy dla Ciebie, w zależności od ustawień regionalnych urządzenia, zarówno podczas połączenia, jak getString()i podczas odwoływania się do ciągów znaków w języku XML za pośrednictwem @string/mystring. Te z res/values/strings.xmlsą rezerwowe, jeśli nie masz folderu obejmującego ustawienia narodowe użytkowników, ten zostanie użyty jako wartości domyślne.

Aby uzyskać więcej informacji, zobacz Lokalizacja i udostępnianie zasobów .


źródło
23
Jeśli jesteś w android.support.v4.app.Fragment, możesz po prostu zadzwonić getString(R.string.mystring)bezpośrednio.
JaKXz
3
Właśnie się nawadniałem. Dlaczego robi się to (przez Google) w tak skomplikowany sposób? Najpierw uzyskaj numeryczny identyfikator tajemnicy (z obiektu R), a następnie uzyskaj ciąg według tego identyfikatora? A gdzie faktycznie znajduje się para „ID-of-mystring => actualValue”? O ile wiem tajemnica => ID-tajemnicy znajduje się w R.java, ale o to chodzi :)
Lukáš Řádek
2
upewnij się, że „R” to R twojego projektu, a nie domyślny android R.
ralphgabb
2
Być może była to odpowiedź, która była potrzebna, ale nie o to proszono! Aby dynamicznie uzyskiwać dostęp do zasobu ciągów według nazwy, zobacz odpowiedź od @leonvian ... która powinna być zaakceptowana przez IMO
Chris Hatton
321

Mam ten sam problem. Ale poniższy kod działa dla mnie: Sprawdź, czy nazwa pakietu jest poprawna. Musisz odszukać pakiet główny aplikacji na Androida.

private String getStringResourceByName(String aString) {
      String packageName = getPackageName();
      int resId = getResources().getIdentifier(aString, "string", packageName);
      return getString(resId);
    }
leonvian
źródło
9
W przypadku, gdy ktoś ma ku temu dobry powód (na przykład pliki danych zawierają niestandardowy ciąg znaków, który decyduje, który ciąg zasobów powinien zostać wyświetlony lub jeśli ten ciąg zostanie pobrany z Internetu) - chciałbym zaznaczyć, że to rozwiązanie jest poprawne. Szczególnie popraw część, w której znajduje się typ zasobu, stringa nie strings. Ponieważ jest to logiczne (podobnie jak reszta Androida). Dziękuję za to (i więcej), @leonvian. :-)
Ivan Vučica
2
@Sameer, aby uzyskać tablicę przez ciągi, wystarczy użyć: res.getStringArray (R.array.planets_array); Rzuć okiem na ten oficjalny link: developer.android.com/guide/topics/resources/…
leonvian
3
Fajne. Aby pozbyć się z oddzielnej deklaracji metody, może to być „uproszczony” w taki sposób: String someStringFromXML = getString(getResources().getIdentifier("some_string_name", "string", getPackageName()));.
Neurotransmitter
80

Nie tylko z działań:

    public static String getStringByIdName(Context context, String idName) {
        Resources res = context.getResources();
        return res.getString(res.getIdentifier(idName, "string", context.getPackageName()));
    }
konmik
źródło
działało świetnie, dziękuję
Mosa
39
getResources().getString(getResources().getIdentifier("propertyName", "string", getPackageName()))
TOUDIdel
źródło
26

Dodałbym coś do rozwiązania leonvian, więc jeśli przypadkiem łańcuch nie zostanie znaleziony wśród zasobów (zwróci wartość 0, to nie jest prawidłowy kod zasobu), funkcja może coś zwrócić:

private String getStringResourceByName(String aString) {
    String packageName = getPackageName();
    int resId = getResources()
            .getIdentifier(aString, "string", packageName);
    if (resId == 0) {
        return aString;
    } else {
        return getString(resId);
    }
}
Miguel Rivero
źródło
15

Najlepsze podejście

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

Działa wszędzie (Utils, Modele również).

Przeczytałem wszystkie odpowiedzi, wszystkie odpowiedzi mogą zrobić twoją pracę.

  • Możesz użyć getString(R.string.some_string_id)w obu Activitylub Fragment.
  • Możesz użyć Context.getString(R.string.some_string_id), gdy nie masz bezpośredniego dostępu do getString()metody. Jak Dialog.

Problem

Kiedy nie masz Contextdostępu , jak metoda w swojej Utilklasie.

Załóżmy poniższą metodę bez kontekstu.

public void someMethod(){
    ...
    // can't use getResource() or getString() without Context.
}

Teraz przejdziesz Contextjako parametr w tej metodzie i użyjeszgetString().

public void someMethod(Context context){
    ...
    context.getString(R.string.some_id);
}

To co robię jest

public void someMethod(){
    ...
    App.getAppResources().getString(R.string.some_id)
}

Co? Jest bardzo prosty w użyciu w dowolnym miejscu w aplikacji!

Oto rozwiązanie, dzięki któremu możesz uzyskać dostęp do zasobów z dowolnego miejsca Util class.

import android.app.Application;
import android.content.res.Resources;

public class App extends Application {
    private static Resources resources;

    @Override
    public void onCreate() {
        super.onCreate();

        resources = getResources();
    }

    public static Resources getAppResources() {
        return resources;
    }

}

Dodaj pole nazwy do manifest.xml <applicationtagu.

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

Teraz możesz już iść. Używaj w App.getAppResources().getString(R.string.some_id)dowolnym miejscu aplikacji.

Khemraj
źródło
+1 proste i czyste rozwiązanie. Zauważ niepoprawną pisownię getResourses, getResourcesspowoduje to zastąpienie. Również wzór singletonu wydaje się niepotrzebny, być może można go pominąć. Jakieś problemy z wyciekiem pamięci w tym rozwiązaniu?
Xarvalus
@Xarvalus Czy powoduje to wyciek pamięci?
Khemraj
w mojej aplikacji wszystko w porządku :) po prostu zastanawiam się, czy ktoś miał z tym jakiś problem. Dam znać, jeśli napotkam jakąkolwiek pułapkę.
Xarvalus
1
Przeciek pamięci Xarvalus zwykle występuje w miejscu, w którym używana jest zmienna, nawet klasa nadrzędna jest zniszczona. Jak w działaniach, fragmentach. Nie sądzę, aby miało to miejsce w tym przypadku.
Khemraj
14

Prosty sposób na przeniesienie łańcucha zasobów z łańcucha do TextView. Tutaj nazwa_zasobu to nazwa zasobu

int resID = getResources().getIdentifier(resourceName, "string", getPackageName());
textview.setText(resID);
Muhammad Adil
źródło
7

Jeśli nie masz odwołania do działania, możesz użyć swojego kontekstu w następujący sposób:

getContext().getString(R.string.your_string_name);
Hazlo8
źródło
4

Istnieje również zestaw predefiniowanych ciągów Androida, takich jak „Ok”, „Anuluj” i wiele innych - więc nie musisz deklarować wszystkich. Są dostępne po prostu przez:

getString(android.R.string.ok)

(W tym przypadku ciąg „Ok”). BTW, dostępne są również inne zasoby Androida, na przykład obrazy ikon itp.

forsberg
źródło
2

Ciąg myString = getString (R.string.mystring);

łatwy sposób

Avinash
źródło
1

Możesz wypróbować to w działaniu:

getResources().getString(R.string.your string name);

W innych sytuacjach, takich jak fragmenty, ... używaj

getContext().getResources().getString(R.string.your string name);
M Shafaei N.
źródło
0

Dla bezpieczeństwa należy dodać: mContext.getResources (). GetString (R.string.your_string);

mContext może być: kontekstem w onAttach () fragmentu lub w działaniu.

O Thạnh Ldt
źródło
0

Jeśli nie chcesz dostać się do działania lub fragmnet, to:

getContext().getResources().getString(R.string.string_name);

Jeśli chcesz pobrać go z klasy spoza działania lub fragmentu, w którym nie masz kontekstu działania, użyj kontekstu aplikacji:

getApplicationContext().getResources().getString(R.string.string_name);
rohegde7
źródło
0
R.string.<string_name>

Użyj tej linii bezpośrednio w pliku Java. Nie komplikuj.

Owais Yosuf
źródło