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

Spiegazione dettagliata dell'implementazione del pattern Observer in Android

Questo articolo spiega un esempio di modello di progettazione di programmazione Android osservatore. Condivido con voi per riferimento, come segue:

Primo: Introduzione

Il modello osservatore è un modello molto utilizzato, il suo luogo più comune è il sistema GUI, il sistema di abbonamento-pubblicazione. Poiché una delle funzioni principali di questo modello è la decoupling, decoupling osservatore e osservato, riducendo la dipendenza tra loro, persino raggiungendo una dipendenza nulla. Per quanto riguarda il sistema GUI, l'interfaccia utente dell'applicazione è variabile, specialmente nei primi stadi di cambiamento del business o della modifica delle esigenze del prodotto, l'interfaccia dell'applicazione cambia spesso, ma la logica del business cambia di poco, in questo caso, il sistema GUI ha bisogno di un meccanismo per affrontare questa situazione, in modo che il livello dell'interfaccia utente sia decoupled dal logica del business specifico, il modello osservatore è quindi utile.

Secondo: Definizione

Definire una dipendenza a molti a uno tra oggetti, in modo che ogni volta che un oggetto cambia stato, tutti gli oggetti che dipendono da esso ricevono una notifica e vengono aggiornati automaticamente.

Terzo: Scena d'uso

Scena di comportamento correlato, è necessario notare che il comportamento correlato è divisibile, non è una relazione di "composizione".

Scena di attivazione multi-livello degli eventi.

Scena di scambio di messaggi tra sistemi diversi, come il meccanismo di elaborazione dei message queue, del bus di eventi.

Quarto: Diagramma di classe UML del modello osservatore

Diagramma di classe UML:

Introduzione ai ruoli:

Subject: Tema astratto, ossia il ruolo dell'osservato (Osservabile), il ruolo del tema astratto conserva le referenze agli oggetti osservatori in un aggregato, ogni tema può avere qualsiasi numero di osservatori. Il tema astratto fornisce un'interfaccia per aggiungere e rimuovere oggetti osservatori.

ConcreteSubject: Oggetto tematico specifico, il ruolo cui viene memorizzato lo stato in un oggetto osservatore specifico, quando lo stato interno del tema specifico cambia, notifica a tutti gli osservatori registrati. Il ruolo di ConcreteSubject è anche chiamato ruolo ConcreteObservable (Osservabile specifico).

Observer:抽象观察者,该角色是观察者的抽象类,它定义了一个更新接口,使得在得到主题的更改通知时更新自己。

ConcreteObserver:具体的观察者,该角色实现抽象观察者角色所定义的更新接口,以便主题的状态发生改变时更新自身的状态。

五、简单实现

这里举一个追剧的例子,平常为了不错过最新的电视剧我们会订阅或关注这个电视剧,当电视剧更新后会第一时间推送给我们,下来就简单实现一下。

抽象观察者类:

/**
 * 抽象观察者类,为所有具体观察者定义一个接口,在得到通知时更新自己
 */
public interface Observer {
  /**
   * 有更新
   * 
   * @param message 消息
   */
  public void update(String message);
}

抽象被观察者类:

/**
 * 抽象被观察者类
 */
public interface Observable {
  /**
   * 推送消息
   * 
   * @param message 内容
   */
  void push(String message);
  /**
   * 订阅
   * 
   * @param observer 订阅者
   */
  void register(Observer observer);
}

具体的观察者类:

/**
 * 具体的观察者类,也就是订阅者
 */
public class User implements Observer {
  @Override
  public void update(String message) {
    System.out.println(name + "," + message + "更新了!");
  }
  // 订阅者的名字
  private String name;
  public User(String name) {
    this.name = name;
  }
}

具体的被观察者类:

/**
 * 具体的被观察者类,也就是订阅的节目
 */
public class Teleplay implements Observable{
  private List<Observer> list = new ArrayList<Observer>();//存储订阅者
  @Override
  public void push(String message) {
    for(Observer observer:list){
      observer.update(message);}
    }
  }
  @Override
  public void register(Observer observer) {
    list.add(observer);
  }
}

Implementazione:

public class Client {
  public static void main(String[] args) {
    //Osservato, qui è il drama iscritto dall'utente
    Teleplay teleplay = new Teleplay();
    //Osservatore, qui è l'utente iscritto
    User user1 = new User("Xiaoming");
    User user2 = new User("Xiaoguang");
    User user3 = new User("Xiaolan");
    //Iscrizione
    teleplay.register(user1);
    teleplay.register(user2);
    teleplay.register(user3);
    //Push di nuova notizia
    teleplay.push("xxx drama");
  }
}

Risultato:

Xiaoming, il drama xxx è stato aggiornato!
Xiaoguang, il drama xxx è stato aggiornato!
Xiaolan, il drama xxx è stato aggiornato!

Dal codice sopra, possiamo vedere che è stato implementato un messaggio di push a molti a molti, i messaggi di push dipendono da classi astratte come Observer e Observable, mentre User e Teleplay non sono affatto collegati, garantendo la flessibilità e l'estensibilità del sistema di iscrizione.

