English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Эта статья рассказывает о примере паттерна наблюдателя в Android-программировании. Предлагается для вашего рассмотрения, подробности см. ниже:
Один: Введение
Паттерн наблюдателя является очень часто используемым паттерном, он наиболее часто используется в системах графического интерфейса пользователя (GUI), системах подписки-публикации. Одна из важнейших ролей этого паттерна - декомпозиция, декомпозиция наблюдателя и наблюдателя, чтобы уменьшить их зависимость, даже до полного отсутствия зависимости. В случае системы GUI UI приложения подвержены изменениям, особенно в начале, когда изменения бизнеса или требований продукта вносят изменения в интерфейс приложения, но логика бизнеса в основном не изменяется. В этом случае GUI системы требуют механизма для应对 этой ситуации, чтобы разорвать связь между UI и конкретной логикой бизнеса, и в этом случае паттерн наблюдателя приходит на помощь.
Два: Определение
Определение одного типа зависимости между объектами, при котором при изменении состояния одного объекта все объекты, зависящие от него, получают уведомление и автоматически обновляются.
Три: Сцены использования
Сцены связанного поведения, необходимо отметить, что связанное поведение можно разделить, а не является отношением «композиции».
Сцены многоуровневого триггирования событий.
Сцены обмена сообщениями между системами, такими как обработка механизмов очередей сообщений и总线 событий.
Четыре: Классовая диаграмма UML паттерна наблюдателя
UML классовая диаграмма:
Объяснение ролей:
Subject: Абстрактная тема, то есть роль наблюдателя (Observable), роль абстрактной темы сохраняет ссылки на все объекты наблюдателей в собрании, каждый темы может иметь любое количество наблюдателей. Абстрактная тема предоставляет интерфейс для добавления и удаления объектов наблюдателей.
ConcreteSubject: Конкретная тема, данная роль сохраняет соответствующие состояния в объект наблюдателя, и когда внутреннее состояние конкретной темы изменяется, она отправляет уведомления всем зарегистрированным наблюдателям. Роль конкретной темы также известна как роль конкретного наблюдателя (ConcreteObservable).
Observer: абстрактный наблюдатель, который является абстрактным классом наблюдателя и определяет интерфейс обновления, чтобы обновлять себя при получении уведомлений о изменениях темы.
ConcreteObserver: конкретный наблюдатель, который реализует интерфейс обновления абстрактного наблюдателя, чтобы обновить自身的 состояние при изменении состояния темы.
Пять, простая реализация
Вот пример, когда вы хотите не пропустить новые серии сериала, вы подписываетесь или следите за этим сериалом, и как только сериал обновляется, вам сразу же推送 уведомление. Давайте просто реализуем это.
Абстрактный класс наблюдателя:
/** * Абстрактный класс наблюдателя, определяющий интерфейс для всех конкретных наблюдателей, обновляющих себя при получении уведомлений */ public interface Observer { /** * Есть обновление * * @param message Сообщение */ public void update(String message); }
Абстрактный класс наблюдаемого:
/** * Абстрактный класс наблюдаемого */ public interface Observable { /** * Пр push messages * * @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); } }
Реализация:
public class Client { public static void main(String[] args) { //наблюдаемый, здесь это сериал, на который подписались пользователи Teleplay teleplay = new Teleplay(); //наблюдатель, здесь это подписчик User user1 = new User("Сяо Минг"); User user2 = new User("Сяо Гуан"); User user3 = new User("Сяо Лань"); //подписка teleplay.register(user1); teleplay.register(user2); teleplay.register(user3); //пуш новостей teleplay.push("xxx сериал"); } }
Результат:
Сяо Минг, обновился xxx сериал! Сяо Гуан, обновился xxx сериал! Сяо Лань, обновился xxx сериал!
Из上面的 кода可以看出, был реализован режим推送 сообщений один ко многим,推送的消息 зависят от абстрактных классов Observer и Observable, а User и Teleplay完全没有耦合, что гарантирует гибкость и расширяемость системы подписки.
Шестой раздел: паттерн наблюдателя в исходном коде Android
1. BaseAdapter
BaseAdapter, я уверен, все знакомы с ним, в адаптерах ListView мы наследуем от него. Давайте разберем это简要.
Часть кода BaseAdapter:
public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter { //наблюдатель данных private final DataSetObservable mDataSetObservable = new DataSetObservable(); public boolean hasStableIds() { возвращать false; } public void registerDataSetObserver(DataSetObserver observer) { mDataSetObservable.registerObserver(observer); } public void unregisterDataSetObserver(DataSetObserver observer) { mDataSetObservable.unregisterObserver(observer); } /** * когда набор данных изменяется, уведомить всех наблюдателей */ public void notifyDataSetChanged() { mDataSetObservable.notifyChanged(); } }
Посмотрите на метод mDataSetObservable.notifyChanged():
public class DataSetObservable extends Observable<DataSetObserver> { /** * Вызывает {@link DataSetObserver#onChanged} для каждого наблюдателя. * Вызывается когда содержимое набора данных изменилось. Получатель * будет получать новые данные в следующий раз, когда оно запросит набор данных. */ public void notifyChanged() { synchronized(mObservers) { // так как onChanged() реализуется приложением, оно может делать что угодно, включая // удаление себя из {@link mObservers} - и это может вызвать проблемы, если // используется итератор на ArrayList {@link mObservers}. // чтобы избежать таких проблем, просто пройдите список в обратном порядке. 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 определен в родительском классе AbsListView класса ListView, это наблюдатель набора данных, код:
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(); } } }
Он состоит из класса AdapterDataSetObserver, наследующегося от класса AdapterView, inheriting from the class AdapterView, который наследует AbsListView, код如下 :
class AdapterDataSetObserver extends DataSetObserver { private Parcelable mInstanceState = null; // Как было сказано ранее, при вызове метода notifyDataSetChanged адаптера вызывается метод onChanged всех наблюдателей, ключевое реализация находится здесь @Override public void onChanged() { mDataChanged = true; mOldItemCount = mItemCount; // Получение количества данных в Adapter mItemCount = getAdapter().getCount(); // Обнаружить случай, когда курсор, который был ранее аннулирован, // был перезаполнен новыми данными. if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null && mOldItemCount == 0 && mItemCount > 0) { AdapterView.this.onRestoreInstanceState(mInstanceState); mInstanceState = null; } rememberSyncState(); } checkFocus(); // перерасположение компонентAdapterView, таких как ListView, GridView и т.д. requestLayout(); } // Код пропущен public void clearSavedState() { mInstanceState = null; } }
Когда данные ListView изменяются, вызывается функция notifyDataSetChanged адаптера, которая, в свою очередь, вызывает функцию notifyChanged DataSetObservable, которая вызывает метод onChanged всех наблюдателей (AdapterDataSetObserver). Это и есть модель наблюдателя!
Седьмой раздел: Заключение
Преимущества:
Между наблюдателем и наблюдаемым существует абстрактная耦合ировка, которая реагирует на изменения в бизнесе.
Улучшение гибкости и расширяемости системы.
Недостатки:
При использовании модели наблюдателя необходимо учитывать вопросы эффективности разработки и выполнения. В программе включен наблюдатель, несколько наблюдателей, разработка и отладка могут быть сложными, и в Java уведомления сообщений обычно выполняются в порядке, поэтому, если наблюдатель застрял, это может повлиять на общую эффективность выполнения. В таких случаях обычно используется асинхронное выполнение.
Читатели, интересующиеся дополнительной информацией о Android, могут ознакомиться с нашими专题ами: «Введение в разработку Android и продвинутые уроки», «Советы по отладке Android и ответы на часто встречающиеся вопросы», «Обзор использования основных компонентов Android», «Обзор навыков работы с Android View View», «Обзор навыков работы с Android layout layout» и «Обзор использования Android View Control»
Надеюсь, что изложенное в этой статье поможет вам в разработке Android-приложений.
Заявление: содержимое статьи взято из Интернета, авторские права принадлежат соответствующему автору, материал был自发но предоставлен пользователями Интернета, сайт не обладает правами собственности, материал не был отредактирован вручную, и сайт не несет ответственности за связанные с этим юридические вопросы. Если вы обнаружите спорное содержимое, пожалуйста, отправьте письмо по адресу: notice#oldtoolbag.com (во время отправки письма замените # на @) для сообщения о нарушении авторских прав,并提供 соответствующие доказательства. В случае подтверждения факта нарушения авторских прав сайт незамедлительно удалят спорное содержимое.