Android Development
Resource Optimization
Unused Resources
Project Cleanup
Mobile App Efficiency

Remove all unused resources from an android project

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

Unused drawables, layouts, strings, and raw assets make Android projects harder to maintain and can increase APK or App Bundle size. The safe way to remove them is not by deleting files blindly, but by combining static analysis, build-time shrinking, and a review of any resources loaded dynamically.

Start With Android Studio and Lint

Android Studio already knows how to look for unused resources. The built-in lint checks are usually the fastest first pass because they understand common references from layouts, manifests, navigation graphs, and generated R usage.

A practical workflow is:

  1. run lint on the module or whole project
  2. inspect UnusedResources findings
  3. confirm whether any flagged resource is used dynamically
  4. delete or rename only after that review

From the command line:

bash
./gradlew lintDebug

Inside Android Studio, the same inspection is available through the code analysis tools. This catches a large percentage of dead resources without touching runtime behavior.

Use Resource Shrinking in Release Builds

Static analysis helps during development, but release builds should also shrink code and resources automatically. In Android builds, resource shrinking works together with code shrinking. If dead code is removed, resources that are reachable only from that dead code can be removed too.

Example in a Gradle Groovy build file:

groovy
1android {
2    buildTypes {
3        release {
4            minifyEnabled true
5            shrinkResources true
6            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
7                    'proguard-rules.pro'
8        }
9    }
10}

This is important because some resources look used at source level but are only reachable through code that R8 later removes. Manual cleanup alone will miss that case.

Be Careful With Dynamic Resource Lookup

The main reason unused-resource cleanup goes wrong is dynamic lookup. If code constructs a resource name at runtime, static tools may not see the reference.

Example:

kotlin
1val imageName = "flag_" + countryCode.lowercase()
2val resId = resources.getIdentifier(imageName, "drawable", packageName)
3if (resId != 0) {
4    imageView.setImageResource(resId)
5}

From the IDE’s point of view, none of the flag_* images may appear referenced directly. Deleting them would break the screen even though lint called them unused.

If you must use dynamic lookup, keep that list small and documented. Even better, replace string-based lookup with an explicit map so the references remain visible to both humans and tools.

kotlin
1val flags = mapOf(
2    "ca" to R.drawable.flag_ca,
3    "us" to R.drawable.flag_us
4)
5imageView.setImageResource(flags[countryCode] ?: R.drawable.flag_default)

That is easier to maintain and safer for shrinkers.

Keep Specific Resources When Needed

Sometimes a resource really is used indirectly and must survive shrinking. In that case, mark it explicitly instead of disabling shrinking globally.

One approach is a keep file using the Android tools namespace:

xml
<resources xmlns:tools="http://schemas.android.com/tools"
    tools:keep="@drawable/flag_ca,@drawable/flag_us,@layout/special_entry" />

That tells the shrinker to preserve those resources even if static analysis cannot prove they are needed.

Clean Up More Than res/

Unused resources are not limited to drawable or layout. It is worth checking:

  • duplicate strings that should be merged
  • obsolete menu XML files
  • old navigation graphs
  • sample JSON or media files in raw or assets
  • alternative-density images no longer used by current UI

These files are easy to forget because they do not always trigger compiler errors.

Common Pitfalls

The biggest mistake is deleting resources after a lint run without checking for runtime lookup through getIdentifier, reflection, or third-party libraries.

Another issue is relying only on manual deletion and never enabling shrinkResources in release builds. That leaves easy size wins on the table.

A third problem is keeping large piles of old assets “just in case.” If a file matters, keep it for a documented reason. Otherwise it is technical debt.

Summary

  • Use Android Studio lint as the first pass for finding unused resources.
  • Enable minifyEnabled and shrinkResources for release builds.
  • Review dynamic resource lookups before deleting anything.
  • Prefer explicit R.drawable or R.layout references over string-based lookup.
  • Keep special resources intentionally instead of disabling shrinking for the whole app.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.