j2emanue
j2emanue

Reputation: 62559

android Drawable - getConstantState.newDrawable() vs mutate()

In android I have read a few articles on how drawables share a constant state. So if you make a change to a drawable it affects all the same bitmaps. For example lets say you had a list of star drawables. changing the alpha on one will change all the star drawables alpha. but you can use mutate to get your own copy of a drawable with no shared state.
The article I was reading is here

Now onto my question:

What is the difference between the following two calls in android:

Drawable clone = drawable.getConstantState().newDrawable();

// vs

Drawable clone = (Drawable) drawable.getDrawable().mutate();

For me they are both cloning a drawable as they both return a drawable that has no shared state. Am I missing something ?

Upvotes: 20

Views: 6867

Answers (1)

Kirill
Kirill

Reputation: 8341

As @4castle pointed in comments mutate() method returns same instance of the drawable with copied constant drawable state. Docs says that

A mutable drawable is guaranteed to not share its state with any other drawable

So it is safe to change a drawable without affecting drawables with the same state

Lets play with this drawable - a black shape

 <!-- shape.xml -->
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
    <solid android:color="@android:color/black" />
</shape>


view1.setBackgroundResource(R.drawable.shape); // set black shape as a background
view1.getBackground().mutate().setTint(Color.CYAN); // change black to cyan
view2.setBackgroundResource(R.drawable.shape); // set black shape background to second view


The opposite method is newDrawable(). It creates a new drawable but with the same constant state. E.g. look at BitmapDrawable.BitmapState:

    @Override
    public Drawable newDrawable() {
        return new BitmapDrawable(this, null);
    }

Changes to new drawable will not affect current drawable, but will change a state:

view1.setBackgroundResource(R.drawable.shape); // set black shape as background
Drawable drawable = view1.getBackground().getConstantState().newDrawable();
drawable.setTint(Color.CYAN); // view still black
view1.setBackground(drawable); // now view is cyan
view2.setBackgroundResource(R.drawable.shape); // second view is cyan also

Upvotes: 29

Related Questions