English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Explicación detallada del patrón de diseño Observador en programación Android

Este artículo narra un ejemplo de diseño de patrones de programación Android: patrón observador. Comparto con ustedes para que lo refieran, como se muestra a continuación:

Uno, introducción:

El patrón observador es un patrón muy utilizado, se utiliza más comúnmente en sistemas GUI, sistemas suscripción-publicación. Porque una de las funciones importantes de este patrón es la desacoplamiento, desacopla al observador y al observador, haciendo que su dependencia sea menor, incluso sin dependencia. En el caso del sistema GUI, la UI de la aplicación es variable, especialmente en la etapa inicial, con el cambio del negocio o la modificación de los requisitos del producto, la interfaz de la aplicación también cambia con frecuencia, pero la lógica del negocio cambia poco, en este caso, el sistema GUI necesita un mecanismo para hacer frente a esta situación, desacoplar la capa UI de la lógica de negocio específica, el patrón observador en este momento se pone en uso.

Dos, definición:

Define una relación de dependencia uno a muchos entre objetos, de manera que cada vez que un objeto cambia de estado, todos los objetos que dependen de él recibirán notificación y se actualizarán automáticamente.

Tres, escenarios de uso:

Escenarios de comportamiento asociado, es necesario tener en cuenta que el comportamiento asociado es desmontable, no es una relación de "composición".

Escenarios de desencadenamiento de eventos en múltiples niveles.

Escenarios de intercambio de mensajes entre sistemas, como el mecanismo de procesamiento de colas de mensajes y el bus de eventos.

Cuatro, el diagrama de clase del patrón observador:

Diagrama de clase UML:

Introducción al rol:

Tema: Tema abstracto, también conocido como el rol del observador (Observable), el rol del tema abstracto guarda las referencias de todos los objetos observadores en una agrupación, y cada tema puede tener cualquier número de observadores. El tema abstracto proporciona una interfaz para agregar y eliminar objetos observadores.

ConcreteSubject: Tema específico, este rol guarda el estado relevante en el objeto observador específico, notifica a todos los observadores registrados cuando cambia el estado propio del tema específico, el rol de tema específico también se llama rol observador específico (ConcreteObservable).

Observer: Observador abstracto, este rol es la clase abstracta del observador, define un interfaz de actualización, que permite que el propio se actualice cuando reciba la notificación de cambio del tema.

ConcreteObserver: Observador específico, este rol implementa el interfaz de actualización definido por el rol observador abstracto, para que el estado propio se actualice cuando cambie el estado del tema.

Cinco, implementación simple

Aquí les damos un ejemplo de seguir series, generalmente para no perdernos las últimas series, nos suscribimos o seguimos esta serie, y cuando la serie se actualiza, se nos notifica primero. Ahora simplemente lo implementemos.

Clase observadora abstracta:

/**
 * Clase observadora abstracta, define una interfaz para todos los observadores específicos, actualiza a sí misma cuando recibe una notificación
 */
public interface Observer {
  /**
   * Hay actualizaciones
   * 
   * @param message Mensaje
   */
  public void update(String message);
}

Clase observadora abstracta:

/**
 * Clase observadora abstracta
 */
public interface Observable {
  /**
   * Enviar mensaje
   * 
   * @param message Contenido
   */
  void push(String message);
  /**
   * Suscripción
   * 
   * @param observer Suscriptor
   */
  void register(Observer observer);
}

Clase observadora específica:

/**
 * Clase observadora específica, es decir, el suscriptor
 */
