• Aucun résultat trouvé

Rayonnement dipolaire électrique dans la zone de rayonnement 4

Dans le document Rayonnement dipolaire électrique (Page 4-8)

Durante o processo de implementação do projeto viu-se que o diagrama de classes previamente planejado para o projeto não iria comportar toda a implementação necessária. Em vista disso surgiu a necessidade de adotar uma arquitetura para melhor organizar o código, deixando-o mais limpo e de mais fácil manutenção. Para tal decisão, escolheu-se o padrão de projeto MVVM. Dessa forma, o antigo diagrama de classes proposto não foi mais utilizado e fez-se a implementação seguindo o padrão, conseguindo-se uma separação de responsabilidades mais clara para o que cada classe faz. Como resultado, ao término do projeto o App-Coleta acabou possuindo 35 classes, ao invés das sete que foram planejadas, e o App- Busca contou com 18 classes, ao invés das seis que foram inicialmente planejadas.

5.1 Diagrama de pacotes

Para uma melhor explicação da implementação da proposta, ao invés de exibir o diagrama de classes, decidiu-se utilizar o diagrama de pacotes. Segundo Ambler (2003), um diagrama de pacotes tem o propósito de descrever os pacotes ou partes de um sistema divididos em agrupamentos lógicos, descrevendo a dependência entre eles. Com isso, consegue-se descrever uma visão geral de alto nível dos requisitos e do design, modularizar logicamente um diagrama complexo e organizar o código fonte.

5.2 Biblioteca Common

Ao longo do desenvolvimento do projeto notou-se que várias partes de código estavam se repetindo nos aplicativos App-Coleta e App-Busca. Com isso, surgiu a ideia de criar uma biblioteca chamada Common, para que o reuso deste código conseguisse ser feito entre os aplicativos. Várias classes foram migradas para a biblioteca, que foi organizada conforme mostrado no diagrama de pacotes da Figura 22.

Figura 22. Diagrama de pacotes para a biblioteca Common.

Fonte: Autor.

5.2.1 Pacotes app e common

Todo aplicativo ou biblioteca no Android possui um identificador único que serve para distinguir o próprio tanto no dispositivo instalado quanto na loja Google Play Store. Quando o projeto de um aplicativo/biblioteca é criado(a), deve-se fornecer um applicationId (identificador da aplicação), que normalmente se encontra no formato

com.exemplo.aplicativo, devendo ter pelo menos dois segmentos, com um ou mais pontos,

sendo que cada segmento deve começar com uma letra e todos os caracteres devem ser alfanuméricos ou sublinhados. Por esse motivo, após a criação do projeto serão gerados pacotes padrões em estilo Java que correspondem exatamente ao applicationId fornecido (ANDROID, 2019h). Como a biblioteca possui o identificador único sendo app.common, os pacotes app e

common são os pacotes gerados automaticamente. Ambos os pacotes app e common não

possuem nenhuma classe, apenas comportam outros pacotes que serão discutidos a seguir.

5.2.2 Pacote view_model

O pacote view_model possui apenas a classe ViewModelFactory. Essa classe implementa ViewModelProvider.Factory e é utilizada na criação de instâncias da classe

ViewModel.

Possui as classes Constants, Logging e TestUtils. A classe Constants fornece constantes, ou seja, dados que não são alterados durante a execução do programa. Um exemplo de constante seria a referência ou o nome do banco de dados Firebase.

A classe Logging possui métodos úteis para efetuar logs em vários modos, como erro, informação e advertência, permitindo passar objetos e exibir a informação destes a partir do método toString(). Ao contrário dos recursos de log nativamente fornecidos pelo framework Android, como Log.i() e Log.e(), entre outros, a classe Logging não limita o número de objetos passados no parâmetro de uma vez só, assim como o tipo de objeto que pode ser logado.

A classe TestUtils, por sua vez, provê métodos que são utilizados nos testes das aplicações. Um deles, por exemplo, é gerar uma fixture, uma instância com um estado pré- definido da classe ParkingLot.

5.2.4 Pacote firebase_models

Esse pacote contém as classes responsáveis por definir a estrutura do modelo do banco de dados do Firebase. São elas: ParkingLot, Prices e WorkingDay, as quais são classes de dados pois possuem o modificador data. Quando o modificador data é usado em uma classe, esta passa a ter como objetivo principal armazenar e fornecer métodos de acesso para ler e gravar dados, além de possuir funcionalidades padrão e funções utilitárias derivadas automaticamente dos dados, como equals(), hashCode(), toString(), copy() e componentN() (KOTLIN, 2019a).

