556

In the Android SDK documentation, all of the examples used with the @drawable/my_image xml syntax directly address images that are stored in the res/drawable directory in my project.

I am wondering if it is explicitly not okay to create a sub directory within the drawable directory.

For example, if I had the following directory layout:

res/drawable
-- sandwiches
  -- tunaOnRye.png
  -- hamAndSwiss.png
-- drinks
  -- coldOne.png
  -- hotTea.png

Could I reference the image of a tuna salad sandwich as @drawable/sandwiches/tunaOnRye

Or do I have to keep the hierarchy flat in the drawable directory.

user2864740
  • 60,010
  • 15
  • 145
  • 220
Pepper Lebeck-Jobe
  • 5,870
  • 2
  • 19
  • 13

22 Answers22

591

No, the resources mechanism doesn't support subfolders in the drawable directory, so yes - you need to keep that hierarchy flat.

The directory layout you showed would result in none of the images being available.

From my own experiments it seems that having a subfolder with any items in it, within the res/drawable folder, will cause the resource compiler to fail -- preventing the R.java file from being generated correctly.

Reto Meier
  • 96,655
  • 18
  • 100
  • 72
  • 154
    As of Android 2.2, this doesn't cause a compiler error, but any subdirectories are ignored when generating the R class. This really sucks, and makes it hard to manage larger projects. =/ – Nik Reiman Jul 28 '10 at 08:42
  • 79
    Totally agree. They need to come up with a better solution supporting sub-folders. It can't be that hard. – znq Sep 06 '10 at 17:22
  • 16
    Hopefully this will be resolved soon, i've got over 100 assets, and even then i coded some of them out. Total night mare trying to manage any marginally complex project. – Emile Jan 06 '11 at 16:40
  • 16
    This is the corresponding Issue in the Android issue tracker: http://code.google.com/p/android/issues/detail?id=2018 – espinchi Jul 20 '11 at 17:55
  • 3
    I'm shocked about that! I'm trying to build a game and I have lots of images. Looks like I'm going to have lots of hard times. – Evren Ozturk Feb 18 '12 at 18:30
  • 14
    100 assets... Try it with 16 thousand assets. – Mytheral Jul 23 '12 at 18:22
  • 2
    I just flattened a bunch of GIF's into animations... I am not a happy camper about the messy folder. – Someone Somewhere Oct 16 '12 at 18:39
  • 1
    for a half year I developing application on android platform, this issue always make me working hard to manage resources.. -,-a – caknia Feb 17 '13 at 01:56
  • Just discovered this issue by trying it, assuming it would work. It doesn't ... not cool! Makes me want to write something handle it myself. – Blake Miller Mar 29 '13 at 17:37
  • 3
    Now, according to the [article](https://code.google.com/p/android/issues/detail?id=2018#c64) it appears that if you use the Gradle build system you **can** have sub directories. However, Google will **not** be implementing this for other build systems (e.g. Ant, etc.). Relevant Comment: "Marking this as released. This is largely possible in the Gradle build system as it exists today, and we won't be implementing this for other build systems" – Forrest Bice Jan 25 '14 at 03:00
  • 5
    now I know this I am going to name using underscores, it seems the only way. E.g. virtualfolder_image1.jpg – Martin Capodici Jun 23 '14 at 09:32
  • I have found that subfolders aren't really ignored.. they are parsed (well.. at least they are read to see what kind of resource is there), but they don't get packaged into the apk. Pre-gradle project I worked on had flavors defined inside the `res` directory, which caused clean builds to last over 10 minutes (yes, a lot of resources, but still..). When we moved those outside of `res` directory, it dropped down to 3 minutes (still not using Gradle). – milosmns Dec 22 '15 at 16:49
  • 1
    There actually seems to be some action going on in a 'newer' Android issue: https://issuetracker.google.com/issues/37009920#comment9. Hope this gets solved soon. Been waiting for this for years. – Wirling Feb 26 '19 at 06:55
  • 3
    2022... we still don't have this simple feature. – NightSkyCode Jan 21 '22 at 12:59
  • @MartinCapodici idea is ok-ish. But it would still be looking at 1000 lines of drawables instead of 10. This is why I always feel Android Studio is MILES behind XCode. – GeneCode Apr 08 '23 at 13:51
163

The workaround I'm using (and the one Android itself seems to favor) is to essentially substitute an underscore for a forward slash, so your structure would look something like this:

sandwich_tunaOnRye.png
sandwich_hamAndSwiss.png
drink_coldOne.png
drink_hotTea.png

The approach requires you to be meticulous in your naming and doesn't make it much easier to wrangle the files themselves (if you decided that drinks and sandwiches should really all be "food", you'd have to do a mass rename rather than simply moving them to the directory); but your programming logic's complexity doesn't suffer too badly compared to the folder structure equivalent.

This situation sucks indeed. Android is a mixed bag of wonderful and terrible design decisions. We can only hope for the latter portion to get weeded out with all due haste :)

