Librería de soporte de Android 23.4.0: android.support.v7.widget.TintContextWrapper no se puede publicar en Actividad

Así que me actualizé a las últimas bibliotecas de soporte, y recibí un fallo que no puedo arreglar. Mi build.gradle ahora tiene estas dependencias:

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... } 

Tuve un oyente de trabajo que se utiliza para capturar clics y comenzar una nueva actividad. Esto funcionaba bien en bibliotecas de soporte v. 23.1.0, pero no en 23.4.0 (y 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); } } 

Este oyente está simplemente conectado a un ImageButton y después el color del botón está tintado, como este:

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

Donde Tinting.tint() es mi propia función de teñido:

 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; } } 

Anteriormente cuando hice clic en el botón todo funcionó como se esperaba, pero ahora el contexto de la vista parece haber cambiado a TintContextWrapper que puedo encontrar poca información sobre. Encontré este problema , pero el miembro del proyecto aconseja preguntar aquí en StackOverflow, así que aquí está.

¿Qué he intentado?

Dado que el miembro del proyecto en el problema de Google declaró que tendrá que obtener la actividad del contexto envuelto. He intentado lanzar a TintContextWrapper lugar de MyActivity , que funciona bien, pero no puedo averiguar cómo obtener MyActivity de TintContextWrapper .

Así que mis preguntas son:

  1. ¿Cómo puedo obtener MyActivity de TintContextWrapper ?
  2. ¿Por qué mi ImageButton repente envuelto en un TintContextWrapper .
  3. ¿Debería esperarse realmente este comportamiento?

Definición de ImageButton en xml es simplemente:

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

Rastro de la pila:

 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) 

  1. Tanto la actividad n TintContextWRapper viene de ContextWrapper . ContextWrapper tiene un método getBaseContext() . Debería ser fácil crear un método de bucle que compruebe la instanceof WrapContext , obtenga el contexto base y, a continuación, compruebe la instanceof Activity . (Si tienes problemas con este método comentario aquí que voy a cavar en algún proyecto mío y pegar aquí a u)

  2. Debido a que AppCompat envuelve su contexto para poder inyectar "compat" vistas y "compat" tintado y otras cosas "compat". Eso es normal.

  3. Sí. Así es como AppCompat hace su cosa.

Krøllebølle

Librería de soporte de Android 23.4.0: android.support.v7.widget.TintContextWrapper no se puede publicar en Actividad

La respuesta a usted pregunta es: primero su código del acontecimiento del tecleo debe ser como:

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

Y luego escribir la función getRequiredActivity ():

 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; 

}

Y su Crash / Excepción es fijo 🙂

Mi sugerencia es pasar una referencia de su actividad en el onClickListener para evitar el problema con TintContextWrapper . Dar a su clase una referencia a MyActivity es simple y evita posibles problemas de casting.

Puedes probar

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

Obtiene el contexto que contiene esta vista sin el contenedor de android.support.v7.widget.TintContextWrapper.

  1. ¿Cómo puedo obtener MyActivity de TintContextWrapper?

Realmente no deberías. No hay garantía de que el Contexto de una Vista sea una Actividad – definitivamente no es una Actividad específica. ¿Dónde está configurando su OnClickListener? Estoy asumiendo que en el lugar donde usted establece el oyente, usted tendrá acceso a la actividad. Por ejemplo, si está configurando el listener de una Actividad:

 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); } } } 

Funcionó para mí después de actualizar las bibliotecas de soporte de Android.

Me enfrenté al mismo problema y se resolvió con
– Biblioteca de soporte de Android, revisión 24.2.1 (septiembre de 2016)
– compileSdkVersion 24
– buildToolsVersion "24.0.3"

  • Cómo agregar Snackbars en un BroadcastReceiver?
  • Problema con windowTranslucentNavigation
  • ADVERTENCIA: Se han encontrado android-support-v4 y android-support-v13 en la lista de dependencias
  • PreferenceInternet no se abre con PreferenceFragmentCompat
  • Icono de elemento del cajón de navegación que no muestra el color original
  • Aplicación de un tema a v7 Support Action Bar
  • El ancho de DialogFragment se reduce después de especificar FEATURE_NO_TITLE
  • SearchView getActionView devolver null
  • Android: ¿Cómo puedo evitar que DrawerLayout pase eventos táctiles a la vista subyacente
  • Causando un error de java.IllegalStateException, ninguna actividad, solamente cuando navega al fragmento por la SEGUNDA vez
  • Biblioteca de soporte de Android lanzando una excepción de recursos no encontrados
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.