public class User implements Observer {
  @Override
  public void update(String message) {
    System.out.println(name + ", + message + "¡Actualizado!");
  }
  // Nombre del suscriptor
  private String name;
  public User(String name) {
    this.name = name;
  }
}

Clase observadora específica:

/**
 * Clase observadora específica, es decir, el programa suscrito
 */
public class Teleplay implements Observable{
  private List<Observer> list = new ArrayList<Observer>();//Almacenar suscriptores
  @Override
  public void push(String message) {
    for(Observer observer:list){
      observer.update(message);
    }
  }
  @Override
  public void register(Observer observer) {
    list.add(observer);
  }
}

Implementación:

public class Client {
  public static void main(String[] args) {
    //Observado, aquí es el programa de televisión suscrito por el usuario
    Teleplay teleplay = new Teleplay();
    //Observador, aquí es el usuario de suscripción
    User user1 = new User("Xiaoming");
    User user2 = new User("Xiaoguang");
    User user3 = new User("Xiaolan");
    //Suscripción
    teleplay.register(user1);
    teleplay.register(user2);
    teleplay.register(user3);
    //Enviar nuevo mensaje
    teleplay.push("xxx programa de televisión");
  }
}

Resultados:

Xiaoming, el programa de televisión xxx se actualizó!
Xiaoguang, el programa de televisión xxx se actualizó!
Xiaolan, el programa de televisión xxx se actualizó!

A partir del código anterior, podemos ver que se ha implementado un mensaje de emisión de uno a muchos, y los mensajes de emisión dependen de las clases abstractas Observer y Observable, mientras que User y Teleplay no tienen耦合, lo que garantiza la flexibilidad y escalabilidad del sistema de suscripción.

Seis, patrón observador en el código fuente de Android

1、BaseAdapter

BaseAdapter, creo que todos lo conocemos, en el adaptador de ListView lo heredamos. Vamos a analizarlo brevemente.

Código parte de BaseAdapter:

public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
  //Observador de conjunto de datos
  private final DataSetObservable mDataSetObservable = new DataSetObservable();
  public boolean hasStableIds() {
    return false;
  }
  public void registerDataSetObserver(DataSetObserver observer) {
    mDataSetObservable.registerObserver(observer);
  }
  public void unregisterDataSetObserver(DataSetObserver observer) {
    mDataSetObservable.unregisterObserver(observer);
  }
  /**
   * Notifica a todos los observadores cuando el conjunto de datos cambia.
   */
  public void notifyDataSetChanged() {
    mDataSetObservable.notifyChanged();
  }
}

Mira el método mDataSetObservable.notifyChanged():

public class DataSetObservable extends Observable<DataSetObserver> {
  /**
   * Invoca {@link DataSetObserver#onChanged} en cada observador.
   * Llamado cuando los contenidos del conjunto de datos han cambiado. El destinatario
   * obtendrá los nuevos contenidos la próxima vez que consulte el conjunto de datos.
   */
  public void notifyChanged() {
    synchronized(mObservers) {
      // ya que onChanged() es implementado por la aplicación, podría hacer cualquier cosa, incluyendo
      // se elimina a sí mismo de {@link mObservers} - lo que podría causar problemas si
      // se utiliza un iterador en la ArrayList {@link mObservers}.
      // para evitar tales problemas, simplemente recorre la lista en orden inverso.
      for (int i = mObservers.size() - 1; i >= 0; i--) {
        mObservers.get(i).onChanged();
      }
    }
  }
}

可以看出在mDataSetObservable.notifyChanged()中遍历所有观察者,并调用他们的onChanged(),从而告知观察者发生了什么。

那么观察者怎么来的,那就是setAdapter方法,代码如下:

@Override
public void setAdapter(ListAdapter adapter) {
    if (mAdapter != null && mDataSetObserver != null) {
      mAdapter.unregisterDataSetObserver(mDataSetObserver);
    }
    resetList();
    mRecycler.clear();
    if (mHeaderViewInfos.size() > 0 || mFooterViewInfos.size() > 0) {
      mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
    }
      mAdapter = adapter;
    }
    mOldSelectedPosition = INVALID_POSITION;
    mOldSelectedRowId = INVALID_ROW_ID;
    // AbsListView#setAdapter将对选择模式状态进行更新。
    super.setAdapter(adapter);
    if (mAdapter != null) {
      mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
      mOldItemCount = mItemCount;
      mItemCount = mAdapter.getCount();
      checkFocus();
      mDataSetObserver = new AdapterDataSetObserver();
      mAdapter.registerDataSetObserver(mDataSetObserver);//注册观察者
      ......省略
    }
}

