从 Resources 对象中检索所有 Drawable 资源

Posted

技术标签:

【中文标题】从 Resources 对象中检索所有 Drawable 资源【英文标题】:Retrieving all Drawable resources from Resources object 【发布时间】:2011-03-14 09:23:03 【问题描述】:

在我的 android 项目中,我想遍历整个 Drawable 资源集合。通常,您只能使用以下方式通过其 ID 检索特定资源:

InputStream is = Resources.getSystem().openRawResource(resourceId)

但是,我想获取所有Drawable 资源,而我不会事先知道他们的 ID。有没有我可以循环使用的集合,或者是否有一种方法可以获取给定项目中资源的资源 ID 列表?

或者,我有没有办法在 Java 中从 R.drawable 静态类中提取所有属性值?

【问题讨论】:

【参考方案1】:

好的,这感觉有点 hack-ish,但这是我通过 Reflection 想出的。 (注意resources 是类android.content.res.Resources 的一个实例。)

final R.drawable drawableResources = new R.drawable();
final Class<R.drawable> c = R.drawable.class;
final Field[] fields = c.getDeclaredFields();

for (int i = 0, max = fields.length; i < max; i++) 
    final int resourceId;
    try 
        resourceId = fields[i].getInt(drawableResources);
     catch (Exception e) 
        continue;
    
    /* make use of resourceId for accessing Drawables here */

如果有人有更好的解决方案,可以更好地利用我可能不知道的 Android 调用,我绝对希望看到他们!

【讨论】:

这是获取我能找到的资源(相对于资产)的唯一方法。请注意,您不需要 drawableResources。由于 R 的所有字段都是静态的,因此 getInt() 可以取 null。 只是一个需要注意的细节:java.lang.reflect.Field 这会在什么时候被调用?我创建了一个返回图像数组的函数,但我收到一条错误消息,指出该数组为空,因此它没有长度 @SteveBlackwell @PjRigor 如果不看一些代码,很难知道为什么会得到这个结果。最好发布一个新问题。【参考方案2】:

我使用 getResources().getIdentifier 扫描资源文件夹中按顺序命名的图像。为了安全起见,我决定在第一次创建活动时缓存图像 ID:

    private void getImagesIdentifiers() 

    int resID=0;        
    int imgnum=1;
    images = new ArrayList<Integer>();

    do             
        resID=getResources().getIdentifier("img_"+imgnum, "drawable", "InsertappPackageNameHere");
        if (resID!=0)
            images.add(resID);
        imgnum++;
    
    while (resID!=0);

    imageMaxNumber=images.size();

【讨论】:

【参考方案3】:

我采纳了 Matt Huggins 的好答案,并对其进行了重构以使其更通用:

public static void loadDrawables(Class<?> clz)
    final Field[] fields = clz.getDeclaredFields();
    for (Field field : fields) 
        final int drawableId;
        try 
            drawableId = field.getInt(clz);
         catch (Exception e) 
            continue;
        
        /* make use of drawableId for accessing Drawables here */
       

用法:

loadDrawables(R.drawable.class);

【讨论】:

【参考方案4】:

你应该使用 Raw 文件夹和 AssetManager,但如果你想使用 drawables,为什么不呢,这里是如何...

假设我们有一个很长的 JPG 可绘制文件列表,并且我们想要获取所有资源 ID,而无需一一检索(R.drawable.pic1、R.drawable.pic2 等)

//first we create an array list to hold all the resources ids
ArrayList<Integer> imageListId = new ArrayList<Integer>();

//we iterate through all the items in the drawable folder
Field[] drawables = R.drawable.class.getFields();
for (Field f : drawables) 
    //if the drawable name contains "pic" in the filename...
    if (f.getName().contains("image"))
        imageListId.add(getResources().getIdentifier(f.getName(), "drawable", getPackageName()));


//now the ArrayList "imageListId" holds all ours image resource ids
for (int imgResourceId : imageListId) 
     //do whatever you want here

【讨论】:

【参考方案5】:

添加一张名为 aaaa 的图片和另一张名为 zzzz 的图片,然后遍历以下内容:

public static void loadDrawables() 
  for(long identifier = (R.drawable.aaaa + 1);
      identifier <= (R.drawable.zzzz - 1);
      identifier++) 
    String name = getResources().getResourceEntryName(identifier);
    //name is the file name without the extension, indentifier is the resource ID
  

这对我有用。

【讨论】:

