Android Support Library 23.4.0: android.support.v7.widget.TintContextWrapper cannot be migrated to Activity

So, I upgraded to the latest support libraries and got a crash that I cannot fix. Now my build.gradle 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, which is used to capture clicks and launch a new action. This worked fine in the support libraries of version 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 bound to an ImageButton , and then the button color is colored as follows:

 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 toning 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 view context seems to have changed to TintContextWrapper , about which I can find little information. I found this problem , but a project member advises setting StackOverflow here, so here it is.

What have i tried?

Since a project member on the Google release stated that you would need to get activity out of a wrapped context. I tried casting TintContextWrapper instead of MyActivity , which works fine, but I can't figure out how to get MyActivity from TintContextWrapper .

So my questions are:

  • How can I get MyActivity from TintContextWrapper ?
  • Why is my ImageButton unexpectedly wrapped in a TintContextWrapper .
  • Should this behavior really be expected?

The definition of ImageButton in xml is simple:

 <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) 
+8
android android-support-library
source share
7 answers
  • both actions n TintContextWRapper comes from ContextWrapper . ContextWrapper have a getBaseContext() method. Creating a loop method that checks instanceof WrapContext should be simple, get the underlying context, and then check instanceof Activity . (If you have problems with this method comment here, I will dig on some of my project and paste here in u)

  • Since AppCompat wraps your context to be able to introduce “compatible” views and “compatible” shades and other “compatible” things. This is normal.

  • Yes. This is how AppCompat does its job.

+8
source share

@ Krøllebølle

Support for Android support 23.4.0: android.support.v7.widget.TintContextWrapper cannot be dropped

The answer to the question: first, the click event code should look like this:

 @Override public void onClick(View view) { MyActivity myActivity = getRequiredActivity(view); myActivity.showIngredientActivity(mIngredient); } 

and then write the getRequiredActivity () function:

 private Activity getRequiredActivity(View req_view) { Context context = req_view.getContext(); while (context instanceof ContextWrapper) { if (context instanceof Activity) { return (Activity)context; } context = ((ContextWrapper)context).getBaseContext(); } return null; 

}

and corrected your violation / exception :)

+4
source share

My suggestion is to pass the link of my activity to onClickListener in order to avoid a problem with TintContextWrapper . Providing your class with a reference to MyActivity is simple and avoids potential casting problems.

+3
source share

You can try

 Activity activity = (Activity) view.getRootView().getContext() 

Gets the context containing this view, without the android.support.v7.widget.TintContextWrapper shell.

+1
source share
  • How can I get MyActivity from TintContextWrapper?

You really shouldn't. It is not guaranteed that the presentation context will be Activity - definitely not a specific Activity. Where do you install your OnClickListener? I assume that in the place where you installed the listener, you will have access to the Activity. For example, if you install a listener from an Activity:

 public class MainActivity extends AppCompatActivity { @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViewById(R.id.ingredientButton).setOnClickListener( new IngredientItemOnClickListener(yourIngredient)); } void showIngredientActivity(Ingredient ingredient) { // Do your stuff } public class IngredientItemOnClickListener implements OnClickListener { private Ingredient mIngredient; public IngredientItemOnClickListener(Ingredient ingredient) { mIngredient = ingredient; } @Override public void onClick(View view) { showIngredientActivity(mIngredient); } } } 
0
source share

It worked for me after updating Android Support Libraries.

0
source share

I encountered the same problem and resolved with
- Android Support Library, version 24.2.1 (September 2016)
- compileSdkVersion 24
- buildToolsVersion "24.0.3"

0
source share