Sezione 6: Modello Observer nel codice di origine di Android

1、BaseAdapter

BaseAdapter credo che molti di voi non siano estranei, nella ListView adapter ereditiamo da esso. Ora andiamo a analizzarlo brevemente.

BaseAdapter 部分代码:

public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
  //数据集观察者
  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);
  }
  /**
   * Quando il set di dati cambia, notifica tutti gli osservatori
   */
  public void notifyDataSetChanged() {
    mDataSetObservable.notifyChanged();
  }
}

Guarda il metodo mDataSetObservable.notifyChanged():

public class DataSetObservable extends Observable<DataSetObserver> {
  /**
   * Invoca {@link DataSetObserver#onChanged} su ogni osservatore.
   * Chiamato quando il contenuto del set di dati è cambiato. Il destinatario
   * otterrà i nuovi contenuti la prossima volta che consulta il set di dati.
   */
  public void notifyChanged() {
    synchronized(mObservers) {
      // poiché onChanged() è implementato dall'app, potrebbe fare qualsiasi cosa, inclusi
      // rimuovendosi da {@link mObservers} - e questo potrebbe causare problemi se
      // un iteratore viene utilizzato sull'ArrayList {@link mObservers}.
      // per evitare tali problemi, percorri la lista nell'ordine inverso.
      per (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);
    } else {
      mAdapter = adapter;
    }
    mOldSelectedPosition = INVALID_POSITION;
    mOldSelectedRowId = INVALID_ROW_ID;
    // AbsListView#setAdapter will update choice mode states.
    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();
    }
  }
}

È derivato dal DataSetObserver di AdapterView, il padre di AbsListView, come segue:

class AdapterDataSetObserver extends DataSetObserver {
  private Parcelable mInstanceState = null;
  // Come spiegato in precedenza, quando si chiama il metodo notifyDataSetChanged dell'Adapter, viene chiamato il metodo onChanged di tutti gli osservatori, l'implementazione fondamentale è qui
  @Override
  public void onChanged() {
    mDataChanged = true;
    mOldItemCount = mItemCount;
    // Ottieni il numero di dati nell'Adapter
    mItemCount = getAdapter().getCount();
    // Rileva il caso in cui un cursore precedentemente invalidato ha
    // è stato ripopolato con nuovi dati.
    if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null
          && mOldItemCount == 0 && mItemCount > 0) {
      AdapterView.this.onRestoreInstanceState(mInstanceState);
      mInstanceState = null;
    } else {
      rememberSyncState();
    }
    checkFocus();
    // Reimposta la layout per ListView, GridView e altri componenti AdapterView
    requestLayout();
  }
  // Codice omesso
  public void clearSavedState() {
    mInstanceState = null;
  }
}

Quando i dati di ListView cambiano, viene chiamata la funzione notifyDataSetChanged dell'Adapter, questa funzione a sua volta chiama la funzione notifyChanged di DataSetObservable, che a sua volta chiama il metodo onChanged di tutti gli Observatori (AdapterDataSetObserver). Questo è un modello Observatore!

Sette, Sommario

Vantaggi:

La relazione tra Observatore e Observato è un耦合 astratto, adatto a rispondere ai cambiamenti aziendali.

Migliora la flessibilità e l'estensibilità del sistema.

Svantaggi:

Quando si utilizza lo schema Observatore, è necessario considerare problemi come l'efficienza di sviluppo e l'efficienza di esecuzione. Il programma include un Observatore, più Observatori, e il processo di sviluppo e debug è piuttosto complesso. Inoltre, i messaggi di notifica in Java sono generalmente eseguiti in ordine, quindi se un Observatore si blocca, può influenzare l'efficienza complessiva dell'esecuzione. In questo caso, generalmente si adotta un'implementazione asincrona.

Per i lettori interessati a ulteriori contenuti relativi a Android, si prega di consultare le sezioni speciali di questo sito: 'Guida di base e avanzata per lo sviluppo Android', 'Trucchi di debug e soluzioni ai problemi comuni Android', 'Sommarizzazione dell'uso dei componenti di base Android', 'Sommarizzazione delle tecniche di View Android', 'Sommarizzazione delle tecniche di layout Android' e 'Sommarizzazione dell'uso dei controlli Android'.

Spero che il contenuto di questo articolo possa essere utile per la progettazione di applicazioni Android.

Dichiarazione: il contenuto di questo articolo è stato prelevato da Internet, è di proprietà del rispettivo autore, il contenuto è stato contribuito e caricato dagli utenti di Internet, questo sito non detiene il diritto di proprietà, non è stato editato manualmente e non assume responsabilità legali correlate. Se trovi contenuti sospetti di violazione del copyright, ti preghiamo di inviare una e-mail a: notice#oldtoolbag.com (al momento dell'invio dell'e-mail, sostituisci # con @) per segnalare il problema e fornire prove pertinenti. Una volta verificata, questo sito rimuoverà immediatamente i contenuti sospetti di violazione del copyright.

Ti potrebbe interessare