Flex/AS3 – Singleton+EventDispatcher = Application Auto-Refresh

Flex/AS3 – Singleton+EventDispatcher = Application Auto-Refresh

Bem, este post vai ser um bocado extenso, mas tenho a certeza que vai ser muito util como me foi a mim. Um dos problemas que tinha na minha aplicação (CRM) que usa apenas PopUp Windows (TitleWindow) era fazer um refresh à listagem de clientes sempre que um cliente novo fosse adicionado. Isto também se aplicava aos produtos, fornecedores e mais…

Coloquem o seguinte caso:

Um utilizador do CRM têm que fazer um orçamento a um cliente, logo abre o menu “Orçamentos” e escolhe “Novo”. Cria o seu orçamento e só depois é que vai inserir o cliente atravez do seu código, ou atravez de uma caixa de procura ( “Procura Clientes” ) que vai listar todos os clientes, então vê nessa janela “Procura Clientes” que o cliente não existe na base de dados. Decide então ir ao menu “Clientes” e selecionar “Novo”, preenche as devidas informações e clica em guardar… o cliente é adicionado, ele fecha a janela e percorre a janela aberta “Procura Clientes” e o cliente que ele acaba de inserir não se encontra na lista. Este era o problema.

1. O Problema – Porquê que isto acontece?
Simples, como a janela que lista os clientes estava aberta antes do novo cliente ser adicionado, ela apenas listou os clientes existentes na altura da sua abertura.

2. Soluções:
2.1. Criar um timer para refrescar a chamada ao backend, altamente desaconselhavel, visto que ciclicamente seriam feitas chamadas remotas o que aumentaria em muito os gastos de memória e mesmo assim o timer teria sempre um intervalo que poderia não coincidir com o adicionar do novo cliente.
2.2. Ao adicionar um novo cliente, verificar se a janela de clientes está aberta e se estiver criar uma função para fazer o refesh e buscar os dados mais recentes do backend, mais lógica mas no entanto confusa porque teriamos andar a verificar e controlar todos os estados do popup, e se for neecssário informar mais de que uma janela desta actualização teriamos o dobro do trabalho.

Mas então como solucionar? Também pensei bastante nisso e até pedi uma dica ao Fabio Vedovelli e ele também me propos a mesma dica do 2.2. mas eu queria uma solução mais prática e então lembrei-me das classes singleton. Se pensar-mos bem um class singleton como usa sempre a mesma instancia ela é sempre a mesma onde quer que seja usada certo? Comentei com o Ved que talvez fosse possivel propagar um evento interno pela class singleton e escutar esse evento em qualquer lado da aplicação desde que escutasse esse evento… e nada como testar… decidi começar a fazer uma implementação de uma classe singleton que fizesse isto… eis a solução:

2.3. Usar uma class singleton para propagar um evento para varios “alvos” informado esses alvos de determinada acção. Neste caso informando que foi adicionado um novo cliente.


A classe:
[coolcode] package com.config
{
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;

public class UpdateController extends EventDispatcher
{

private static var instance:UpdateController;
private static var allowInstantiation:Boolean;

public static function getInstance():UpdateController {
if (instance == null) {
allowInstantiation = true;
instance = new UpdateController();
allowInstantiation = false;
}
return instance;
}

public function UpdateController(target:IEventDispatcher=null):void {
super(target);
if (!allowInstantiation) {
throw new Error(“Error: Nova instancia impossivel, Use UpdateController.getInstance() para usar a mesma instancia.”);
}

}

}
}
[/coolcode] Como podem ver, trata-se de uma class simples do package com.config com o nome de UpdateController, esta class vai ser chamada quer na TitleWindow “Adiciona Cliente” e que na TitleWindow “Procura Clientes”, sendo que vai ser disparado um evento na na class a partir da “Adiciona Cliente” e este será escutado na “Procura Clientes”.

Na minha TitleWindow “Adiciona Cliente” eu tenho uma função que recebe a resposta do meu RemoteObject, e no caso do cliente ter sido inserido com sucesso:
[coolcode] import com.config.UpdateController;

private var updateManager:UpdateController = UpdateController.getInstance();

private function insereCliente(resultado:ResultEvent):void {
if(resultado.result.inserido==true) updateManager.dispatchEvent(new Event(“clienteInserido”));
}
[/coolcode] Neste momento, quando for recebida uma resposta da inserção de um novo cliente é disparado um evento “clienteInserido” na class singleton que nos vai permitir que na janela “Procura Clientes” tenhamos um listener à espera deste evento, para isso nessa janela basta escrever numa função que seja executado logo no creationComplete, por exemplo init:

