Android, pobieranie identyfikatora zasobu z ciągu?

158

Muszę przekazać identyfikator zasobu do metody w jednej z moich klas. Musi używać zarówno identyfikatora, na który wskazuje odwołanie, jak i łańcucha. Jak najlepiej to osiągnąć?

Na przykład:

R.drawable.icon

Muszę uzyskać całkowity identyfikator tego, ale potrzebuję również dostępu do ciągu „ikona”.

Byłoby lepiej, gdyby wszystko, co musiałem przekazać do metody, to ciąg znaków „ikona”.

Hamid
źródło
czy w podobny sposób można getId plików zapisanych w pamięci wewnętrznej? Mam problem, ponieważ powinienem podać tablicę identyfikatorów zamiast lokalizacji do mojej galerii (myślę, że to adapter) .. dzięki
Ewoks
@Ewoks: Nie mają identyfikatorów w pamięci wewnętrznej. To tylko obrazy, jeśli chcesz załadować je do kilku obiektów Image i przekazać je, możesz jednak zacząć nowe pytanie.
Hamid

Odpowiedzi:

171

@EboMike: Nie wiedziałem, że Resources.getIdentifier()istnieje.

W moich projektach wykorzystałem do tego następujący kod:

public static int getResId(String resName, Class<?> c) {

    try {
        Field idField = c.getDeclaredField(resName);
        return idField.getInt(idField);
    } catch (Exception e) {
        e.printStackTrace();
        return -1;
    } 
}

Zostałby użyty w ten sposób do uzyskania wartości wartości R.drawable.iconcałkowitej zasobu

int resID = getResId("icon", R.drawable.class); // or other resource class

Właśnie znalazłem post na blogu, w którym napisano, że Resources.getIdentifier()jest to wolniejsze niż używanie refleksji, tak jak ja. Sprawdź to .

Macarse
źródło
8
@Macarse: Obecnie getIdentifier()musi przeprowadzić dwa wyszukiwania odbić. W powyższym przykładzie getIdentifier()użyje odbicia, aby pobrać Drawable.class, a następnie innego wyszukiwania odbicia, aby uzyskać identyfikator zasobu. To tłumaczyłoby różnicę prędkości. Biorąc to pod uwagę, żadne z nich nie są szczególnie szybkie i dlatego naprawdę muszą być buforowane (szczególnie jeśli są używane w pętli lub dla wierszy w a ListView). A dużym problemem podejścia opartego na refleksji jest to, że przyjmuje założenia dotyczące wewnętrznych elementów Androida, które mogą ulec zmianie w niektórych przyszłych wersjach.
CommonsWare
1
@CommonsWare: Zgadza się. Sprawdzałem, jak zaimplementowano Androida i kończy się to natywnym połączeniem. gitorious.org/android-eeepc/base/blobs/… => gitorious.org/android-eeepc/base/blobs/…
Macarse
3
Zamiast tego użyłbym tablicy liczb całkowitych z identyfikatorami. Używanie ciągów znaków jako identyfikatorów nie wydaje się właściwym podejściem.
EboMike
9
Dlaczego contextparametr?
Rudey
14
Wywołanie powinno mieć postać getId ("icon", R.drawable.class); not getResId ("ikona", kontekst, Drawable.class);
Smeet
80

Możesz użyć tej funkcji, aby uzyskać identyfikator zasobu.

public static int getResourceId(String pVariableName, String pResourcename, String pPackageName) 
{
    try {
        return getResources().getIdentifier(pVariableName, pResourcename, pPackageName);
    } catch (Exception e) {
        e.printStackTrace();
        return -1;
    } 
}

Więc jeśli chcesz uzyskać taką funkcję wywołania z możliwością rysowania

getResourceId("myIcon", "drawable", getPackageName());

a dla string możesz to tak nazwać

getResourceId("myAppName", "string", getPackageName());

Przeczytaj to

Azhar
źródło
11
Jaki jest sens tworzenia funkcji, która po prostu wywołuje inną i „obsługuje” ewentualny wyjątek? Bezpośrednio wywołaj metodę getResources (). GetIdentifier ().
Ricardo Meneghin Filho
37

Jest to oparte na odpowiedzi @Macarse.

Użyj tego, aby uzyskać identyfikator zasobów w szybszy i bardziej przyjazny dla kodu sposób.

public static int getId(String resourceName, Class<?> c) {
    try {
        Field idField = c.getDeclaredField(resourceName);
        return idField.getInt(idField);
    } catch (Exception e) {
        throw new RuntimeException("No resource ID found for: "
                + resourceName + " / " + c, e);
    }
}

Przykład:

getId("icon", R.drawable.class);
Daniel De León
źródło
30

Jak uzyskać identyfikator zasobu aplikacji z nazwy zasobu, jest dość powszechnym pytaniem, na które udzielono odpowiedzi.

Odpowiedź na pytanie, jak uzyskać natywny identyfikator zasobu Androida z nazwy zasobu, jest gorsza. Oto moje rozwiązanie, aby uzyskać zasób do rysowania systemu Android według nazwy zasobu:

