Streamlining Android Development 5: Splitting Android resources like a pro!

How-To Android

Working on a project for some time? Is it starting to get really big and hard to navigate in? Are you having hundreds or thousands of drawables, layout or others resource files? You can get easily lost in them. This is why we will discuss resource directory splitting today.

Dislaimer: This will only work in old-school Project view! Which I am still favoring before the new Android view.

So, we already described our problem here. Hundreds or thousand of files in just few folders. This can be a real pain. I am not much used to double-shift file opening, as I often don't even remember the file names. This is why I was looking for a nice solution for this problem.

The solution is pretty simple here. Let's pick one of the resource folders as an example. Let's say we will talk about layouts now. In the classic scenario, you would have all your layouts in res/layout/ folder. Now, you know that you have for example some kinds of Community screen, and you have about twenty layouts which are part of it. You would like to ideally put them in the sub-folder. Sadly this is not currently possible. Thankfully, there is small workaround for that.

As I said. We cannot just simply create res/layout/community/ and put our .xml files in there. What we can do, is create our new resource structure, for example: res/layouts/community/layout/, and put the layout folder there. We can then also create res/layouts/layout for the rest of the layout files. Now we just need to tell Gradle that we have multiple resource folders! Gradle will then look in their root for any known resource directories, like layout, drawable, mipmap, etc..

Here is the example how the split layout resources currently looks on my project.

Pretty nice huh? You can split like this anything you want. Now let's get down to how to edit the Gradle file. It is really simple. We will edit the build.gradle file in our module. Here is a small example of how to do it:

android {
    sourceSets {
        main.res.srcDirs = [
            'src/main/res/drawables/drawables_en',
            'src/main/res/drawables/drawables_fr',
            'src/main/res/drawables/drawables_button',
            'src/main/res/drawables/drawables_gradient',
            'src/main/res/drawables/drawables_selector',
            'src/main/res/drawables/drawables_shape',
            'src/main/res/drawables',
            'src/main/res/layouts/layouts_main/feed',
            'src/main/res/layouts/layouts_main/video',
            'src/main/res/layouts/layouts_main/podcasts',
            'src/main/res/layouts/layouts_main/community',
            'src/main/res/layouts/layouts_main/search',
            'src/main/res/layouts/layouts_main/standing',
            'src/main/res/layouts/layouts_main/score',
            'src/main/res/layouts/layouts_main',
            'src/main/res/layouts/layouts_article',
            'src/main/res/layouts/layouts_settings',
            'src/main/res/layouts',
            'src/main/res/mipmaps',
            'src/main/res/values',
            'src/main/res'
        ]
    }
}

You can see that I am also splitting my drawables. I like splitting them to at least shapes, buttons, gradients, selectors and the rest. Putting all mipmaps into one folder is also a great idea as you usually not interacting with them, and you don't need those X folders visible all the time. Grouping values can be also a great idea, as you often split them by the API, screen desnity or language.

Just don't forget that you are specifying the resource root directories in the Gradle file. You still need to place proper sub-directories inside them, which will tell what kind of resource is there. For example, having directory: src/main/res/drawables/drawables_en is not enough, and you still need to create the path like this: src/main/res/drawables/drawables_en/drawable.

And one more warning!

In case you are using more flavors, you need to use also this small fix. Not sure why, but the compiler is going to think that the resource has not changes even when you change something in the layout or drawable. This would result in the state where you would be making changes to your resources, but after each compilation you would still see the old resource. This few lines should tell the compiler that the resource has changed and he should invalidate it. In case you are not using flavors, this should not be necessary.

// Because of flavors and multiple res folders.
afterEvaluate {
    android.applicationVariants.all { variant ->
        tasks.named("generate${variant.name.capitalize()}ResValues").configure { task ->
            task.outputs.upToDateWhen {false}
        }
    }
}

I hope this will make a navigation in your resources easier and cleaner for you!

Previous Post