[coolcode] import com.config.UpdateController;

private var updateManager:UpdateController = UpdateController.getInstance();

private function init():void{
updateManager.addEventListener(“clienteInserido”, novoClienteInserido);
}

//e criar o seu handler:

private function novoClienteInserido(evt:Event):void {
//aqui coloco uma nova chamada ao meu remoteObject para actualizar os clientes:
meuRO.buscaClientes();
}
[/coolcode] A partir deste momento, se ambas as janelas estiverem abertas, ao adicionar um novo cliente, a listagem de clientes na janela “Procura Clientes” será actualizada…

Simples, rápido e eficaz…

Como devem imaginar, este tipo de eventos e classes pode até ser usado para informar 50 janelas que foi adicionado um cliente, isto a partir de apenas 5/6 linhas de código… e se quiserem mesmo extender ainda mais esta class, poderão até passar o novo cliente por ela e adicionar á listagem de clientes sem ter que chamar o remoteObject buscaClientes();

Espero que vos seja util.

Abraço.


11 comments

add yours
  • Carlos Gustavo April 28, 2009

    Excelente! Eu semprei usei instâncias comuns de eventos em objetos estáticos ou em singleton, mas nunca parei pra fazer o EventDispatcher direto. Valeu a dica.

  • Tony April 28, 2009

    E eu aqui me matando fazendo com solução 2.2 até hoje.
    Muito util. Valeu!

  • Chucky April 28, 2009

    Quando comecei a ler o post o que me passou pela cabeça foi mesmo “ora mas entao nao seria mais facil emitir um evento e depois no popup receber esse evento e actualizar os dados?” e foi realmente isso que fez :) secalhar ia ter problemas com a minha soluçao pois talvez o evento nao chegasse ao popup mas com o bubbles nao dava?(certamente ja estou a divagar!)

    Obrigado por partilhar a soluçao, sem duvida é uma grande ajuda e uma optima dica!

  • RIVALDO XAVIER June 8, 2009

    Exelente post, ajudou em um dilema (qual a melhor solução para refresh)…

  • Vagner Machado August 3, 2009

    E se por acaso 2 usuários em máquinas diferentes. Quando um está com a janela de busca aberta e outro em outra máquina realiza o cadastro. Então apenas a máquina no qual o cadastro foi realizado seria realmente consistente com os dados. Enquanto a outra máquina estaria com os dados desatualizados.
    Teria alguma solução que pudesse perceber qualquer alteração realizada no banco pelo back-end e transmitisse uma mensagem ao front-end para ser atualizada as listas.

  • Vagner Machado August 3, 2009

    A solução que eu uso hoje em dia é um ArrayCollectin Bindable.
    E a cada ResultEvent em cadastro ou atualização o método de atualizar listas é chamado.

    Controle fica assim:

    [Bindable]
    public var usuarios:ArrayCollection;

    […]

    private function cadastrarUsuarioResult(event:ResultEvent):void
    {
    Alerta.info(“Usuário cadastrado com sucesso!”);
    consultarUsuarios();
    }

    private function consultarUsuariosResult(event:ResultEvent):void
    {
    usuarios=event.result as ArrayCollection;
    }

  • Jamilso October 14, 2009

    era só usar o Cairngorm que nao tinha problema.

  • Bruno November 21, 2009

    Não entendi o uso da propriedade allowInstantiation

    Para que ela serve na verdade? Porque daquele método updateControler?

  • Lincoln November 24, 2009

    2.4

    use MVC (pureMVC, cairngorm, etc)

  • Rafael January 28, 2010

    Olá pessoal!
    eu estou tendo um problema, fiz uma implementação que nem está no artigo mas, tenho já pelo menos 10 eventos custmizados, os primeiros que eu criei funcionam mas, os último não, parece que os dispacher não são chamados e não gera erro na hora de compilar.
    Será que eu fiz algo de errado?

  • Márcio January 24, 2011

    Pessoal, sou iniciante no Flex, e sobre este caso tenho uma dúvida:

    Se eu criar um evento customizado e criar um listener na tela de inclusão na tela de orçamento. Quando eu for fazer a inclusão do cliente, dispacho esse evento que irá se propagar para a tela de inclusão de orçamentos. Também seria para funcionar, não é?

    Obrigado,
    Márcio Ozório

Leave a Comment

Post