English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Este artigo descreve um exemplo de padrão de design de programação Observer no Android. Compartilho com vocês para referência, conforme a seguir:
Primeiro: Introdução
O padrão Observer é altamente utilizado, mais comumente utilizado em sistemas GUI, sistemas de inscrição-publicação. Este padrão tem uma função importante de desacoplamento, desacoplando o observável e o observador, tornando a dependência entre eles menor, até mesmo completamente independente. Em termos de sistemas GUI, a UI da aplicação é altamente volátil, especialmente no início, com a mudança do negócio ou a modificação das necessidades do produto, a interface da aplicação também muda frequentemente, mas a lógica de negócios basicamente não muda muito, neste caso, o sistema GUI precisa de um mecanismo para lidar com essa situação, desacoplando a camada UI da lógica de negócios específica, e o padrão Observer entra em ação neste momento.
Segundo: Definição
Define um tipo de dependência de muitos para um entre objetos, de modo que sempre que um objeto muda de estado, todos os objetos que dependem dele serão notificados e atualizados automaticamente.
Terceiro: Cenários de uso
Cenários de comportamento associado, é necessário notar que o comportamento associado é divisível, não é uma relação de "composição".
Cenários de gatilho de eventos de múltiplas etapas.
Cenários de troca de mensagens entre sistemas cruzados, como o mecanismo de processamento de filas de mensagens e buses de eventos.
Quarto: Diagrama de classe do padrão Observer
Diagrama de classe UML:
Introdução ao papel:
Tema abstrato: também conhecido como papel observável (Observable), o papel do tema abstrato armazena as referências de todos os objetos observadores em um agrupamento, cada tema pode ter qualquer número de observadores. O tema abstrato fornece uma interface para adicionar e excluir objetos observadores.
ConcreteSubject: Tema específico, esse papel armazena o estado em objetos de observador específicos, notifica todos os observadores registrados quando o estado do tema específico muda, o papel de tema específico também é chamado de papel de observador específico (ConcreteObservable).
Observer: Observador abstrato, esse papel é a classe abstrata do observador, define um interface de atualização, para que o próprio seja atualizado quando receber notificações do tema.
ConcreteObserver: Observador específico, esse papel implementa o interface de observador abstrato definido pelo papel de tema, para que o estado próprio seja atualizado quando o estado do tema mudar.
V, Implementação simples
Vamos dar um exemplo de assistir a séries, geralmente para não perder os novos dramas, nos inscrevemos ou nos inscrevemos nessa série. Quando a série for atualizada, ela será enviada para nós imediatamente. Vamos implementar de maneira simples.
Classe abstrata do observador:
/** * Classe abstrata do observador, define uma interface para todos os observadores específicos, atualiza-se quando recebe notificações */ public interface Observer { /** * Há atualizações * * @param message Mensagem */ public void update(String message); }
Classe abstrata do observador:
/** * Classe abstrata do observador */ public interface Observable { /** * Push de mensagens * * @param message Conteúdo */ void push(String message); /** * Assinar * * @param observer Assinante */ void register(Observer observer); }
Classe específica do observador:
/** * Classe específica do observador, também conhecida como assinante */ public class User implements Observer { @Override public void update(String message) { System.out.println(name + ", + message + "Atualizado!"); } // Nome do assinante private String name; public User(String name) { this.name = name; } }
Classe específica do observador:
/** * Classe específica do observador, também conhecida como programa suscrito */ public class Teleplay implements Observable{ private List<Observer> list = new ArrayList<Observer>();//Armazenar assinantes @Override public void push(String message) { for(Observer observer:list){ observer.update(message); } } @Override public void register(Observer observer) { list.add(observer); } }
Implementação:
public class Client { public static void main(String[] args) { //Observado, aqui é o drama assinado pelo usuário Teleplay teleplay = new Teleplay(); //Observador, aqui é o usuário de assinatura User user1 = new User("Xiaoming"); User user2 = new User("Xiaoguang"); User user3 = new User("Xiaolan"); //Assinar teleplay.register(user1); teleplay.register(user2); teleplay.register(user3); //Enviar nova mensagem teleplay.push("xxx drama"); } }
Resultados:
Xiaoming, o episódio xxx do drama foi atualizado! Xiaoguang, o episódio xxx do drama foi atualizado! Xiaolan, o episódio xxx do drama foi atualizado!
Do código acima, podemos ver que foi implementado um modelo de mensagem de um para muitos, as mensagens enviadas dependem de classes abstratas como Observer e Observable, enquanto User e Teleplay não têm dependência entre si, garantindo a flexibilidade e escalabilidade do sistema de assinatura.
Seis, padrão Observer no código-fonte do Android
1、BaseAdapter
BaseAdapter, acho que todos estão familiarizados com ele, na ListView adapter herdamos dela. Vamos analisar simplesmente.
Código parte do BaseAdapter:
public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter { //Observador de conjunto de dados 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 o conjunto de dados muda, notificar todos os observadores */ public void notifyDataSetChanged() { mDataSetObservable.notifyChanged(); } }
Vamos olhar para o método mDataSetObservable.notifyChanged():
public class DataSetObservable extends Observable<DataSetObserver> { /** * Invoca {@link DataSetObserver#onChanged} em cada observador. * Chamado quando o conteúdo do conjunto de dados muda. O destinatário * obterá os novos conteúdos na próxima vez que consultar o conjunto de dados. */ public void notifyChanged() { synchronized(mObservers) { // since onChanged() é implementado pelo aplicativo, ele pode fazer qualquer coisa, incluindo // remover-se da {@link mObservers} - isso poderia causar problemas se // um iterador é usado na ArrayList {@link mObservers}. // para evitar tais problemas, simplesmente passe pela lista na ordem inversa. for (int i = mObservers.size() - 1; i >= 0; i--) { mObservers.get(i).onChanged(); } } } }
Pode-se ver que em mDataSetObservable.notifyChanged() é percorrido todos os observadores e chamado seus onChanged(), informando os observadores do que aconteceu.
Então como o observador surge, é o método setAdapter, código如下:
@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 atualizará os estados de modo de escolha. super.setAdapter(adapter); if (mAdapter != null) { mAreAllItemsSelectable = mAdapter.areAllItemsEnabled(); mOldItemCount = mItemCount; mItemCount = mAdapter.getCount(); checkFocus(); mDataSetObserver = new AdapterDataSetObserver(); mAdapter.registerDataSetObserver(mDataSetObserver);//Registrar observador ...... omitido } }
AdapterDataSetObserver está definido na classe pai AbsListView de ListView, é um observador de conjunto de dados, código:
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(); } } }
É derivado do AdapterDataSetObserver da classe pai AdapterView, que herda AbsListView, o código é o seguinte:
class AdapterDataSetObserver extends DataSetObserver { private Parcelable mInstanceState = null; // Como mencionado anteriormente, ao chamar o método notifyDataSetChanged do Adapter, ele chama o método onChanged de todos os observadores, a implementação central está aqui @Override public void onChanged() { mDataChanged = true; mOldItemCount = mItemCount; // Obter o número de dados no Adapter mItemCount = getAdapter().getCount(); // Detectar o caso em que um cursor que foi anteriormente invalidado // foi re-populado com novos dados. if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null && mOldItemCount == 0 && mItemCount > 0) { AdapterView.this.onRestoreInstanceState(mInstanceState); mInstanceState = null; } rememberSyncState(); } checkFocus(); // Reestruturar os componentes AdapterView como ListView, GridView e outros requestLayout(); } // Código omitido public void clearSavedState() { mInstanceState = null; } }
Quando os dados do ListView mudam, é chamada a função notifyDataSetChanged do Adapter, que, por sua vez, chama a função notifyChanged do DataSetObservable, que chama o método onChanged de todos os observadores (AdapterDataSetObserver). Isso é um padrão Observer!
Sete, Resumo
Vantagens:
A dependência entre o observador e o observado é abstrata, facilitando a adaptação às mudanças de negócios.
Aumenta a flexibilidade e a expansibilidade do sistema.
Desvantagens:
Ao usar o padrão Observer, é necessário considerar questões de eficiência de desenvolvimento e execução. No programa, há um observador e vários observados, o desenvolvimento e a depuração são relativamente complexos, e na Java, a notificação de mensagens geralmente é executada em ordem. Portanto, se um observador estiver lento, isso afetará a eficiência geral da execução. Nesse caso, geralmente é adotada uma implementação assíncrona.
Leitores interessados em mais conteúdo sobre Android podem consultar as seções especiais deste site: 'Introdução e Aperfeiçoamento em Desenvolvimento de Android', 'Dicas de Debug e Solução de Problemas Comuns em Android', 'Sumário de Uso dos Componentes Básicos de Android', 'Sumário de Dicas de View de Android', 'Sumário de Dicas de Layout de Android' e 'Sumário de Uso dos Controles de Android'
Espero que o conteúdo deste artigo ajude a todos a programar em Android.
Declaração: O conteúdo deste artigo é de origem na internet, pertencente ao respectivo detentor dos direitos autorais, contribuído e carregado voluntariamente pelos usuários da internet. Este site não possui direitos de propriedade, não foi editado manualmente e não assume responsabilidade por eventuais responsabilidades legais. Se você encontrar conteúdo suspeito de violação de direitos autorais, seja bem-vindo a enviar e-mail para: notice#oldtoolbag.com (ao enviar e-mail, substitua # por @ para denunciar e forneça provas relevantes. Se confirmado, o site deletará imediatamente o conteúdo suspeito de violação de direitos autorais.)