android textview meizu

android - NullPointerException en dispositivos Meizu en Editor.updateCursorPositionMz



textview (8)

En mi caso, verifiqué que el uso de AppCompatEditText lugar de TextInputEditText efectivamente evitó bloqueos, pero no pudimos usar esta solución. Estamos usando un sdk con vistas que extienden TextInputEditText , por lo que cambiar a AppCompatEditText requeriría copiar / modificar un poco el código sdk en nuestro proyecto.

Intenté establecer la sugerencia tanto en TextInputEditText como en TextInputLayout , pero terminé viendo una doble sugerencia (como un texto borroso, y estoy seguro de que no bebí demasiado).

Eché un vistazo al problema de GitHub vinculado por @Andrew: github.com/android-in-china/Compatibility/issues/11

En ese problema, explican que la causa raíz es un problema en Meizu cuando TextInputEditText.getHint() es diferente de TextInputEditText.mHint .

Cuando TextInputEditText está dentro de TextInputLayout , y la sugerencia se especifica en xml en TextInputEditText , la biblioteca de soporte básicamente "mueve" la sugerencia al TextInputLayout contiene: lo establece en el contenedor y luego lo establece en null en el texto de edición.

Esta fuente que hace esto está en TextInputLayout.setEditText() :

// If we do not have a valid hint, try and retrieve it from the EditText, if enabled if (hintEnabled) { if (TextUtils.isEmpty(hint)) { // Save the hint so it can be restored on dispatchProvideAutofillStructure(); originalHint = this.editText.getHint(); setHint(originalHint); // Clear the EditText''s hint as we will display it ourselves this.editText.setHint(null); }

Luego, cuando llame a TextInputEditText.getHint() , devolverá la sugerencia del contenedor.

Esta incoherencia entre getHint() (el valor de la sugerencia) y mHint (nulo) parece plantear un problema para los dispositivos Meizu

Encontré otra forma de evitar este problema.

En los dispositivos Meizu, yo:

1) restablece de manera programática la sugerencia de TextInputEditText a su configuración original de xml (al llamar a su getHint() anulada, que devuelve la sugerencia del contenedor).

2) establezca el color de la sugerencia de TextInputEditText en transparente, para evitar el efecto de doble / borrosa sugerencia:

private void hackFixHintsForMeizu(TextInputEditText... editTexts) { String manufacturer = Build.MANUFACTURER.toUpperCase(Locale.US); if (manufacturer.contains("MEIZU")) { for (TextInputEditText editText : editTexts) { editText.setHintTextColor(Color.TRANSPARENT); editText.setHint(editText.getHint()); } } }

Últimamente, se han producido fallos en mi aplicación de Android, solo en dispositivos Meizu (M5c, M5s, M5 Note). Versión de Android: 6.0.

Aquí está la traza de pila completa:

Fatal Exception: java.lang.NullPointerException: Attempt to invoke virtual method ''int android.text.Layout.getLineForOffset(int)'' on a null object reference at android.widget.Editor.updateCursorPositionMz(Editor.java:6964) at android.widget.Editor.updateCursorsPositions(Editor.java:1760) at android.widget.TextView.getUpdatedHighlightPath(TextView.java:5689) at android.widget.TextView.onDraw(TextView.java:5882) at android.view.View.draw(View.java:16539) at android.view.View.updateDisplayListIfDirty(View.java:15492) at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3719) at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3699) at android.view.View.updateDisplayListIfDirty(View.java:15443) at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3719) at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3699) at android.view.View.updateDisplayListIfDirty(View.java:15443) at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3719) at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3699) at android.view.View.updateDisplayListIfDirty(View.java:15443) at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3719) at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3699) at android.view.View.updateDisplayListIfDirty(View.java:15443) at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3719) at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3699) at android.view.View.updateDisplayListIfDirty(View.java:15443) at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3719) at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3699) at android.view.View.updateDisplayListIfDirty(View.java:15443) at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3719) at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3699) at android.view.View.updateDisplayListIfDirty(View.java:15443) at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3719) at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3699) at android.view.View.updateDisplayListIfDirty(View.java:15443) at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3719) at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3699) at android.view.View.updateDisplayListIfDirty(View.java:15443) at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3719) at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3699) at android.view.View.updateDisplayListIfDirty(View.java:15443) at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3719) at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3699) at android.view.View.updateDisplayListIfDirty(View.java:15443) at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3719) at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3699) at android.view.View.updateDisplayListIfDirty(View.java:15443) at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:286) at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:292) at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:327) at android.view.ViewRootImpl.draw(ViewRootImpl.java:3051) at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2855) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2464) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1337) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6819) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:894) at android.view.Choreographer.doCallbacks(Choreographer.java:696) at android.view.Choreographer.doFrame(Choreographer.java:631) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:880) at android.os.Handler.handleCallback(Handler.java:815) at android.os.Handler.dispatchMessage(Handler.java:104) at android.os.Looper.loop(Looper.java:207) at android.app.ActivityThread.main(ActivityThread.java:5969) at java.lang.reflect.Method.invoke(Method.java) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:830) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:720)