A Figura 23 demonstra o diagrama de classes para o modelo de dados. Pode-se notar que a classe ParkingLot representa o nodo central do esquema do modelo de dados, enquanto as classes Prices e WorkingDay são agregações da classe ParkingLot, caracterizando nodos folha (Figura 20).

Figura 23. Diagrama de classes representando o modelo do banco de dados do Firebase.

Fonte: Autor.

5.2.5 Pacote network

Possui a classe NetworkUtil e a interface InternetStatusListener. A classe

NetworkUtil se encarrega de registrar receptores de transmissão para receber eventos

referentes ao estado da conexão com a internet. Juntamente com a classe NetworkUtil é utilizada a interface InternetStatusListener, que possui as assinaturas de método onNetworkDisconnected e onNetworkConnected.

5.2.6 Pacote receivers

Este pacote contém unicamente a classe InternetStatusReceiver. As instâncias dessa classe são utilizadas em conjunto com a classe NetworkUtil e corresponde a um receptor de transmissão, específico para receber eventos de mudança de conexão com a Internet.

5.3 App-Coleta

Para facilitar a compreensão de como o App-Coleta foi desenvolvido, novamente será utilizado o diagrama de pacotes, focando principalmente na interação das camadas do padrão de projetos MVVM (Figura 24).

Figura 24. Diagrama de pacotes para o App-Coleta.

5.3.1 Pacotes app e coleta

Assim como para a biblioteca Common, os pacotes app e coleta são gerados automaticamente. Ambos os pacotes não possuem nenhuma classe e apenas comportam outros pacotes que serão discutidos a seguir.

5.3.2 Pacote application

O pacote application contém a classe AppColetaApplication e serve para manter o estado global do aplicativo. No caso do App-Coleta, a classe AppColetaApplication possui um companion object, que é um objeto comum a todas as instâncias dessa classe e se assemelha aos campos estáticos do Java (KOTLIN, 2019b). A partir de um companion object, outras classes podem chamar os métodos definidos em uma classe sem a necessidade de criar uma instância da mesma. Quando uma classe estende a classe Application do framework Android, esta é instanciada antes de qualquer outra, quando o processo do aplicativo é criado, podendo assim iniciar variáveis globais (ANDROID, 2019i). No caso da classe AppColetaApplication, há somente uma variável global, que é uma instância da classe Context. Context é uma interface com informações globais sobre o ambiente do aplicativo e permite o acesso a recursos e classes específicas do framework Android, bem como o início de atividades (Activities) e transmissão e recebimento de intenções (Intents). Ter essa variável global da classe Context acaba sendo muito útil em casos onde não é possível se ter acesso ao contexto da aplicação. Adicionalmente, nessa classe acontece a inicialização da instância global do Firebase, que contém todas as informações da coleção de serviços utilizados no App-Coleta.

5.3.3 Pacote repository

O App-Coleta utiliza o padrão de projetos repository. Segundo Fowler (2002), esse padrão tem o propósito de encapsular um conjunto de objetos persistidos em um armazenamento de dados e as operações executadas sobre eles, fornecendo uma visão mais orientada a objetos da camada de persistência. Ao se utilizar um repositório têm-se os benefícios de uma separação limpa e dependência unidirecional entre o domínio e as camadas de mapeamento de dados. Com esse propósito, decidiu-se utilizar o padrão de projetos repository

como uma forma de: primeiro, abstrair a camada de dados, com o aplicativo acessando a camada de dados sem se preocupar se a implementação é direcionada a um banco de dados local ou a uma API online; segundo, é uma maneira de centralizar o manuseio dos objetos de domínio.

Assim, o pacote repository orquestra e organiza o acesso aos dados. Este pacote possui outros dois pacotes, database e settings, bem como a classe Repository e a interface

ParkingLotListener.

O pacote database, como o nome já indica, contém as classes e interfaces relacionadas ao acesso ao banco de dados da aplicação. Contém a classe Database e a interface

DatabaseListener.

A classe Database possui a finalidade de acessar, modificar e observar mudanças de dados do Firebase. Ela implementa a interface ValueEventListener, que pertence à API do Firebase, e serve para observar mudanças em um nodo específico da árvore do banco de dados. Quando uma instância da classe Database é criada, ela acessa dois nodos, ou referências do modelo de dados do Firebase. O primeiro acesso são os dados do estacionamento (a classe

ParkingLot), a partir da URI (Uniform Resource Identifier, Identificador de Recurso

Uniforme, traduzido do Inglês) https://tcc-parking-db.firebaseio.com/tcc-parking-