public static Drawable getAndroidDrawable(String pDrawableName){
    int resourceId=Resources.getSystem().getIdentifier(pDrawableName, "drawable", "android");
    if(resourceId==0){
        return null;
    } else {
        return Resources.getSystem().getDrawable(resourceId);
    }
}

Metodę można zmodyfikować, aby uzyskać dostęp do innych typów zasobów.

Martin Pearman
źródło
Teraz .getResources () getDrawable jest przestarzała. if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP){ return mContext.getDrawable(resourceId); } else { return mContext.getResources().getDrawable(resourceId); }
Evilripper
11

Jeśli potrzebujesz sparować string i int, to co powiesz na Mapę?

static Map<String, Integer> icons = new HashMap<String, Integer>();

static {
    icons.add("icon1", R.drawable.icon);
    icons.add("icon2", R.drawable.othericon);
    icons.add("someicon", R.drawable.whatever);
}
Peter Knego
źródło
9

Możesz użyć Resources.getIdentifier(), chociaż musisz użyć formatu swojego ciągu, ponieważ używasz go w plikach XML, tj package:drawable/icon.

EboMike
źródło
Moja odpowiedź poniżej jest odwrotnością tego. Przekaż identyfikator zasobu, a następnie użyj, getResourceEntryName(id)aby znaleźć nazwę ciągu. Nie trzeba szukać „ikony” w dłuższym tekście.
Steve Waring
8

Tak mi się podobało, to działa dla mnie:

    imageView.setImageResource(context.getResources().
         getIdentifier("drawable/apple", null, context.getPackageName()));
Sarvar Nishonboev
źródło
7
Simple method to get resource ID:

public int getDrawableName(Context ctx,String str){
    return ctx.getResources().getIdentifier(str,"drawable",ctx.getPackageName());
}
Ivan Vovk
źródło
1
Byłoby lepiej, gdybyś podał więcej informacji do swojej odpowiedzi.
xMRi
6

Prosty sposób na uzyskanie identyfikatora zasobu z ciągu. Tutaj resourceName to nazwa ImageView zasobów w rozciągliwej folderze, który jest zawarty w pliku XML, jak również.

int resID = getResources().getIdentifier(resourceName, "id", getPackageName());
ImageView im = (ImageView) findViewById(resID);
Context context = im.getContext();
int id = context.getResources().getIdentifier(resourceName, "drawable",
context.getPackageName());
im.setImageResource(id);
Muhammad Adil
źródło
Dzięki stary, to było naprawdę pomocne. Dużo szukałem i nie udało mi się. Widząc twoją odpowiedź stwierdziłem, że drugi parametr dla getIdentifiermusi być id. Nie było to nawet wspomniane na stronie programistów Androida. skąd masz te informacje?
Prakash GPz
4

Ponieważ powiedziałeś, że chcesz przekazać tylko jeden parametr i wydawało się, że nie ma znaczenia który, możesz przekazać identyfikator zasobu, a następnie znaleźć nazwę ciągu, w ten sposób:

String name = getResources().getResourceEntryName(id);

Może to być najbardziej efektywny sposób uzyskania obu wartości. Nie musisz martwić się znajdowaniem tylko części „ikony” z dłuższego ciągu.

Steve Waring
źródło
2

W twoim res / layout / my_image_layout.xml

<LinearLayout ...>
    <ImageView
        android:id="@+id/row_0_col_7"
      ...>
    </ImageView>
</LinearLayout>

Aby pobrać ten ImageView przez jego wartość @ + id, w kodzie java wykonaj następujące czynności:

String row = "0";
String column= "7";
String tileID = "row_" + (row) + "_col_" + (column);
ImageView image = (ImageView) activity.findViewById(activity.getResources()
                .getIdentifier(tileID, "id", activity.getPackageName()));

/*Bottom code changes that ImageView to a different image. "blank" (R.mipmap.blank) is the name of an image I have in my drawable folder. */
image.setImageResource(R.mipmap.blank);  
Gen
źródło
2

Podejście Kotlina

inline fun <reified T: Class<R.drawable>> T.getId(resourceName: String): Int {
            return try {
                val idField = getDeclaredField (resourceName)
                idField.getInt(idField)
            } catch (e:Exception) {
                e.printStackTrace()
                -1
            }
        }

Stosowanie:

val resId = R.drawable::class.java.getId("icon")
Arsenius
źródło
1

W MonoDroid / Xamarin.Android możesz:

 var resourceId = Resources.GetIdentifier("icon", "drawable", PackageName);

Ale ponieważ GetIdentifier nie jest zalecany w Androidzie - możesz użyć Reflection w następujący sposób:

 var resourceId = (int)typeof(Resource.Drawable).GetField("icon").GetValue(null);

gdzie proponuję spróbować / złapać lub zweryfikować przekazywane ciągi.

Daniele D.
źródło
1

Aby uzyskać identyfikator do rysowania z nazwy zasobu String, używam tego kodu:

private int getResId(String resName) {
    int defId = -1;
    try {
        Field f = R.drawable.class.getDeclaredField(resName);
        Field def = R.drawable.class.getDeclaredField("transparent_flag");
        defId = def.getInt(null);
        return f.getInt(null);
    } catch (NoSuchFieldException | IllegalAccessException e) {
        return defId;
    }
}
bitvale
źródło