8

I have a project which contains a lot of drawables, which are named starting with "a" or "b" (For example a1_back, a2_back, b1_start, b2_start and many-many more). Those drawables are not used in code, but used by the following code:

String name = image.getName();//getName() returns for examle "a1_back"
res = getResources().getIdentifier(name, "drawable", getPackageName());

So, nowhere in code do I have specific string "a1_back" used. That's why when I set "shrinkResources true" all my drawables starting with "a" and "b" are removed.

I've read that you can specify what resources to keep using following xml file:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
    tools:keep="@layout/l_used_c"
    tools:discard="@layout/unused2" />

But I have way to many drawables and don't want to specify each one separately. Is there a way to set a pattern in "tools:keep"(to keep all drawables starting with "a" or "b") or maybe make it keep all drawables in project, but remove other unused resources?

Thanks in advance! :)

hkop
  • 304
  • 3
  • 9
  • if you are dealing with only resources, android studio have an option click on **Refactor** >> **Remove Unused Resources**. – Akshay Bhat 'AB' Dec 22 '16 at 10:43
  • Yes, but I don't want my drawables to be removed! i want to keep them, but remove everything else. – hkop Dec 22 '16 at 10:45
  • Run the remove unused resources, then use your source control program to restore the drawables. – nasch Dec 23 '16 at 22:29

3 Answers3

3

There is a workaround you can use. Add a prefix for all drawables which you want to keep

@Nullable
private Drawable getDrawableByName(@NonNull final Context context, @NonNull final String name) {
    final String prefixName = String.format("prefix_%s", name);
    return getDrawable(context, prefixName);
}

@Nullable
protected Drawable getDrawable(@NonNull final Context context, @NonNull final String name) {
    final Resources resources = context.getResources();
    final int resourceId = resources.getIdentifier(name, "drawable", context.getPackageName());
    try {
        return resources.getDrawable(resourceId, context.getTheme());
    } catch (final Resources.NotFoundException exception) {
        return null;
    }
}

The trick here

final String prefixName = String.format("prefix_%s", name);

Resource shrinking mechanism analyzes that all drawables with "prefix_" can be used and it doesn't touch these files.

3

When accessing resource dynamically , use this trick as explained in Android User Guide using this example

String name = String.format("img_%1d", angle + 1);
res = getResources().getIdentifier(name, "drawable", getPackageName());
Mohamed ALOUANE
  • 5,349
  • 6
  • 29
  • 60
1

The other answers work but in case you want to be doubly sure your resources are kept you can instruct the build tools with explicit instructions in XML.

Google describes how to use a keep.xml file with pattern matching here: https://developer.android.com/studio/build/shrink-code#keep-resources

This is the example Google used, notice the use of *:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
    tools:keep="@layout/l_used*_c,@layout/l_used_a,@layout/l_used_b*"
    tools:discard="@layout/unused2" />

Also you can check the build file build/outputs/mapping/debug/resources.txt for explanations about which resources are being kept and which aren't and why.

satur9nine
  • 13,927
  • 5
  • 80
  • 123