Krøllebølle Krøllebølle - 5 months ago 570
Android Question

Android support library 23.4.0: android.support.v7.widget.TintContextWrapper cannot be cast to Activity

So I updated to the latest support libraries, and got a crash I am not able to fix. My build.gradle now has these dependencies:

dependencies {
compile 'com.android.support:appcompat-v7:23.4.0'
compile 'com.android.support:gridlayout-v7:23.4.0'
compile 'com.android.support:support-v4:23.4.0'
compile 'com.android.support:cardview-v7:23.4.0'
compile 'com.android.support:recyclerview-v7:23.4.0'
compile 'com.android.support:design:23.4.0'
// More stuff...
}


I had a working listener that is used to catch clicks and start a new Activity. This was working fine in support libraries v. 23.1.0, but not in 23.4.0 (and 23.3.0):

public class IngredientItemOnClickListener implements OnClickListener
{
private Ingredient mIngredient;

public IngredientItemOnClickListener(Ingredient ingredient)
{
mIngredient= ingredient;
}

@Override
public void onClick(View view)
{
MyActivity myActivity = (MyActivity) view.getContext(); // <-- crash here
myActivity.showIngredientActivity(mIngredient);
}
}


This listener is simply attached to an
ImageButton
and thereafter the color of the Button is tinted, like this:

Ingredient ingredient = getIngredient();
myImageButton.setOnClickListener(new IngredientItemOnClickListener(ingredient));
Drawable drawable = Tinting.tint(myActivity, R.drawable.my_icon, R.color.red);
myImageButton.setImageDrawable(drawable);


where
Tinting.tint()
is my own tinting function:

public class Tinting
{
@Nullable
public static Drawable tint(Context context, int drawableId, int colorId)
{
final Drawable drawable = ContextCompat.getDrawable(context, drawableId);
if (drawable != null)
{
final Drawable wrapped = DrawableCompat.wrap(drawable);
drawable.mutate();
DrawableCompat.setTint(wrapped, ContextCompat.getColor(context, colorId));
}
return drawable;
}
}


Previously when I clicked the button everything worked as expected, but now the Context of the View seems to have changed to
TintContextWrapper
which I can find little information about. I found this issue, but the project member advises to ask here on StackOverflow, so here it is.

What have I tried?



Since the project member in the Google issue stated You will need to obtain the activity from the wrapped context. I tried casting to
TintContextWrapper
instead of
MyActivity
, which works fine, but I cannot figure out how to get
MyActivity
from
TintContextWrapper
.

So my questions are:




  1. How can I get
    MyActivity
    from the
    TintContextWrapper
    ?

  2. Why is my
    ImageButton
    suddenly wrapped in a
    TintContextWrapper
    .

  3. Should this behavior really be expected?



Definition of ImageButton in xml is simply:



<ImageButton
android:id="@+id/my_id"
android:src="@drawable/my_icon" />


Stack trace:



java.lang.ClassCastException: android.support.v7.widget.TintContextWrapper cannot be cast to com.my.app.activities.MyActivity
at com.my.app.listeners.IngredientItemOnClickListener.onClick(IngredientItemOnClickListener.java:21)
at android.view.View.performClick(View.java:4475)
at android.view.View$PerformClick.run(View.java:18786)
at android.os.Handler.handleCallback(Handler.java:730)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:176)
at android.app.ActivityThread.main(ActivityThread.java:5419)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1046)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862)
at dalvik.system.NativeStart.main(Native Method)

Answer
  1. both activity n TintContextWRapper comes from ContextWrapper. ContextWrapper have a method getBaseContext(). It should be easy to create a loop method that checks instanceof WrapContext, gets base context and then checks instanceof Activity. (If you have problems with this method comment here that I'll dig on some project of mine and paste here to u)

  2. Because AppCompat wraps your context to be able to inject "compat" views and "compat" tinting and other "compat" stuff. That's normal.

  3. Yes. That's how AppCompat does its thing.

Comments