Android interfaz de usuario no estrellarse cuando se modifica la interfaz de usuario Ver fuera del hilo

estiércol:

Guión:

Me encontré con un problema extraño mientras que las pruebas a cabo las discusiones en mi fragmento.

Tengo un fragmento escrito en Kotlin con el siguiente fragmento en onResume ():

override fun onResume() {
    super.onResume()

    val handlerThread = HandlerThread("Stuff")
    handlerThread.start()
    val handler = Handler(handlerThread.looper)
    handler.post {
        Thread.sleep(2000)
        tv_name.setText("Something something : " + isMainThread())
    }
}

es TrenzadoPrincipal () es una función que comprueba si el hilo actual es el hilo principal de este modo:

private fun isMainThread(): Boolean = Looper.myLooper() == Looper.getMainLooper()

Estoy viendo mi TextView se actualiza después de 2 segundos con el texto "Algo algo: true"

Profetizándoles me dice que este hilo no está en el hilo UI / Main.

Me pareció que era extraño así que creé el mismo fragmento, pero escrito en Java en lugar de con el siguiente fragmento de onResume ():

@Override
public void onResume() {
    super.onResume();

    HandlerThread handlerThread = new HandlerThread("stuff");
    handlerThread.start();
    new Handler(handlerThread.getLooper()).post(new Runnable() {
        @Override
        public void run() {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            textView.setText("Something something...");
        }
    });
}

La aplicación se bloquea con la siguiente excepción como se esperaba:

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
        at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:7313)
        at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:1161)

Hice un poco de investigación, pero realmente no pude encontrar algo que explica esto. También, por favor asumen que mis puntos de vista están inflados correctamente.

Pregunta:

¿Por qué mi aplicación se bloquea cuando se modifico mi TextView en el ejecutable que se ejecuta fuera de mi hilo de interfaz de usuario en el fragmento escrito en Kotlin?

Si hay algo en alguna parte de alguna documentación que explica esto, por favor alguien puede referirse a esto?

No estoy realmente tratando de modificar mi interfaz de usuario fuera el hilo de interfaz de usuario, Tengo curiosidad por qué ocurre esto.

Por favor, hágamelo saber si ustedes necesitan más información. ¡Muchas gracias!

Actualización: Según lo mencionado @Hong Duan, requestLayout () no estaba recibiendo llamadas. Esto no tiene nada que ver con Kotlin / Java pero con la misma TextView.

Metí la pata y no nos dimos cuenta de que el TextView en mi fragmento Kotlin tiene una layout_width de "match_parent." Mientras que el TextView en mi fragmento de Java tiene un layout_width de "wrap_content."

TLDR: error del usuario + requestLayout (), donde no siempre se produce la comprobación de hilo.

Hong Duan:

La CalledFromWrongThreadExceptionúnica tiros cuando sea necesario, pero no siempre. En sus casos, cuando la lanza ViewRootImpl.checkThread()se llama durante ViewRootImpl.requestLayout(), aquí está el código de ViewRootImpl.java:

@Override
public void requestLayout() {
    if (!mHandlingLayoutInLayoutRequest) {
        checkThread();
        mLayoutRequested = true;
        scheduleTraversals();
    }
}

void checkThread() {
    if (mThread != Thread.currentThread()) {
        throw new CalledFromWrongThreadException(
                "Only the original thread that created a view hierarchy can touch its views.");
    }
}

Y para TextView, no siempre es necesario para la redistribución cuando lo actualizamos de texto, podemos ver la lógica en el código fuente :

/**
 * Check whether entirely new text requires a new view layout
 * or merely a new text layout.
 */
private void checkForRelayout() {
    // If we have a fixed width, we can just swap in a new text layout
    // if the text height stays the same or if the view height is fixed.

    if ((mLayoutParams.width != LayoutParams.WRAP_CONTENT
            || (mMaxWidthMode == mMinWidthMode && mMaxWidth == mMinWidth))
            && (mHint == null || mHintLayout != null)
            && (mRight - mLeft - getCompoundPaddingLeft() - getCompoundPaddingRight() > 0)) {
        // Static width, so try making a new text layout.

        int oldht = mLayout.getHeight();
        int want = mLayout.getWidth();
        int hintWant = mHintLayout == null ? 0 : mHintLayout.getWidth();

        /*
         * No need to bring the text into view, since the size is not
         * changing (unless we do the requestLayout(), in which case it
         * will happen at measure).
         */
        makeNewLayout(want, hintWant, UNKNOWN_BORING, UNKNOWN_BORING,
                      mRight - mLeft - getCompoundPaddingLeft() - getCompoundPaddingRight(),
                      false);

        if (mEllipsize != TextUtils.TruncateAt.MARQUEE) {
            // In a fixed-height view, so use our new text layout.
            if (mLayoutParams.height != LayoutParams.WRAP_CONTENT
                    && mLayoutParams.height != LayoutParams.MATCH_PARENT) {
                autoSizeText();
                invalidate();
                return; // return with out relayout
            }

            // Dynamic height, but height has stayed the same,
            // so use our new text layout.
            if (mLayout.getHeight() == oldht
                    && (mHintLayout == null || mHintLayout.getHeight() == oldht)) {
                autoSizeText();
                invalidate();
                return; // return with out relayout
            }
        }

        // We lose: the height has changed and we have a dynamic height.
        // Request a new view layout using our new text layout.
        requestLayout();
        invalidate();
    } else {
        // Dynamic width, so we have no choice but to request a new
        // view layout with a new text layout.
        nullLayouts();
        requestLayout();
        invalidate();
    }
}

Como se puede ver, en algunos casos, el requestLayout()no se llama, por lo que el registro de entrada del hilo principal no se introduce.

Así que creo que el punto clave no se trata de Kotlin o Java, se trata de los TextViewparametros de diseño s'que determinaron si requestLayout()se llama o no.

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=180230&siteId=1
Recomendado
Clasificación