If you have ever encountered development under Android on Java or Kotlin, you probably noticed how often you have to work with application resources - strings, colors, styles or dimensional values. But what to do when you need to efficiently retrieve an array of data from XMLwithout losing performance? This is where TypedArray comes to the rescue - a powerful tool that many developers underestimate.
In this article we will look at what TypedArrayis, how it differs from ordinary arrays in Android, and why its correct use can significantly speed up the loading of resources. You'll learn how to work with style attributes, extract values โโfrom themes, and avoid common mistakes that lead to memory leaks or application crashes. Weโll also look at practical code examples that you can immediately apply in your projects.
Regardless of whether you are a beginner or an experienced developer, understanding TypedArray will help you write cleaner and more efficient code. This is especially true for applications where performance is critical - for example, in games or multimedia players. Let's take a look at how this mechanism works under the hood.
What is TypedArray and why do you need it
TypedArray is a specialized class in Android SDKthat provides access to arrays of resources defined in XMLfiles. Unlike conventional arrays (for example String[] or int[]), it is optimized for working with application resources and allows you to retrieve them with minimal overhead.
The main advantage TypedArray is that it automatically manages the life cycle of resources and prevents memory leaksthat often arise when manually extracting data through Resources.getStringArray() or similar methods. In addition, it supports working with style attributes (for example, from styles.xml or themes.xml), which makes it indispensable for creating flexible and adaptive interfaces.
A typical usage example is retrieving an array of strings or colors from resources:
// Retrieving an array of strings from resourcesTypedArray typedArray = context.obtainStyledAttributes(R.styleable.MyCustomView);
String[] items = typedArray.getTextArray(R.styleable.MyCustomView_items);
typedArray.recycle(); // Important! Freeing up resources
Without TypedArray you would have to manually parse XML or use less efficient methods, which leads to unnecessary CPU time and memory.
TypedArray vs regular arrays: key differences
At first glance, it may seem that TypedArray and standard arrays (String[], int[]) solve the same problem. However, in practice, there are fundamental differences between them that affect the performance and usability of the code.
- ๐น Performance: TypedArray works directly with binary resources Android, which speeds up data access compared to manual parsing
XML. - ๐น Memory management: TypedArray requires an explicit call
recycle()to free up resources. Regular arrays are managed automatically by the garbage collector, but can lead to leaks if references are not cleaned up. - ๐น Styling and theme support: Only TypedArray allows you to extract values from style attributes (for example
?attr/colorPrimary), which is critical for responsive design. - ๐น Typing: TypedArray provides methods for retrieving data of specific types (
getString(),getColor(),getDimension()), while regular arrays require type casting.
Consider a simple example: if you need to get an array of colors from resources, then with TypedArray it would look like this:
TypedArray colorsArray = context.resources.obtainTypedArray(R.array.my_colors);int[] colors = new int[colorsArray.length()];
for (int i = 0; i < colorsArray.length(); i++) {
colors[i] = colorsArray.getColor(i, Color.BLACK);
}
colorsArray.recycle();
And without it, you would have to use a less flexible approach:
int[] colors = context.resources.getIntArray(R.array.my_colors);
The last method does not support working with style attributes and does not allow you to dynamically substitute values from themes.
How to work with TypedArray: basic operations
To start using TypedArray, you need to understand several key points: how to receive it, how to extract data and how to properly release resources. Let's look at each step.
1. Getting a TypedArray
There are two main ways to get an instance TypedArray:
- ๐ Via
Resources.obtainTypedArray()โ for working with arrays of resources (for example,<array>vres/values/arrays.xml). - ๐ Via
Context.obtainStyledAttributes()โfor extracting attributes from styles or themes.
Example for an array:
TypedArray typedArray = context.resources.obtainTypedArray(R.array.my_string_array);
Example for styles:
TypedArray attrs = context.obtainStyledAttributes(R.styleable.MyCustomView);
2. Data extraction
TypedArray provides methods for working with different types of data:
- ๐
getString(int index)โ getting a string. - ๐จ
getColor(int index, int defaultColor)โ getting a color with a backup value. - ๐
getDimension(int index, float defaultValue)โ getting a size value in pixels. - ๐ข
getInt(int index, int defaultValue)โ getting an integer. - ๐ผ๏ธ
getDrawable(int index)โ getting a drawable resource.
However, when working with style attributes, indexes are defined in R.styleable.
3. Freeing up resources
This is the most critical moment! After use TypedArray required you need to call recycle(), otherwise a memory leak will occur. Example:
TypedArray typedArray = context.resources.obtainTypedArray(R.array.my_array);// Working with data..
typedArray.recycle(); // Release!
โ ๏ธ Attention: If you forget to callrecycle()then Android Studio may issue a warningTypedArray was not recycledwhen analyzing the code. In some cases, this leads to the application crashing with an errorOutOfMemoryError.
โ๏ธ Checklist for working with TypedArray
Working with style and theme attributes
One of the most powerful uses TypedArray is working with style attributes. This allows you to create flexible interface components that adapt to the current application theme. For example, you can define a custom one that will use colors from the theme. View, which will use the colors from the theme.
Let's look at the process step by step:
1. Defining attributes in XML
First you need to declare the attributes in the file res/values/attrs.xml:
<?xml version="1.0" encoding="utf-8"?><resources>
<declare-styleable name="MyCustomView">
<attr name="customText" format="string"/>
<attr name="customColor" format="color"/>
<attr name="customSize" format="dimension"/>
</declare-styleable>
</resources>
2. Using attributes in layout
Now you can use these attributes in XMLmarkup:
<com.example.MyCustomViewandroid:layout_width="wrap_content"
android:layout_height="wrap_content"
app:customText="Hello, TypedArray!"
app:customColor="@color/primary"
app:customSize="16sp"/>
3. Retrieving attributes in code
In the class MyCustomView we retrieve values โโvia TypedArray:
public MyCustomView(Context context, AttributeSet attrs) {super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyCustomView);
String text = a.getString(R.styleable.MyCustomView_customText);
int color = a.getColor(R.styleable.MyCustomView_customColor, Color.BLACK);
float size = a.getDimension(R.styleable.MyCustomView_customSize, 16f);
a.recycle(); // Don't forget!
// Use the received values..
}
This approach allows your component to automatically adapt to the application theme without requiring hard coding of colors or sizes.
โ ๏ธ Attention: If you use attributes from system themes (for example, ?attr/colorPrimary), make sure they are defined in the current theme. Otherwise TypedArray will return the default value.
Optimizing performance when working with TypedArray
Although TypedArray is already optimized for working with resources, there are several tricks that will help make its use even more effective. This is especially important for applications where performance is critical - for example, in games or graphics-intensive applications.
1. Caching TypedArray
If you need to retrieve data from the same array multiple times, you should consider caching TypedArray. However, remember that you can cache only if you are sure that the resources will not change while the application is running.
private TypedArray cachedTypedArray;public void init() {
if (cachedTypedArray == null) {
cachedTypedArray = context.resources.obtainTypedArray(R.array.my_data);
}
// We use cachedTypedArray..
}
2. Minimizing recycle() calls
If you work with several TypedArray in a row, it is better to free them immediately after use, rather than wait for the end of the method. This will reduce the memory load.
3. Using default values
Always specify fallback values โโin methods like getColor() or getDimension(). This will prevent crashes if the resource suddenly becomes unavailable:
int color = typedArray.getColor(R.styleable.MyView_customColor, Color.RED);
4. Avoid redundant calls
If you need to get multiple values โโfrom one TypedArray, do it in one block rather than creating a new instance for each value.
Compare the inefficient approach:
// Bad: creating a new TypedArray for each valueint color = context.obtainStyledAttributes(attrs, R.styleable.MyView)
.getColor(R.styleable.MyView_color, Color.BLACK);
float size = context.obtainStyledAttributes(attrs, R.styleable.MyView)
.getDimension(R.styleable.MyView_size, 16f);
And the optimized one:
// Good: we use one instanceTypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyView);
int color = a.getColor(R.styleable.MyView_color, Color.BLACK);
float size = a.getDimension(R.styleable.MyView_size, 16f);
a.recycle();
| Optimization technique | Advantage | When to use |
|---|---|---|
| Caching TypedArray | Reduces overhead for repeated extraction | If the data is static and used frequently |
| Default values | Prevents crashes in the absence of a resource | Always, except in cases where the absence of a value is critical |
Minimization recycle() |
Reduces memory fragmentation | When working with several arrays in a row |
| Batch extraction | Reduces the number of operations with resources | When several are needed values from one array |
Common mistakes and how to avoid them
Even experienced developers sometimes make mistakes when working with TypedArray. Let's look at the most common of them and learn how to prevent them.
1. Forgotten recycle() call
This is the most common error that leads to memory leaks. Always check what recycle() is called in the block finallyif there is a possibility of exceptions:
TypedArray a = null;try {
a = context.obtainStyledAttributes(attrs, R.styleable.MyView);
// Working with data..
} finally {
if (a != null) a.recycle();
}
2. Incorrect indexes
When working with style attributes, it is easy to confuse indexes, especially if there are attrs.xml many fields. Always use generated constants from R.styleable:
// Correct:int color = a.getColor(R.styleable.MyView_customColor, Color.BLACK);
// Incorrect (can lead to ArrayIndexOutOfBounds):
int color = a.getColor(0, Color.BLACK);
3. Ignoring default values
If you do not specify a fallback value, then if there is no resource, the method will return 0 or null, which can lead to unexpected behavior. For example, getColor() without default will return 0 (transparent color), which is not visually noticeable, but will break the logic.
4. Working with TypedArray in the background
TypedArray is not thread safe! All operations with it must be performed in the main thread (UI thread). If you need to fetch data in a background thread, do it in advance and pass the results through handlers or LiveData.
โ ๏ธ Attention: Trying to use TypedArray toAsyncTaskorCoroutinetoDispatchers.IOwill crash with errorOnly the original thread that created a view hierarchy can touch its views.
What will happen if you do not call recycle()?
Every call to obtainTypedArray() or obtainStyledAttributes() allocates a new data structure in memory. If not freed via recycle(), these objects will accumulate, which will eventually lead to a memory leak. In the worst case, the application will start to slow down or crash with an OutOfMemoryError, especially on devices with limited resources.
Practical example: dynamic theme with TypedArray
Let's look at a real example where TypedArray helps create a dynamic theme for an application. Let's say we have a setting that allows the user to choose between a light and dark theme, and we want all custom views to automatically adjust to the selected theme.
1. We define attributes in attrs.xml
<?xml version="1.0" encoding="utf-8"?><resources>
<declare-styleable name="ThemedButton">
<attr name="buttonBackground" format="reference"/>
<attr name="buttonTextColor" format="color"/>
</declare-styleable>
</resources>
2. We create styles for themes
In res/values/themes.xml and res/values-night/themes.xml we define different values for attributes:
<style name="Theme.MyApp" parent="Theme.MaterialComponents.Light">
<item name="buttonBackground">@drawable/button_light</item>
<item name="buttonTextColor">@color/black</item>
</style>
<style name="Theme.MyApp" parent="Theme.MaterialComponents">
<item name="buttonBackground">@drawable/button_dark</item>
<item name="buttonTextColor">@color/white</item>
</style>
3. Implementing a custom button
In the class ThemedButton extract the attributes and apply them:
public class ThemedButton extends AppCompatButton {public ThemedButton(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(
attrs,
R.styleable.ThemedButton,
R.attr.themedButtonStyle, // Default style
0
);
Drawable background = a.getDrawable(R.styleable.ThemedButton_buttonBackground);
int textColor = a.getColor(R.styleable.ThemedButton_buttonTextColor, Color.BLACK);
setBackground(background);
setTextColor(textColor);
a.recycle();
}
}
4. We use it in markup
<com.example.ThemedButtonandroid:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click me"
app:buttonBackground="?attr/buttonBackground"
app:buttonTextColor="?attr/buttonTextColor"/>
Now the button will automatically change its appearance depending on the selected theme, without the need to manually update its parameters.
TypedArray allows you to create truly adaptive interface components that dynamically adapt to the current theme or style of the application. This eliminates the need to hard-code colors, sizes, and other attributes, making your code more flexible and maintainable.
FAQ: Answers to common questions about TypedArray
Can TypedArray be used to work with arrays defined in code (not in XML)?
No, TypedArray is intended exclusively for working with resources defined in XMLfiles (for example, in res/values/). To work with arrays created in code, use standard data structures (ArrayList, int[] etc.).
What happens if you call recycle() twice?
Call recycle() on an already freed one TypedArray will not lead to an error, but will not do anything either. However, it is better to avoid such situations, as this may indicate errors in the resource management logic.
How to access a TypedArray from a fragment?
In a fragment, you can get TypedArray through the context, for example: requireContext().obtainStyledAttributes(..). Don't forget to call recycle() in onDestroyView()if the array is used in a fragment view.
Can TypedArray be serialized?
No, TypedArray does not support serialization. If you need to store data, extract it into standard structures (for example List<String>) and serialize it already.
Why does my application crash with the error "ArrayIndexOutOfBounds" when working with TypedArray?
This error usually occurs if you are trying to access an index that does not exist. Make sure that:
- You are using the correct constants from
R.styleable. - In
attrs.xmlall attributes are correctly defined. - You do not exceed the length of the array (check through
typedArray.length()).