db/parking_lots/<id_estacionamento>. Para esse nodo é configurado um listener utilizando

a interface ValueEventListener. O segundo são os dados de coordenadas de localização geográfica, acessados pela URI https://tcc-parking-db.firebaseio.com/tcc-parking-

db/parking_lot_ids/<id_estacionamento>. Para esse nodo, não é configurado um ValueEventListener pois quando se alteram as configurações de coordenadas, essas já são

salvas juntamente com os dados do estacionamento, sendo replicadas automaticamente. Quando qualquer mudança referente ao estacionamento é acionada no dispositivo (configurações ou mudança do estado das vagas), ela é enviada ao Firebase por meio da classe

Database. Adicionalmente, quando uma mudança ocorre no Firebase, essa é replicada e

propagada localmente do dispositivo. Esse último caso pode acontecer quando se possui dois ou mais dispositivos autenticados com uma mesma conta. Se um dispositivo faz a mudança do número de vagas livres, por exemplo, todos os outros dispositivos com a mesma conta irão receber essa mudança instantaneamente.

A interface DatabaseListener é utilizada no repositório do projeto, e define a assinatura de métodos que serão utilizados ao se receber uma atualização do Firebase. Ela

contém apenas um método chamado onDataReceived e possui como parâmetro uma instância da classe ParkingLot.

Já o pacote settings compreende as classes ApplicationSettings e SettingsHolder, responsáveis por gerenciar e armazenar as configurações locais do aplicativo. A classe

ApplicationSettings é uma classe do tipo enum, e contém campos que consistem em um

conjunto fixo de constantes, cada um definindo uma configuração específica. Esses campos são SERVER_IP, SERVER_PORT, SERVER_TOKEN e SERVER_ENABLED, todos pertencentes às configurações do servidor local. A classe ApplicationSettings possui um

companion object, facilitando a chamada dos métodos definidos na classe ApplicationSettings. As configurações são salvas em disco a partir do uso de

SharedPreferences (preferências de usuário). Um objeto SharedPreferences manipula um arquivo que contém pares de chave-valor e fornece métodos simples para lê-los e gravá-los. Cada arquivo pertencente ao SharedPreferences é gerenciado pelo framework Android e pode ser privado ou compartilhado (ANDROID, 2019j). A implementação do uso das preferências de usuário fica a cargo da classe SettingsHolder, onde estão declarados os métodos para ler e gravar as configurações. Essas configurações acontecem em modo privado, ou seja, o arquivo de chave-valor pode ser acessado apenas pelo aplicativo que criou o arquivo.

A classe Repository se encarrega da implementação do padrão de projetos repository comentado anteriormente. Ela contém o acesso ao banco de dados Firebase (classe Database) e as configurações/preferências de usuário (classe ApplicationSettings). Para receber atualizações provenientes da classe Database, a classe Repository implementa a interface

DatabaseListener.

As instâncias que fazem o uso de Repository, implementam a interface

ParkingLotListener, possuindo a assinatura de apenas um método, onParkingLotUpdated,

que também possui como parâmetro uma instância da classe ParkingLot.

5.3.4 Pacote server

Esse pacote possui as classes CustomNanoHTTPD e a interface

ParkingSpotListener.

A classe CustomNanoHTTPD possui o papel de criar um servidor local no dispositivo a fim de receber requisições HTTP exteriores para o update de vagas do

estacionamento. A classe CustomNanoHTTPD estende a classe NanoHTTPD, que pertence à biblioteca NanoHTTPD, um servidor HTTP projetado para incorporação em outros aplicativos.

Os seguintes parâmetros são passados no construtor:

a) Endereço IP e porta: utilizados para configurar o servidor do projeto App-Coleta; b) Token: código único utilizado para verificar se as requisições recebidas são válidas. O

uso de token é opcional. Quando utilizado, todas as requisições devem conter no corpo da mensagem o mesmo valor do token configurado, assim, validando a requisição. c) Instância de ParkingSpotListener: um ouvinte que propaga intenções válidas de

mudanças do número de estacionamento.

A classe CustomNanoHTTPD pode receber requisições em duas URLs: a) “http://<ip>:<porta>/vagaLivre”: URL usada para adicionar uma vaga livre;

b) “http://<ip>:<porta>/vagaOcupada”: URL usada para adicionar uma vaga ocupada.

