Android LiveData análisis de código fuente-lectura de código fuente 100 días (2)

0. Introducción

LiveData, también pertenece a la colección de compilación JetPack, según la descripción del documento LiveData es una clase de contenedor de datos observable. A diferencia de los observables habituales, LiveData tiene en cuenta el ciclo de vida, lo que significa que respeta el ciclo de vida de otros componentes de la aplicación, como Actividad, Fragmento o Servicio. Este conocimiento garantiza que LiveData solo actualice los observadores de componentes de la aplicación que se encuentran en el estado del ciclo de vida activo.
Ventajas (lo siguiente se tomó del documento de Google, Google lo tradujo)
(1) Asegúrese de que su interfaz de usuario se ajuste al estado de sus datos
LiveData sigue el patrón del observador. Cuando el estado del ciclo de vida cambia, LiveData notificará al objeto Observer. Puede fusionar código para actualizar la interfaz de usuario en estos objetos Observer. Cada vez que cambian los datos de la aplicación, sus observadores pueden actualizar la interfaz de usuario cada vez que cambia, en lugar de actualizar la interfaz de usuario.
(2) No hay pérdida de memoria. El
observador está vinculado al objeto de ciclo de vida y se limpia después de que se destruye su ciclo de vida relacionado.
Sin bloqueo debido a inactividad
Si el ciclo de vida del observador está inactivo (por ejemplo, en el caso de actividad en la pila de back-end), no recibirá ningún evento de LiveData.
(3) El procesamiento manual del ciclo de vida de los
componentes de la interfaz de usuario ya no es necesario, solo se observan los datos relacionados, y no se detendrá ni reanudará la observación. LiveData gestiona automáticamente todos estos porque es consciente de los cambios de estado del ciclo de vida relevantes mientras observa.
(4) Conserve siempre los datos más recientes
Si el ciclo de vida pasa a estar inactivo, se recibirán los datos más recientes cuando vuelva a estar activo. Por ejemplo, las actividades en segundo plano reciben los datos más recientes inmediatamente después de volver al primer plano.
(5) Cambios de configuración apropiados
Si las actividades o los segmentos se vuelven a crear debido a cambios de configuración (como la rotación del dispositivo), los últimos datos disponibles se recibirán de inmediato.
(6) Compartir recursos
Puede usar el patrón singleton para extender los objetos LiveData para envolver los servicios del sistema para que puedan compartirse en la aplicación. El objeto LiveData se conecta al servicio del sistema una vez, y luego cualquier observador que necesite el recurso solo puede ver el objeto LiveData.

1. Utilizar

class MainActivity : AppCompatActivity() {

    val curName: MutableLiveData<String> by lazy {

        MutableLiveData<String>()
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        curName.observe(this, Observer<String> {
            println("value is $it")
        })
        curName.value="old value"
    }

}

El uso es muy simple, cuando el valor del objeto MutableLiveData cambia, se lanza el método onChanged del Observer, donde MutableLiveData hereda de LiveData.

2.Proposito

(1) ¿Cómo LiveData realiza el conocimiento del ciclo de vida?
(2) Cómo actualizar eventos
(3) Cómo evitar pérdidas de memoria

3. Análisis

3.1 ¿Cómo LiveData realiza el conocimiento del ciclo de vida?

Primero mira el método del observador de LiveData

@MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        if (existing != null && !existing.isAttachedTo(owner)) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;
        }
        owner.getLifecycle().addObserver(wrapper);
    }

Mire la última línea, owner.getLifecycle (). AddObserver (wrapper); el propietario es la Actividad o Fragmento que usamos, que corresponde al artículo anterior Ciclo de vida en el
análisis del código fuente del ciclo de vida de Android: lectura del código fuente 100 días (1) , agregue aquí El oyente es LifecycleBoundObservr, esta clase implementa LifecycleObserver, que es la forma de detectar el ciclo de vida.

3.2 Cómo actualizar eventos

Para ser honesto, este control es un modo de observador, el observador del evento es LifecycleBoundObserver, mire el método onStateChanged de este objeto

        @Override
        public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            activeStateChanged(shouldBeActive());
        }

Eche un vistazo al método activieStageChanged

void activeStateChanged(boolean newActive) {
            if (newActive == mActive) {
                return;
            }
            // immediately set active state, so we'd never dispatch anything to inactive
            // owner
            mActive = newActive;
            boolean wasInactive = LiveData.this.mActiveCount == 0;
            LiveData.this.mActiveCount += mActive ? 1 : -1;
            if (wasInactive && mActive) {
                onActive();
            }
            if (LiveData.this.mActiveCount == 0 && !mActive) {
                onInactive();
            }
            if (mActive) {
                dispatchingValue(this);
            }
        }

Este método se utiliza para tratar el ciclo de vida para evitar pérdidas de memoria. El método real que se utiliza para observar los datos para su procesamiento es el método dispatchingValue. Eche un vistazo a este método.

private void dispatchingValue(@Nullable ObserverWrapper initiator) {
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            if (initiator != null) {
                considerNotify(initiator);
                initiator = null;
            } else {
                for (Iterator<Map.Entry<Observer<T>, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }

Si el parámetro ObserverWrapper no es nulo, llame al método considerNotify; de lo contrario, itere sobre mObservers y llame a considerNotify, luego eche un vistazo a este método

private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            return;
        }
        // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
        //
        // we still first check observer.active to keep it as the entrance for events. So even if
        // the observer moved to an active state, if we've not received that event, we better not
        // notify for a more predictable notification order.
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        //noinspection unchecked
        observer.mObserver.onChanged((T) mData);
    }

Primero determine si es necesario activar ObserverWrapper, si necesita ser activado, llame al método activeStateChanged; de lo contrario, llame al método onChanged ((T) mData) de nuestro Observer personalizado.

3.3 Cómo evitar pérdidas de memoria

Vuelva al activeStateChanged (shouldBeActive ()) llamado en el método onStateChanged, mire el método shouldBeActive

 @Override
        boolean shouldBeActive() {
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }
        
 public boolean isAtLeast(@NonNull State state) {
            return compareTo(state) >= 0;
        }        

Este método es para comparar el estado actual con STARTED, si es STARTED o RESUMED, entonces el parámetro pasado en activeStateChanged es verdadero, de lo contrario es falso, luego mira hacia atrás en el método activeStateChanged

void activeStateChanged(boolean newActive) {
            if (newActive == mActive) {
                return;
            }
            // immediately set active state, so we'd never dispatch anything to inactive
            // owner
            mActive = newActive;
            boolean wasInactive = LiveData.this.mActiveCount == 0;
            LiveData.this.mActiveCount += mActive ? 1 : -1;
            if (wasInactive && mActive) {
                onActive();
            }
            if (LiveData.this.mActiveCount == 0 && !mActive) {
                onInactive();
            }
            if (mActive) {
                dispatchingValue(this);
            }
        }
    }

Cuando el estado no ha cambiado, regrese directamente; de ​​lo contrario, juzgue si es el estado activo según newActive,

          if (wasInactive && mActive) {
                onActive();
            }
            if (LiveData.this.mActiveCount == 0 && !mActive) {
                onInactive();
            }

Luego llame a los métodos onActive y onInactive de acuerdo con mActive y activeCount. Esto es claro de un vistazo, cuando el ciclo de vida llama a onStart, está en estado activo, y después de onstop está en estado inactivo, de modo que cuando los datos cambian, no pasarán al método Observer, evitando así pérdidas de memoria. .

Sigue mi cuenta pública

Supongo que te gusta

Origin blog.csdn.net/skateboard1/article/details/84330447
Recomendado
Clasificación