No hay una relación directa con mi código (incluso en los stracktraces de otros hilos). Solo sé que sucede cada vez que en un fragmento en el que hay vistas de texto. Puede estar ocurriendo cuando un TextView está ganando enfoque, pero no tengo forma de estar seguro. Por supuesto no puedo reproducir el error, a menos que compre un Meizu.

Además, dado que el método superior se llama updateCursorPositionMz , me parece que esto puede ser un problema interno en el FlymeOS de Meizu ("Mz" = "Meizu"?).

¿Alguien ya ha tenido este problema, conoce la causa y cómo solucionarlo?

Gracias.



Estoy utilizando Kotlin y Fragmentos y acabo de corregir de forma recursiva todas las entradas de texto en onViewCreated.

override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) fixTextInputEditText(view) // call this in onViewCreated } private fun fixTextInputEditText(view: View) { val manufacturer = Build.MANUFACTURER.toUpperCase(Locale.US) if ("MEIZU" in manufacturer) { val views = getAllTextInputs(view) views.forEach(::hackFixHintsForMeizu) } } private fun getAllTextInputs(v: View): List<TextInputEditText> { if (v !is ViewGroup) { val editTexts = mutableListOf<TextInputEditText>() (v as? TextInputEditText)?.let { editTexts += it } return editTexts } val result = mutableListOf<TextInputEditText>() for (i in 0 until v.childCount) { val child = v.getChildAt(i) result += getAllTextInputs(child) } return result } private fun hackFixHintsForMeizu(editText: TextInputEditText) { if (editText.hint != null) { editText.setHintTextColor(Color.TRANSPARENT) editText.hint = editText.hint } }


Finalmente tuve la oportunidad de poner mis manos en un Meizu. Como pensé, el bloqueo se produce cada vez que el usuario hace clic en un campo para obtener el foco.

En mi caso, tuve algunos android.support.design.widget.TextInputEditText dentro de TextInputLayout s. Simplemente reemplazando estos TextInputEditText s con AppCompatEditText s solucionamos el problema, de esta manera:

<android.support.design.widget.TextInputLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="..."> <android.support.v7.widget.AppCompatEditText android:layout_width="match_parent" android:layout_height="wrap_content"/> </android.support.design.widget.TextInputLayout>

El comportamiento sigue siendo el mismo (ya que TextInputEditText extiende AppCompatEditText ). Sin embargo, todavía no he encontrado la causa raíz del problema.


La adición de la sugerencia en TextInputLayout y TextInputEditText solucionó el bloqueo para mí:

<android.support.design.widget.TextInputLayout android:id="@+id/text_input_layout" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="@string/login" app:hintAnimationEnabled="false"> <android.support.design.widget.TextInputEditText android:id="@+id/text_input_edit_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="@string/login" /> </android.support.design.widget.TextInputLayout>

Finalmente, reinicie la sugerencia de TextInputEditText programación para evitar el color muy oscuro del texto de la sugerencia:

editText = findViewById(R.id.text_input_edit_text); editText.setHint("");

Verificado en Meizu MX6 con Android 6.0


Ninguna de las variantes anteriores funcionó para mí sin modificaciones.

Mi aplicación usa fragmentos, TextInputEditText a veces se usa sin TextInputLayout, la actualización a la última versión de AndroidX no era una opción en este momento, reemplazar el TextInputEditText tampoco era una opción en este momento.

Mi versión (basada en esa solución y la solución de Google):

import android.os.Build import java.util.* import android.content.Context import android.support.design.widget.TextInputEditText import android.util.AttributeSet import android.widget.TextView import android.support.design.widget.TextInputLayout import android.view.inputmethod.EditorInfo import android.view.inputmethod.InputConnection import java.lang.reflect.Field import java.lang.reflect.Method import android.support.design.R class MyInputEditText(context: Context?, attrs: AttributeSet?,defStyleAttr:Int) : TextInputEditText(context, attrs,defStyleAttr){ constructor(context: Context?, attrs: AttributeSet?):this(context,attrs,R.attr.editTextStyle) constructor(context: Context?):this(context,null,R.attr.editTextStyle) private val buggyMeizu = ("meizu") in Build.MANUFACTURER.toLowerCase(Locale.US) private lateinit var getTextInputLayoutMethod:Method private lateinit var providesHintMethod:Method private lateinit var mHintField:Field init { if (buggyMeizu) { getTextInputLayoutMethod=TextInputEditText::class.java.getDeclaredMethod("getTextInputLayout") getTextInputLayoutMethod.isAccessible=true providesHintMethod=TextInputLayout::class.java.getDeclaredMethod("isProvidingHint") providesHintMethod.isAccessible=true mHintField=TextView::class.java.getDeclaredField("mHint") mHintField.isAccessible=true } } private fun getTILProvidesHint():Boolean { val layout=getTIL() if (layout!=null) { val result=providesHintMethod.invoke(layout) as Boolean return result; } else { return false } } private fun getTIL():TextInputLayout? = getTextInputLayoutMethod.invoke(this) as TextInputLayout? private fun getBaseHint():CharSequence? = mHintField.get(this) as CharSequence? override fun getHint(): CharSequence? { if (!buggyMeizu) { return super.getHint() } else { val layout=getTIL() return if (layout != null && (getTILProvidesHint()) ) layout.hint else provideHintWrapped() } } override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection? { val needHint=(outAttrs.hintText==null) val ic = super.onCreateInputConnection(outAttrs) if (buggyMeizu) { if (ic != null && needHint) { outAttrs.hintText = this.provideHintWrapped() } } return ic } private fun provideHintWrapped():CharSequence? { val hintFromLayout=getHintFromLayoutMine() if (hintFromLayout!=null) { return hintFromLayout } else { val baseHint=getBaseHint() if (baseHint!=null) { return baseHint } else { return null } } } private fun getHintFromLayoutMine(): CharSequence? { val layout = getTIL() return layout?.hint } override fun onAttachedToWindow() { if (buggyMeizu) { val baseHint=getBaseHint() if (getTIL() != null && getTILProvidesHint() && baseHint == null) { this.hint="" } } super.onAttachedToWindow() } }