Uma requisição ao ser recebida no endereço http://<ip>:<porta>/<endpoint> é validada, e se aceita, essa informação é repassada à frente pela instância do ouvinte

ParkingSpotListener. O servidor local aceita tanto requisições GET quanto POST. O uso de

token só é aceito e validado quando acompanhado de requisições POST.

A interface ParkingSpotListener tem o simples propósito de definir as assinaturas dos métodos que serão usados ao modificar uma vaga. Possui os métodos onIncreaseParkingSpot (vaga ocupada) e onDecreaseParkingSpot (vaga livre).

5.3.5 Pacote services

Esse pacote comporta os serviços presentes no App-Coleta. Possui apenas uma classe chamada ParkingLotServerService. Essa classe estende a classe Service, e como comentado anteriormente, um serviço é um componente de aplicativo que pode executar operações de execução demorada em segundo plano e não fornece uma interface com o usuário. Nesse caso específico, a classe ParkingLotServerService tem o propósito de comportar a execução de uma instância da classe CustomNanoHTTPD. Sendo assim, este serviço cria uma instância de

CustomNanoHTTPD e implementa a interface ParkingSpotListener para ouvir as mudanças

que são recebidas no servidor local.

Outra interface que ParkingLotServerService implementa é ParkingLotListener, que possui o intuito de tanto ouvir as mudanças do repositório do projeto, quanto aplicar as mudanças externas vindas a partir de requisições.

5.3.6 Pacote view_model

O pacote view_model abrange todas as classes que utilizam a classe ViewModel. Para a maioria das telas do aplicativo App-Coleta, há uma implementação de uma ViewModel.

A classe ViewModel do framework Android é responsável por preparar, gerenciar os dados e fazer a comunicação entre as atividades e Fragmentos com o resto da aplicação, como por exemplo, chamadas às classes que contém as regras de negócio. Uma instância da classe

ViewModel sempre é atrelada a um escopo (uma atividade ou fragmento). No entanto, quando

o escopo deixar de existir, a instância da classe ViewModel ainda será preservada, e quando esse mesmo escopo voltar a existir, essa instância da ViewModel será acoplada novamente, mantendo assim as informações necessárias para uma view (ANDROID, 2019g). Normalmente, as classes ViewModel expõem essas informações através da classe LiveData. Essa classe abriga dados que podem ser observados e que respeita o ciclo de vida de outros componentes do aplicativo. Essencialmente, a classe LiveData abriga instâncias de outras classes. Dessa forma, um componente pode adicionar um observador na instância de LiveData de uma

ViewModel, e toda vez que a ViewModel modificar os dados de LiveData, o componente que

está observando as mudanças irá recebê-las automaticamente (ANDROID, 2019g). As classes existentes no pacote view_model são:

a) AccountFragmentViewModel: interage com o fragmento AccountFragment; b) ParkingFragmentViewModel: interage com o fragmento ParkingFragment; c) MainActivityViewModel: interage com a atividade MainActivity;

d) ServerFragmentViewModel: interage com o fragmento ServerFragment; e) SpotsFragmentViewModel: interage com o fragmento SpotsFragment.

Todas elas implementam a interface InternetStatusListener. Em cada uma, o método addInternetStatusListener da classe NetworkUtil é chamado. Isso faz com que informações

sobre o estado da conexão com a internet possam ser recebidos e expostos através do uso de

LiveData. No tocante à interação com as regras de negócio, as classes ParkingFragmentViewModel, MainActivityViewModel, ServerFragmentViewModel e SpotsFragmentViewModel possuem o acesso à classe Repository através de uma instância

recebida no construtor da classe, sendo capazes de alterar dados bem como receber atualizações do repositório. Os tipos de dados que são gerenciados por cada view model serão explorados na próxima seção, onde serão evidenciadas as classes do pacote views.

5.3.7 Pacote views

O pacote views contém todos os pacotes e classes que estão relacionados à interação com o usuário, ou seja, as atividades e fragmentos. Contidos no pacote view, têm-se mais outros três pacotes, sendo: activities, dialogs e fragments.

5.3.7.1 Pacote activities

O pacote activities contém as atividades LoginActivity, MainActivity e

ConfigActivity.

A atividade LoginActivity é responsável pelo registro e login de usuários no App- Coleta. Como comentado anteriormente, os usuários podem tanto fazer login e registro utilizando uma conta do Google quanto utilizar um e-mail e senha. Na Figura 25 é mostrada a implementação final da tela de login. Pode-se notar o uso do botão de login do Google, que não existia na tela de mockup (Figura 12).

