Keywords: Android | Background Setting | Drawable | Programmatic Setting | API Compatibility
Abstract: This article provides an in-depth exploration of various methods for dynamically setting background Drawables in Android applications. It covers the usage of setBackgroundResource, setBackground, and setBackgroundDrawable, analyzes compatibility issues across different API versions, introduces support library tools like ContextCompat and ResourcesCompat, and discusses the importance of Drawable state sharing and the mutate method. Through comprehensive code examples, the article demonstrates best practices to help developers avoid common pitfalls and performance issues.
Basic Methods for Background Setting
In Android development, dynamically setting view backgrounds is a common requirement. The most fundamental approach is using the setBackgroundResource method, which sets the background Drawable directly through resource ID. Example code:
RelativeLayout layout = (RelativeLayout) findViewById(R.id.background);
layout.setBackgroundResource(R.drawable.ready);
This method is straightforward and suitable for most scenarios. However, when dealing with large images, proper memory management is crucial to avoid out-of-memory errors caused by loading oversized images.
API Version Compatibility Handling
As the Android system continues to evolve, background setting methods have also changed. To ensure application compatibility across different versions, appropriate methods must be selected based on API level:
final int sdk = android.os.Build.VERSION.SDK_INT;
if(sdk < android.os.Build.VERSION_CODES.JELLY_BEAN) {
layout.setBackgroundDrawable(ContextCompat.getDrawable(context, R.drawable.ready));
} else {
layout.setBackground(ContextCompat.getDrawable(context, R.drawable.ready));
}
Before API 16 (Jelly Bean), the setBackgroundDrawable method should be used, while setBackground is recommended for later versions.
Support Library Usage
With the deprecation of getDrawable(int) in API 22, using support library methods is recommended. ContextCompat provides backward-compatible solutions:
ContextCompat.getDrawable(context, R.drawable.ready)
The internal implementation of ContextCompat.getDrawable selects the appropriate method based on the current API version:
public static final Drawable getDrawable(Context context, int id) {
final int version = Build.VERSION.SDK_INT;
if (version >= 21) {
return ContextCompatApi21.getDrawable(context, id);
} else {
return context.getResources().getDrawable(id);
}
}
In API 21 (Lollipop) and above, this method returns a Drawable object styled according to the specified Context's theme.
ResourcesCompat Alternative
Besides ContextCompat, ResourcesCompat can also be used to obtain Drawables:
import android.support.v4.content.res.ResourcesCompat;
ResourcesCompat.getDrawable(getResources(), R.drawable.name_of_drawable, null);
This approach works reliably across all API levels, providing better compatibility.
Custom Drawable Creation and Usage
In practical development, creating custom Drawable resources is often necessary. Gradient backgrounds can be defined via XML:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:angle="270"
android:endColor="@color/white"
android:startColor="#0F9D58" />
</shape>
This custom Drawable can then be set in code:
LinearLayout mainView = findViewById(R.id.main);
mainView.setBackground(ResourcesCompat.getDrawable(getResources(),
R.drawable.back_drawable, null));
Drawable State Sharing Issues
When modifying Drawables, an important consideration is that multiple views using the same Drawable resource share the same state. This is due to Android's optimization mechanism to avoid creating new Drawable instances for each view.
When independent modification of a Drawable is required, the mutate() method must be used:
Drawable drawable = ContextCompat.getDrawable(context, R.drawable.background);
Drawable mutableDrawable = drawable.mutate();
// Now mutableDrawable can be safely modified without affecting other instances
layout.setBackground(mutableDrawable);
This method creates a new Drawable instance with independent state, preventing unintended effects on other views using the same resource.
Performance Optimization Recommendations
When handling large images, appropriate loading strategies should be employed:
- Use appropriate image dimensions to avoid loading oversized bitmaps
- Consider using BitmapFactory.Options for sampling
- Recycle Bitmap resources when no longer needed
- Utilize memory caching to optimize repeated loading
Build Configuration
To use support libraries, dependencies must be added in the app's build.gradle file:
implementation 'com.android.support:support-v4:23.0.0'
Or use updated versions of support libraries to ensure access to the latest compatibility fixes and feature improvements.
Conclusion
Dynamically setting Android background Drawables requires consideration of multiple factors, including API compatibility, performance optimization, and Drawable state management. By properly utilizing support libraries and following best practices, stable and efficient applications can be created. Remember to use the mutate method when modifying Drawables and pay attention to memory management when handling large images, as these practices significantly enhance application quality and user experience.