Después de eso, busque y reemplace TextInputEditText con MyInputEditText en todos los archivos de diseño y código.


FixedTextInputEditText mi solución en el FixedTextInputEditText como se menciona en https://github.com/android-in-china/Compatibility/issues/11#issuecomment-427560370 .

En primer lugar, creé una instancia de TextInputEditText fija:

public class MeizuTextInputEditText extends TextInputEditText { public MeizuTextInputEditText(Context context) { super(context); } public MeizuTextInputEditText(Context context, AttributeSet attrs) { super(context, attrs); } public MeizuTextInputEditText(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public CharSequence getHint() { try { return getMeizuHintHack(); } catch (Exception e) { return super.getHint(); } } private CharSequence getMeizuHintHack() throws NoSuchFieldException, IllegalAccessException { Field textView = TextView.class.getDeclaredField("mHint"); textView.setAccessible(true); return (CharSequence) textView.get(this); } }

Pero luego tendría que reemplazar todos mis usos TextInputEditText con MeizuTextInputEditText que no es algo que pueda hacer fácilmente en una base de código más grande. Además, al crear vistas futuras, siempre debe considerar el uso de MeizuTextInputEditText lugar de la vista "rota". Olvidarse de eso fácilmente volvería a presentar problemas de producción.

Por lo tanto, la solución final consiste en la clase de vista personalizada y junto con la biblioteca ViewPump ( https://github.com/InflationX/ViewPump ) podemos hacerlo fácilmente. Tal como se explica en los documentos, debe registrar un interceptor personalizado que se parece a este:

public class TextInputEditTextInterceptor implements Interceptor { @Override public InflateResult intercept(Chain chain) { InflateRequest request = chain.request(); View view = inflateView(request.name(), request.context(), request.attrs()); if (view != null) { return InflateResult.builder() .view(view) .name(view.getClass().getName()) .context(request.context()) .attrs(request.attrs()) .build(); } else { return chain.proceed(request); } } @Nullable private View inflateView(String name, Context context, AttributeSet attrs) { if (name.endsWith("TextInputEditText")) { return new MeizuTextInputEditText(context, attrs); } return null; } }

Y el registro de ese interceptor personalizado se realiza igual que en los documentos mediante la configuración de un ViewPump en el onCreate de su actividad:

@Override @CallSuper protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); ViewPump.Builder viewPumpBuilder = ViewPump.builder(); if (isMeizuDevice()) { viewPumpBuilder.addInterceptor(new TextInputEditTextInterceptor()); } ViewPump.init(viewPumpBuilder.build()); }

Como puede ver, solo MeizuTextInputEditText el MeizuTextInputEditText si se detecta un dispositivo Meizu. De esa manera, la reflexión no se activa para los dispositivos que no la necesitan. Además, este método es una clase de actividad básica que tengo de la cual todas las demás actividades se extienden en mi proyecto, por lo que todas las actividades que se inician en mi proyecto Y donde el dispositivo es un Meizu tendrán la solución automáticamente.


Eliminar la sugerencia de xml : ya sea de TextInputLayout o TextInputEditText .

Para componentes de material

<com.google.android.material.textfield.TextInputLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <com.google.android.material.textfield.TextInputEditText android:id="@+id/text_input_edit_text" android:layout_width="match_parent" android:layout_height="wrap_content"/> </com.google.android.material.textfield.TextInputLayout>

Para soporte de diseño

<android.support.design.widget.TextInputLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <android.support.design.widget.TextInputEditText android:id="@+id/text_input_edit_text" android:layout_width="match_parent" android:layout_height="wrap_content"/> </android.support.design.widget.TextInputLayout>

En el código establecido, sugerencia programática :

val myTextInputEditText = findViewById<TextInputEditText>(R.id.text_input_edit_text) myTextInputEditText.hint = "Your hint"

Probado en Meizu M5S , Android 6.0