Figura 25. Atividade para a tela de login.

Fonte: Autor.

No decorrer da implementação, descobriu-se que o SDK Firebase Authentication oferece todas as atividades para o registro de um novo usuário, e por isso, não foi necessário o desenvolvimento destas. A sequência de atividades utilizadas no registro de um novo usuário é mostrada na Figura 26.

Após o usuário ter feito login e cadastrado todas as configurações necessárias, a primeira tela que é mostrada é a atividade MainActivity (Figura 27). Quando a MainActivity é criada, uma instância da classe MainActivityViewModel também é criada. Em seguida, começa-se a observar os dados que a MainActivityViewModel fornece e que correspondem ao número de vagas livres e ocupadas, tal como o estado da conexão com a internet. A

MainActivity tem o propósito principal de gerenciar o número de vagas livres. Quando o

usuário modifica uma vaga utilizando a MainActivity, métodos correspondentes são chamados na MainActivityViewModel e como essa possui uma instância de Repository os dados são alterados no Firebase.

Figura 27. Atividade para a tela principal.

Fonte: Autor.

Se por algum motivo o dispositivo ficar sem Internet, um ícone e uma mensagem serão apresentados ao usuário, como exibido na Figura 28. A mensagem contém um botão que abrirá a tela de configurações de Internet. Essa mesma mensagem e ícone aparecerão para todas as telas que o usuário acessar, enquanto o App-Coleta estiver autenticado em uma conta.

Figura 28. Atividade principal notificando a falta de conexão com a internet.

Fonte: Autor.

Para acessar a tela de configurações, foi adicionado um ícone situado no canto superior direito, como mostra a Figura 29.

Tais configurações são mostradas através da atividade ConfigActivity. O propósito fundamental dessa atividade é controlar os fragmentos que serão mostrados ao usuário. Diferentemente do que foi proposto no mockup (Figura 13), as configurações acabaram sendo divididas em múltiplas partes, deixando o layout das configurações melhor organizado. Para tal, usou-se abas dentro da ConfigActivity. Com isso tem-se um layout que permite ao usuário deslizar para a esquerda e direita através de "páginas" de conteúdo que geralmente são fragmentos diferentes. Isso é possível através do uso de ViewPager e

FragmentPagerAdapter, classes do framework Android que permitem constituir layouts

nesse formato. À vista disso, cada aba representa um fragmento que está sendo mostrado. Outra parte evidente da ConfigActivity é a presença de um menu, só que nesse caso, possui duas funções conjuntas que são sair do App-Coleta e parar o servidor local para que o número de vagas não seja mais atualizado.

Figura 29. Atividade de configurações.

Fonte: Autor.

Vale ressaltar que a ConfigActivity não observa nem modifica os dados do estacionamento, mas apenas gerencia os fragmentos.

5.3.7.2 Pacote fragments

No pacote fragments encontram-se as classes ParkingFragment, SpotsFragment,

ServerFragment e AccountFragment, cada uma delas sendo um fragmento que será utilizado

na atividade ConfigActivity. Tirando o fragmento AccountFragment, os demais obtêm os dados que são exibidos através da observação de uma instância de LiveData que está localizada em sua respectiva ViewModel. Todas os fragmentos observam o mesmo tipo de dado, sendo a classe de dados ParkingLot (LiveData<ParkingLot>). Quando uma configuração é modificada, ela é repassada para a ViewModel, que então é repassada para o repositório da aplicação e salva no Firebase. Os fragmentos que possuem campos editáveis contam com os botões "Cancelar" e "Salvar". O botão "Salvar", ao ser pressionado, registra as novas

configurações no Firebase, enquanto o botão "Cancelar" desfaz qualquer alteração realizada que não tenha sido salva.

O fragmento inicial é o ParkingFragment. Ele abrange praticamente todas as informações do estacionamento, sendo possível visualizá-las e editá-las, conforme mostrado na Figura 30.

Figura 30. Fragmento para a tela de configuração de endereço.

Fonte: Autor.

O segundo fragmento é o SpotsFragment (Figura 31), que é responsável por exibir as informações referentes às vagas do estacionamento, como o número de vagas totais e se o estacionamento possui vagas cobertas, por exemplo. Nesse fragmento também é possível editar

Dans le document Rayonnement dipolaire électrique (Page 4-8)

Documents relatifs