我喜欢这个 hack 背后的创意。 ;) 多么有创意啊!非常感谢【参考方案6】:

如果您发现自己想要这样做,您可能误用了资源系统。如果您想遍历 .apk 中包含的文件,请查看资产和 AssetManager

【讨论】:

谢谢,我去看看。我正在尝试将纹理加载到内存中以在 OpenGL 游戏中使用。 这行得通,并且不太特定于项目(由于类R 是特定于项目的),我喜欢。唯一的区别是我必须使用“assets”文件夹而不是“res”文件夹。 这不是答案。【参考方案7】:

我猜反射代码会起作用,但我不明白你为什么需要这个。

一旦安装了应用程序,Android 中的资源就是静态的,因此您可以拥有资源列表或数组。比如:

<string-array name="drawables_list">
    <item>drawable1</item>
    <item>drawable2</item>
    <item>drawable3</item>
</string-array>

您可以通过Activity 获得它:

getResources().getStringArray(R.array.drawables_list);

【讨论】:

这行得通,但它的问题是每次我向文件夹添加一个可绘制对象时,我还必须更新这个字符串数组。我正在寻找更自动化的东西。【参考方案8】:

这样做:

Field[] declaredFields = (R.drawable.class).getDeclaredFields();

【讨论】:

那么如何从字段对象中获取资源? 可以这样写代码:imageView.setImageDrawable(Utils.getDrawable(declaredFields.get(position).getName(), context))【参考方案9】:

OP 想要可绘制对象,而我需要布局。这就是我想出的布局。 name.startsWith 业务让我忽略系统生成的布局,因此您可能需要稍微调整一下。通过修改clz 的值,这应该适用于任何资源类型。

public static Map<String,Integer> loadLayouts()
    final Class<?> clz = R.layout.class;
    Map<String,Integer> layouts = new HashMap<>();
    final Field[] fields = clz.getDeclaredFields();
    for (Field field : fields) 
        String name = field.getName();
        if (
                !name.startsWith("abc_")
                && !name.startsWith("design_")
                && !name.startsWith("notification_")
                && !name.startsWith("select_dialog_")
                && !name.startsWith("support_")
        ) 
            try 
                layouts.put(field.getName(), field.getInt(clz));
             catch (Exception e) 
                continue;
            
        
    
    return layouts;

【讨论】:

【参考方案10】:

使用我的代码

R.drawable drawableResources = new R.drawable();
Class<R.drawable> c = R.drawable.class;
Field[] fields = c.getDeclaredFields();

for (int i = 0, max = fields.length; i < max; i++) 
    final int resourceId;
    try 
        resourceId = fields[i].getInt(drawableResources);
        // call save with param of resourceId
        SaveImage(resourceId);
     catch (Exception e) 
        continue;
    


...

public void SaveImage(int resId)
    if (!CheckExternalStorage()) 
        return;
    

    Bitmap bmp = BitmapFactory.decodeResource(getResources(), resID);
    try 
        File dir = new File(path);
        if (!dir.exists()) 
            dir.mkdirs();
        
        OutputStream fOut = null;
        File file = new File(path, "image1.png");
        file.createNewFile();
        fOut = new FileOutputStream(file);
        bmp.compress(Bitmap.CompressFormat.PNG, 100, fOut);
        fOut.flush();
        fOut.close();
        MediaStore.Images.Media.insertImage(this.getContentResolver(), file.getAbsolutePath(), file.getName(), file.getName());
        Log.i(LOGTAG, "Image Written to Exterbal Storage");

     catch (Exception e) 
        Log.e("saveToExternalStorage()", e.getMessage());
    

【讨论】:

【参考方案11】:

在 Kotlin 中创建一组可绘制对象:

    val drawablesFields: Array<Field> = drawable::class.java.fields
    val drawables: ArrayList<Drawable> = ArrayList()
    for (field in drawablesFields) 
        context?.let  ContextCompat.getDrawable(it, field.getInt(null)) ?.let 
            drawables.add (
                it
            )
        
    

【讨论】:

以上是关于从 Resources 对象中检索所有 Drawable 资源的主要内容,如果未能解决你的问题,请参考以下文章

从 Firestore 中检索文档引用的值

在postgresql中如何从数据库中检索出所有的表名

使用 underscore.js 从对象/数组中仅检索一个字段

Javascript:从 sessionStorage 中检索所有密钥?

从 Realm 数据库中检索单个对象的正确方法

如何从 Cloud Firestore 上的对象中检索值?迅速