Android Library — Modularizando seus apps
Em algum momento, como desenvolvedor, você vai considerar escrever uma biblioteca. Talvez porque você tenha criado uma maneira interessante para realizar algo específico e quer compartilhar com o mundo, ou talvez por simplesmente querer reutilizar seu código de forma elegante. Qualquer que seja a motivação, quando falamos de Android, escrever uma biblioteca não é nada trivial. Você se questionará sobre o sistema de criação, o processo de publicação, a compatibilidade com Android, Java e muito mais.
Recentemente iniciei no mundo mobile e o objetivo deste post é compartilhar alguns aprendizados e conclusões que tive até o momento. Vou falar alguns pontos de atenção que devemos ter quando criamos uma biblioteca. Além de mostrar um simples exemplo de desenvolvimento de uma biblioteca Android.
Quando você deve pensar em escrever uma biblioteca?
Para começar a falar disso, é interessante responder essa simples pergunta. Algumas razões para escrever uma biblioteca:
- Modularidade: A primeira razão é modularidade. Dividir seu código em unidades menores traz muitas vantagens. Unidades menores são mais fáceis de entender e testar. Em geral, elas tendem a ter uma qualidade superior no final.
- Reutilização: Depois de ter unidades menores, você pode usá-las em vários lugares da sua aplicação ou até em várias aplicações diferentes.
- Distribuição: A capacidade de distribuição também é uma consequência da reutilização. Se for útil para você, pode ser para mais alguém. Além do mais, ao compartilhar as pessoas lhe darão feedback e por resultado a qualidade será aprimorada.
- Identidade visual: Especificamente no Android, você pode usar uma biblioteca para definir a sua identidade visual (os resources e assets) em um único lugar.
As boas práticas
Manter a “casa organizada” é uma das principais responsabilidades de um desenvolvedor de software. Inclusive este é um problema abordado em outras áreas do desenvolvimento de Software, abaixo alguns exemplos:
- O Twelve Factor tem como principal objetivo definir um manual de boas práticas para o micro serviços.
- A Microsoft definiu diretrizes para o desenvolvimento de suas API RESTful.
Mas o que isso tem a ver com o desenvolvimento de bibliotecas?
Na verdade, está muito relacionado. Assim como no desenvolvimento de API RESTful e micro serviços, o desenvolvimento de uma biblioteca deve possuir um nível de qualidade e atenção elevado, visto que ela geralmente será utilizada por outros desenvolvedores e muitas aplicações podem depender do bom funcionamento dela.
As boas práticas que vou falar aqui são dicas de Joshua Bloch (autor do livro Effective Java). No livro e nesta apresentação ele fala sobre como projetar uma boa API (ou biblioteca). Abaixo listo algumas características que uma boa biblioteca possui:
- Fácil de aprender: Como já falei aqui, uma biblioteca será sempre utilizada por outros desenvolvedores. Dito isto, desenvolver algo usando ela tem que ser simples e natural.
- Fácil de usar (mesmo sem documentação): Isso significa que os nomes dos métodos, classes e argumentos devem ser coerentes e fazer sentido. Eles não devem enganar seu usuário de forma alguma.
- Difícil de fazer uso indevido: Depois de publicar sua biblioteca, você não tem ideia de como ela será usada. Talvez durante o desenvolvimento você perceba padrões de uso e pense “Tudo bem, as pessoas podem usar isso dessa maneira, eu só vou documentar que é necessário utilizar desse jeito.” Contudo, sempre tem aqueles que não leem a documentação. Então, sempre que puder, tente impor isso no código.
- Fácil de ler e manter o código que o utiliza: Este ponto está muito relacionado com o “fácil de usar”. É importante sempre priorizar a simplicidade. Afinal, você está escrevendo a biblioteca porque quer resolver problemas e não criar :).
- Fácil de estender: Este não é tão importante quanto os anteriores, mas é sempre bom pensar. Se os usuários quiserem adicionar alguma funcionalidade na sua biblioteca, eles não devem ser obrigados a clonar e modificar o seu código, é muito melhor se eles puderem simplesmente estende-la e implementar suas próprias funcionalidades.
Mãos a obra
Certo, agora chega de teoria e vamos para a prática. A biblioteca que iremos criar será uma ImageView personalizada. A nossa biblioteca terá as seguintes funcionalidades:
- Possibilidade de carregar uma imagem diretamente de um link;
- Aplicação opcional de filtro preto e branco;
- Configuração de imagem de erro (caso ocorra um erro, deverá aparecer a imagem escolhida);
- Configuração de placeholder (a imagem que deve aparecer enquanto a original não é carregada);
Caso queira acompanhar o tutorial com código completo, você pode encontrar ele aqui.
Preparando o ambiente
Para executar esse projeto você precisará somente do Android Studio. Siga esse tutorial caso ainda não o tenha instalado.
Criando o aplicativo
Vamos começar criando um novo projeto Android. Clique no menu File -> New -> New Project
e atente para os seguintes campos:
- Vamos nomear o aplicativo de MyImageView
- Marque “Phone and tablet” e escolha a opção “API 21: Android 5.0”.
- Na tela de Activity, escolha “Empty Activity”.
Certo, acabamos de criar o aplicativo que utilizaremos para testar a nossa biblioteca. Agora vamos criar a biblioteca, depois voltaremos neste aplicativo.
Criando a biblioteca
Clique no menu File -> New -> New Module
e atente para os seguintes campos:
- Na primeira tela, escolha Android Library.
- Vamos nomear a biblioteca de MyImageViewLibrary
Agora a biblioteca está criada também. Na imagem abaixo demonstra como você deve estar visualizando no menu de projetos do Android Studio:
Vamos começar a desenvolver o nosso ImageView. Primeiro iremos criar o XML que possui a configuração de layout do nossa biblioteca:
- Na pasta
myimageviewlibrary/res
, clique com o botão direito e selecionenew -> New Resource directory
, no campoResource type
selecionelayout
. - Na pasta
myimageviewlibrary/res/layout
, clique com o botão direito e selecionenew -> Layout resource file
. - Chame o arquivo de
my_image_view_layout.xml
. - No campo Root element selecione
FrameLayout.
- No XML criado, adicione um ImageView conforme o exemplo abaixo.
Abaixo um exemplo do nosso XML:
O próximo passo é criar a classe que conterá as regra e comportamentos do nossa biblioteca:
- Na pasta
myimageviewlibrary/java/com.example.pkg.myimageviewlibrary
, clique com o botão direito e selecionenew -> Java class
, no campoName
selecioneMyImageViewBasic
e noSuper class
selecioneRelativeLayout
. - Após criar a classe, o Android Studio deve estar acusando erro informando que tem que implementar algum construtor. Implemente os três primeiros, conforme demonstrado abaixo.
Esta classe ainda não está pronta, mas antes de continuar este desenvolvimento, devemos criar os atributos. Estes atributos servirão como porta de entrada para o nossa biblioteca, tornando-a mais flexível. Vamos ver como criar:
- Na pasta
myimageviewlibrary/res/values
, clique com o botão direito e selecionenew -> Values resource file
. No campoName
informeattrs.xml
- Preencha o arquivo com o conteúdo abaixo.
Observação: O
name
dodeclare-styleable
deve ser o mesmo da classe definida anteriormente.
Vamos revisar o que são os nossos atributos:
- imageSrc: Serve para configurar a imagem principal.
- imagePlaceholder: Serve para configurar a imagem que será mostrada de placeholder ( é a imagem que mostrará enquanto a do
imageSrc
não baixar). - imageError: Serve para configurar a imagem que será mostrada caso ocorra algum erro no download.
- isBlackAndWhite: Serve para informar se deve ou não aplicar um filtro preto e branco na imagem.
Agora vamos acessar estes atributos na nossa classe. Para ficar mais fácil de explicar, vou mostrar a versão final da classe e vamos comentar somente os pontos relevantes:
Para as funcionalidades relacionadas a download de imagem utilizamos a biblioteca Glide, ela gerencia o download e cache de imagens para Android.
Se você já está familiarizado com desenvolvimento de software, a maior parte deste código é fácil de entender. Vamos focar a analise do código nos métodos criados:
initView: Como o nome sugere, este método é responsável por inicializar o componente. O trecho abaixo, está iterando os atributos definidos no arquivo attrs.xml
e armazenando em variáveis para tomarmos alguma ação posteriormente.
TypedArray arr = context.obtainStyledAttributes(attrs, R.styleable.MyImageViewBasic, defStyleAttr, 0);
isBlackAndWhite = arr.getBoolean(R.styleable.MyImageViewBasic_isBlackAndWhite, false);
imageFile = arr.getDrawable(R.styleable.MyImageViewBasic_imageSrc);
imagePlaceHolder = arr.getDrawable(R.styleable.MyImageViewBasic_imagePlaceholder);
imageError = arr.getDrawable(R.styleable.MyImageViewBasic_imageError);
setDrawableImage: Este método serve para setar a imagem principal a partir de um resource do Android.
setUrlImage: Este método também serve para setar a imagem principal, a diferença é que ele irá efetuar o download dela, através da URL. Note que é neste método que estamos utilizando a biblioteca Glide (citada acima), para importar essa dependência, abra o arquivo myimageviewlibrary/build.gradle
e adicione a seguinte linha:
dependencies {
.
.
.
implementation 'com.github.bumptech.glide:glide:3.7.0'
}
Agora vamos usar a nossa biblioteca
O primeiro passo é adicionar ela como dependência no projeto app
:
- Clique com botão direito no
app
e selecione Open module settings. - Na aba Dependencies, clique no botão “+” e selecione Module dependency, você deverá ver a biblioteca que desenvolvemos (
myimageviewlibrary
), selecione ela e acabamos de configurar uma dependência local.
Agora sim vamos testar, abra o arquivo activity_main.xml
e adicione a nossa biblioteca, modifique ele como demonstrado abaixo:
Algumas observações, note que estamos utilizando três dos atributos definidos. Caso o download da imagem dê algum erro, mostrada a imagem configurada no resource @drawable/error
. Enquanto a imagem não for carregada, será mostrada a imagem configurada no resource @drawable/placeholder
. Por fim, configuramos a imagem para ter um filtro preto e branco.
Dica: Para configurar o resources, simplesmente cole imagens com os nome “error” e “placeholder” na pasta
res/drawable
.
Ainda falta algo, onde configuramos a URL da imagem que será mostrada?
Abra o arquivo MainActivity.java
e modifique para fazer isso:
Se você executar agora a aplicação, ocorrerá um erro de cara. A imagem que aparecerá será aquela configurada no @drawable/error
.
O erro que está ocorrendo é devido a falta de permissão para acesso a internet. Para configurar isso,modifique o AndroidManifest.xml
da nossa biblioteca e adicione a seguinte linha:
<uses-permission android:name="android.permission.INTERNET" />
Execute novamente e veja a biblioteca em funcionamento:
E agora?
Bom, o assunto não termina por aqui. Na verdade, existe muito mais para aprender. No próximo post pretendo falar sobre as diferentes maneiras existentes para disponibilizar esta nossa biblioteca para o resto do mundo.
Se quiser trocar uma ideia ou entrar em contato comigo, pode me achar no Twitter(@e_ferreirasouza) ou Linkedin.
Grande abraço e até a próxima!