Cheezmeister
  • 4,895
  • 3
  • 31
  • 37
  • 33
    Just a note that capital letters aren't allowed in the drawable folder. I get the error: "Invalid file name: must contain only [a-z0-9_.]" – Jason Axelson Oct 12 '13 at 02:34
  • 6
    +1 for "mixed bag of wonderful and terrible design decisions" – Brent Faust Apr 15 '14 at 02:27
  • 1
    Hardly a workaround : rather "what you should do so as not to go completely mad". It's ludicrous to be limited to one directory. – RichieHH Jul 19 '14 at 15:26
44

Actually, on Android Studio it is possible. You can have nested resources as shown here :

enter image description here

There is also a plugin to group resources here.

I recommend to avoid this though.

android developer
  • 114,585
  • 152
  • 739
  • 1,270
37

Yes - it does suck :) However you can use the assets folder and have sub directories in there and load images that way.

dijipiji
  • 3,063
  • 1
  • 26
  • 21
  • 10
    the problem is not only for drawable folder but also for layout folder :( My layout's folder contains more than 100 xml files, and it's hard for me to open the right xml layout in this. – anticafe Jan 12 '11 at 16:32
  • Appart for other objections, resources may be easily localized but AFAIK there is no l10n in-built mechanism for assets. – Fran Marzoa Jul 05 '12 at 11:02
  • @anticafe use "Go to resource" in your IDE (Eclipse: CTRL+SHIFT+R, IDEA/Android Studio: CTRL+SHIFT+N) – TWiStErRob Oct 19 '14 at 22:23
24

Use assets folder.

sample code:

InputStream is = null;
try {
    is = this.getResources().getAssets().open("test/sample.png");
} catch (IOException e) {
    ;
}

image = BitmapFactory.decodeStream(is);
forsvarir
  • 10,749
  • 6
  • 46
  • 77
milkia
  • 265
  • 2
  • 2
  • 5
    The only issue with this method is that there is a LOT more homework involved with using bitmaps. Android's resource system does a much better job of memory management. Why would you rebuild a memory management system when Android already does it? Espeically if he has 100+ images, that's a lot of loading and releasing of bitmaps. – Rev Tyler Jun 30 '12 at 20:13
  • 23
    This is a real problem is you plan to localize your application, also if you have different resources for different screen densities, so it is not a solution, just a workaround valid for only some cases. – Fran Marzoa Jul 05 '12 at 11:14
  • 1
    I need to give @Fran 's comment at least a thousand upvotes :) – HGPB Aug 20 '12 at 16:30
22

I've wrote an eclipse plugin which allows to create virtual subfolder by separating the file name with two underscores __. The project is in early stages, but don't worry it won't crash your IDE

more details can be found here, feel free to fork and send pull requests:

https://github.com/kirill578/Android-Sorted-Res-Folder

enter image description here

Kirill Kulakov
  • 10,035
  • 9
  • 50
  • 67
9

In android studio with gradle you can have multiple source directors which will allow you to separate resources. For example:

android {
    ....
    android.sourceSets {
        main.res.srcDirs = ['src/main/extraresdirnamed_sandwiches', 'src/main/res']
    }
    ....
}

However the names must not collide which means you will still need to have names such as sandwiches_tunaOnRye but you will be able to have a seperate section for all of your sandwiches.

This allows you to store your resources in different structures (useful for auto generated content such as actionbargenerator)

Alec Holmes
  • 3,625
  • 4
  • 22
  • 23
9

I like to use a simple script to flatten an organized directory structure provided by designers to something that can be used to generate an R file.

Run with current path in drawable-hdpi:

#! /bin/bash
DIRS=`find * -type d`
for dir in ${DIRS} ; do 
  for file in `ls ${dir}` ; do
    mv ${dir}/${file}  ${dir}_${file};
  done 
  rmdir ${dir};
done
Rene
  • 4,033
  • 2
  • 24
  • 29
  • 1
    Your script will not work if there is sub folders under folders. I think you need to replace all '/' with '_' in ${dir}. – Seunghoon Jun 08 '12 at 23:38
5

One way to partially get around the problem is to use the API Level suffix. I use res/layout-v1, res/layout-v2 etc to hold multiple sub projects in the same apk. This mechanism can be used for all resource types.

Obviously, this can only be used if you are targeting API levels above the res/layout-v? you are using.

Also, watch out for the bug in Android 1.5 and 1.6. See Andoroid documentation about the API Level suffix.

OferR
  • 1,634
  • 19
  • 21
  • To whoever downgraded this answer: Can you explain why? This mechanism, although not pretty, works well for me. – OferR Dec 14 '12 at 11:48
  • This is what I do as well and it works good enough. I have a bunch of small images that I don't want to expand out, so I keep them in their own folder. – AaronC Oct 12 '21 at 23:27
4

There is a workaround for this situation: you can create a resVector (for example) folder on the same level as default res folder. There you can add any drawable-xxx resource folders there:

resVector
-drawable
-layout
-color

After that all you need is to add

sourceSets {
        main.res.srcDirs += 'src/main/resVector'
    }

into your build.gradle file (inside android { }).

Anton Derevyanko
  • 3,405
  • 1
  • 24
  • 32
  • 1
    Sadly they're merge together in the project panel in Android Studio when using the "Android" perspective :( – charles-allen Jan 14 '18 at 07:24
  • @AjahnCharles - I prefer not to use this perspective at all (anyway - I'm always working at 'distraction free mode')... But you are right - "Android" merges everything. – Anton Derevyanko Apr 03 '18 at 12:24
3

With the advent of library system, creating a library per big set of assets could be a solution.

It is still problematic as one must avoid using the same names within all the assets but using a prefix scheme per library should help with that.

It's not as simple as being able to create folders but that helps keeping things sane...

shi
  • 131
  • 3
  • Yes, I think this is good. If I add country flags to my drawable-ldpi etc. folders then they will get swamped. I think that creating a library project for all generic resources will help reduce the clutter in the project that you are actively working on. Surprised you only have 1 upvote. – Tom Jul 22 '13 at 22:48
1

This is not perfect methods. You have to implement same way which is display here.

You can also call the image under the folder through the code you can use

Resources res = getResources();
Drawable shape = res. getDrawable(R.drawable.gradient_box);

TextView tv = (TextView)findViewByID(R.id.textview);
tv.setBackground(shape);
1

Not mine but I found this thread when looking for this issue, if your using Android Studio and Gradle Build system its pretty easy no plugins necessary just a little build file editing

https://stackoverflow.com/a/22426467/618419

Community
  • 1
  • 1
Captnwalker1
  • 679
  • 7
  • 16
1

Gradle with Android Studio could do it this way (link).

It's in the paragraph "Configuring the Structure"

sourceSets {
 main {
    java {
        srcDir 'src/java'
    }
    resources {
        srcDir 'src/resources'
    }
 }
}
user3290180
  • 4,260
  • 9
  • 42
  • 77
1

create a folder in main. like: 'res_notification_btn'

and create tree folder in. like 'drawable' or 'layout'

then in 'build.gradle' add this

sourceSets
            {
                main
                {
                    res
                    {
                        srcDirs = ['src/main/res_notification_btn', 'src/main/res']
                      or
                        srcDir 'src/main/res_notification_btn'
                    }
                }
            }
Ali Bagheri
  • 3,068
  • 27
  • 28
0
#!/usr/bin/env ruby

# current dir should be drawable-hdpi/ etc

# nuke all symlinks
Dir.foreach('.') {|f|
    File.delete(f) if File.symlink?(f)
}

# symlink all resources renaming with underscores
Dir.glob("**/*.png") {|f|
    system "ln -s #{f} #{f.gsub('/', '_')}" if f.include?("/")
}
Blake Miller
  • 805
  • 11
  • 16
  • All this does is automate the workaround suggested by Cheezmeister. It's working for me ... care to explain the downvote? – Blake Miller Jun 18 '13 at 18:38
0

Check Bash Flatten Folder script that converts folder hierarchy to a single folder

Sneg
  • 1,039
  • 1
  • 11
  • 15
0

assets/ You can use it to store raw asset files. Files that you save here are compiled into an .apk file as-is, and the original filename is preserved. You can navigate this directory in the same way as a typical file system using URIs and read files as a stream of bytes using the AssetManager. For example, this is a good location for textures and game data. http://developer.android.com/tools/projects/index.html

Alex M
  • 77
  • 8
0

Subdirectories are not allowed, the resource must contain only [a-z0-9_.].

No you have uppercase letters, and no forward slashes.

bramp
  • 9,581
  • 5
  • 40
  • 46
0

It is possible to have multiple drawable folders by having an extra folder parallel to 'res' with a subdirectory 'drawable' and then add following to gradle:

sourceSets {
    main {
        res.srcDirs 'src/main/<extra_res>'
    }
}

Tested with gradle 6.5.1

Fracdroid
  • 1,135
  • 10
  • 15
0

For anyone using Xamarin (either Xamarin.Android or Xamarin.Forms), there is a way to do this.

In the .csproj file for the Android project find the line for MonoAndroidResourcePrefix (documented, though rather poorly, here). Add the subdirectories you are wanting to use here, separating each entry by semicolons. When building, Visual Studio strips these prefixes so that all of the resources end up in a flat hierarchy. You may need to reload the solution after making these changes.

Example of setup in Xamarin

These directories do not need to be subdirectories of the default Resources directory in the project.

Make sure that files you add are getting the build action set to "AndroidResource".

For Xamarin.Android, the visual editor won't recognize images and will show the error "This resource URL cannot be resolved" but the project will build and the image will be visible at runtime.

Error in editor Example in emulator

dtim
  • 31
  • 2
-6
  1. Right click on Drawable
  2. Select New ---> Directory
  3. Enter the directory name. Eg: logo.png(the location will already show the drawable folder by default)
  4. Copy and paste the images directly into the drawable folder. While pasting you get an option to choose mdpi/xhdpi/xxhdpi etc for each of the images from a list. Select the appropriate option and enter the name of the image. Make sure to keep the same name as the directory name i.e logo.png
  5. Do the same for the remaining images. All of them will be placed under the logo.png main folder.