AdapterDataSetObserver定义在ListView的父类AbsListView中,是一个数据集观察者,代码:

class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {
  @Override
  public void onChanged() {
    super.onChanged();
    if (mFastScroller != null) {
      mFastScroller.onSectionsChanged();
    }
  }
  @Override
  public void onInvalidated() {
    super.onInvalidated();
    if (mFastScroller != null) {
      mFastScroller.onSectionsChanged();
    }
  }
}

Este se debe a AdapterDataSetObserver, que hereda de AdapterView del padre AbsListView, el código es el siguiente:

class AdapterDataSetObserver extends DataSetObserver {
  private Parcelable mInstanceState = null;
  // Como se mencionó anteriormente, cuando se llama a notifyDataSetChanged del Adapter, se llama al método onChanged de todos los observadores, la implementación central está aquí
  @Override
  public void onChanged() {
    mDataChanged = true;
    mOldItemCount = mItemCount;
    // Obtener la cantidad de datos en el Adapter
    mItemCount = getAdapter().getCount();
    // Detectar el caso en el que un cursor que anteriormente se invalidó tiene
    // ha sido repopulado con nuevos datos.
    if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null
          && mOldItemCount == 0 && mItemCount > 0) {
      AdapterView.this.onRestoreInstanceState(mInstanceState);
      mInstanceState = null;
    }
      rememberSyncState();
    }
    checkFocus();
    // Reorganizar los componentes de AdapterView como ListView, GridView y otros
    requestLayout();
  }
  // El código se omitió
  public void clearSavedState() {
    mInstanceState = null;
  }
}

Cuando los datos de ListView cambian, se llama a la función notifyDataSetChanged del Adapter, esta función a su vez llama a la función notifyChanged del DataSetObservable, esta función llama al método onChanged de todos los observadores (AdapterDataSetObserver). ¡Esto es un patrón Observer!

Capítulo VII: Resumen

Ventajas:

La耦合 entre el observador y el observado es abstracta, para hacer frente a los cambios en el negocio.

Mejorar la flexibilidad y la expansibilidad del sistema.

Desventajas:

Al aplicar el patrón Observer, es necesario considerar problemas como la eficiencia de desarrollo y la eficiencia de ejecución. En el programa, incluye un observador, varios observadores, y el desarrollo, depuración y otros son bastante complejos. Además, en Java, la notificación de mensajes generalmente se ejecuta en orden, por lo que si un observador se atasca, puede afectar la eficiencia de ejecución general. En este caso, generalmente se utiliza una implementación asíncrona.

Los lectores interesados en más contenido relacionado con Android pueden consultar las secciones especiales de este sitio: 'Introducción y tutorial avanzado de desarrollo Android', 'Técnicas de depuración y resumen de métodos de solución de problemas comunes de Android', 'Resumen de uso de componentes básicos de Android', 'Resumen de técnicas de View de Android', 'Resumen de técnicas de layout de Android' y 'Resumen de uso de controles de Android'.

Espero que lo descrito en este artículo pueda ayudar a todos en el diseño de programas Android.

Declaración: El contenido de este artículo se obtiene de la red, pertenece al propietario original, el contenido se contribuye y carga de manera autónoma por los usuarios de Internet, este sitio no posee los derechos de propiedad, no se ha procesado editorialmente y no asume la responsabilidad legal relevante. Si encuentra contenido sospechoso de copyright, le invitamos a enviar un correo electrónico a: notice#oldtoolbag.com (al enviar un correo electrónico, reemplace # con @) para denunciar y proporcionar evidencia relevante. Una vez verificada, este sitio eliminará inmediatamente el contenido sospechoso de infracción.

Te gustará