{"action":"created","comment":{"url":"https://api.github.com/repos/futurice/android-best-practices/pulls/comments/44510460","id":44510460,"diff_hunk":"@@ -0,0 +1,562 @@\n+# As melhores práticas no desenvolvimento Android\n+\n+Lições aprendidas por programadores Android na [Futurice](http://www.futurice.com). Evite reinventar a roda seguindo estas recomendações. Se está interessado em desenvolver aplicações para iOS ou Windows Phone, não se esqueça de verificar também nossas [**iOS Good Practices**](https://github.com/futurice/ios-good-practices) e [**Windows App Development Best Practices**](https://github.com/futurice/windows-app-development-best-practices).\n+\n+[![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-android--best--practices-brightgreen.svg?style=flat)](https://android-arsenal.com/details/1/1091)\n+\n+## Resumo\n+\n+#### Use o Gradle e a estrutura do projeto por ele recomendada\n+#### Coloque suas senhas e dados sensíveis em gradle.properties\n+#### Não escreva o seu próprio cliente de HTTP, utilize as bibliotecas Volley ou OkHttp\n+#### Use a biblioteca Jackson para fazer o parse de JSON\n+#### Evite o Guava e utilize poucas bibliotecas devido ao *limite máximo de 65 mil métodos*\n+#### Use Fragmentos para representar um ecrã UI\n+#### Use Atividades apenas para gerir Fragmentos\n+#### As layouts de XML são código, organize-as bem\n+#### Use estilos para evitar atributos duplicados nas layouts de XML\n+#### Use múltiplos ficheiros de estilos para evitar apenas um muito grande\n+#### Mantenha o seu colors.xml pequeno e DRY (sem repetições), defina apenas a palete\n+#### Mantenha também o dimens.xml DRY, defina constantes genéricas\n+#### Não faça uma hierarquia muito profunda de ViewGroups\n+#### Evite processar WebViews no cliente, e cuidado com fugas\n+#### Use o Robolectric para testes unitários, Robotium para testes conetados (UI)\n+#### Use o Genymotion como simulador\n+#### Use sempre o ProGuard ou DexGuard\n+#### Use SharedPreferences para persistência simples, caso contrário use ContentProviders\n+\n+\n+----------\n+\n+### Android SDK\n+\n+Coloque o [Android SDK](https://developer.android.com/sdk/installing/index.html?pkg=tools) algures no seu diretório inicial ou algum outro local independente da aplicação . Alguns IDEs incluem o SDK aquando da instalação, e pode colocá-lo sob o mesmo diretório que o IDE. Isso pode ser mau quando precisa de atualizar (ou reinstalar) o IDE, ou quando mudar IDEs . Além disso, evite colocar o SDK noutro diretório em nível de sistema que pode precisar de permissões sudo, se o IDE é executado sob o utilizador e não na raiz.\n+\n+### Sistema de compilação\n+\n+A sua opção padrão deve ser o [Gradle](http://tools.android.com/tech-docs/new-build-system). O Ant é muito mais limitado e também mais verboso. Com o Gradle, é fácil:\n+\n+- Construir sabores ou variantes diferentes do seu aplicativo\n+- Fazer tarefas simples tipo script\n+- Gerir e fazer o download de dependências\n+- Personalizar keystores\n+- E mais\n+\n+O plugin Gradle do Android também está a ser activamente desenvolvido pela Google como o novo sistema de compilação padrão.\n+\n+### Estrutura do Projeto\n+\n+Existem duas opções populares: a estrutura do projeto antiga Ant juntamente com o Eclipse ADT, e a nova estrutura do projeto Gradle juntamente com o Android Studio. Você deve escolher a nova estrutura do projeto. Se o seu projeto usa a estrutura antiga, considere-a desatualizada e comece a transferi-la para a nova estrutura.\n+\n+Estrutura antiga:\n+\n+```\n+old-structure\n+├─ assets\n+├─ libs\n+├─ res\n+├─ src\n+│  └─ com/futurice/project\n+├─ AndroidManifest.xml\n+├─ build.gradle\n+├─ project.properties\n+└─ proguard-rules.pro\n+```\n+\n+Estrutura nova:\n+\n+```\n+new-structure\n+├─ library-foobar\n+├─ app\n+│  ├─ libs\n+│  ├─ src\n+│  │  ├─ androidTest\n+│  │  │  └─ java\n+│  │  │     └─ com/futurice/project\n+│  │  └─ main\n+│  │     ├─ java\n+│  │     │  └─ com/futurice/project\n+│  │     ├─ res\n+│  │     └─ AndroidManifest.xml\n+│  ├─ build.gradle\n+│  └─ proguard-rules.pro\n+├─ build.gradle\n+└─ settings.gradle\n+```\n+\n+A principal diferença é que a nova estrutura separa explicitamente 'source sets' (`main`, `androidTest`), um conceito do Gradle. Você poderá, por exemplo, adicionar diretórios 'paid' e 'free' a `src` que terá o código fonte para os sabores pagos e gratuitos da sua aplicação.\n+\n+Ter um diretório de topo `app` é útil para distinguir a sua aplicação de outras bibliotecas (por exemplo, `library-foobar`) que terá uma referência na sua aplicação. O `settings.gradle` posteriormente mantém referências para estas bibliotecas, e o `app/build.gradle` pode fazer referência a elas.\n+\n+### Configuração do Gradle\n+\n+**Estrutura geral.** Siga [o guia do Google sobre Gradle para Android](http://tools.android.com/tech-docs/new-build-system/user-guide)\n+\n+**Pequenas tarefas.** Ao invés de scripts (shell, Python, Perl, etc.), pode fazer tarefas com o Gradle. Siga [a documentação do Gradle](http://www.gradle.org/docs/current/userguide/userguide_single.html#N10CBF) para mais detalhes.\n+\n+**Senhas.** No `build.gradle` da sua aplicação, precisa de definir `signingConfigs` para a _compilação de lançamento_. O que deverá evitar:\n+\n+_Não faça isto_. Irá aparecerá no sistema de controlo de versão.\n+\n+```groovy\n+signingConfigs {\n+    release {\n+        storeFile file(\"myapp.keystore\")\n+        storePassword \"password123\"\n+        keyAlias \"thekey\"\n+        keyPassword \"password789\"\n+    }\n+}\n+```\n+\n+Ao invés, crie o ficheiro `gradle.properties` o qual _não_ deverá ser adicionado ao sistema de controle de versão:\n+\n+```\n+KEYSTORE_PASSWORD=password123\n+KEY_PASSWORD=password789\n+```\n+\n+Aquele ficheiro será importado automaticamente pelo gradle, podendo utilizá-lo no `build.gradle` da seguinte forma:\n+\n+```groovy\n+signingConfigs {\n+    release {\n+        try {\n+            storeFile file(\"myapp.keystore\")\n+            storePassword KEYSTORE_PASSWORD\n+            keyAlias \"thekey\"\n+            keyPassword KEY_PASSWORD\n+        }\n+        catch (ex) {\n+            throw new InvalidUserDataException(\"You should define KEYSTORE_PASSWORD and KEY_PASSWORD in gradle.properties.\")\n+        }\n+    }\n+}\n+```\n+\n+**Prefira a resolução de dependências Maven em vez de importar ficheiros jar.** Se você incluir explicitamente os ficheiros jar no seu projeto, eles terão uma versão fixa específica, como `2.1.1`. Baixar jars e gerir atualizações é uma confusão, este é o problema que o Maven resolve de forma adequada, e é também incentivada nas compilações de Android Gradle. Por exemplo:\n+\n+```groovy\n+dependencies {\n+    compile 'com.squareup.okhttp:okhttp:2.2.0'\n+    compile 'com.squareup.okhttp:okhttp-urlconnection:2.2.0'\n+}\n+```    \n+\n+**Evite a resolução de dependências dinâmicas do Mavem**\n+\n+Evite usar versões dinâmicas, como por exemplo `2.1.+`, isto porque podem resultar em compilações instáveis ou subtis diferenças de comportamento não rastreadas entre as compilações. O uso de versões estáticas como `2.1.1` ajuda a criar um ambiente de desenvolvimento mais estável, previsível e repetível.\n+\n+### IDEs e editores de texto\n+\n+**Use qualquer editor, mas este deverá integrar bem com a estrutura do projeto.** Os editores são uma escolha pessoal, contudo é sua responsabilidade colocar o editor a funcionar de acordo com a estrutura do projeto e o sistema de compilação.\n+\n+O IDE mais recomendado neste momento é o [Android Studio](https://developer.android.com/sdk/installing/studio.html), porque foi e está a ser desenvolvido pela Google, é o mais próximo do Gradle, usa a nova estrutura de projeto por definição, encontra-se em fase estável, e foi adaptado especificamente para desenvolvimento Android.\n+\n+Pode usar o [Eclipse ADT](https://developer.android.com/sdk/installing/index.html?pkg=adt) se assim o desejar, mas terá de o configurar, visto que ele espera a antiga estrutura do projeto e compilações Ant. Poderá até mesmo usar editores de texto simples como o Vim, Sublime Text, ou Emacs. Nesse caso, irá ter de usar Gradle e `adb` na linha de comando. Se a integração do Eclipse com o Gradle não está a funcionar corretamente, as suas opções são usar a linha de comando apenas para compilação, ou migrar para o Android Studio. A última é a melhor opção visto que o plugin ADT foi depreciado recentemente.\n+\n+O que quer que use, certifique-se apenas que o Gradle e a nova estrutura do projeto se mantêm como a forma oficial de compilar a sua aplicação, e evite adicionar os ficheiros com as configurações específicas do seu editor ao sistema de controlo de versão. Por exemplo, evite adicionar o ficheiro Ant `build.xml`. Especialmente não se esqueça de manter o `build.gradle` atualizado e em funcionamento se está a modificar as configurações de compilação do Ant. Além disso, seja gentil com outros programadores, não os force a alterar as suas ferramentas preferidas.\n+\n+### Bibliotecas\n+\n+**[Jackson](http://wiki.fasterxml.com/JacksonHome)** é uma biblioteca em Java para converter Objetos em JSON e vice-versa. [Gson](https://code.google.com/p/google-gson/) é uma escolha popular para resolver este problema, contudo nós achamos que o Jackson é mais eficiente visto que suporta maneiras alternativas de processar JSON: _streaming_, modelo de árvore em memória, e a vinculação tradicional JSON-POJO. Mantenha em mente, contudo, que o Jackson é uma biblioteca maior do que Gson, assim, dependendo do seu caso, pode preferir Gson para evitar a limitação dos 65 mil métodos. Outras alternativas: [Json-smart](https://code.google.com/p/json-smart/) e [Boon JSON](https://github.com/RichardHightower/boon/wiki/Boon-JSON-in-five-minutes)\n+\n+**Trabalhos em rede, armazenamento em cache e imagens.** Há um par de soluções testadas exaustivamente no dia-a-dia para a realização de requisições para servidores, que você deverá utilizar antes de considerar implementar o seu próprio cliente. Use o [Volley](https://android.googlesource.com/platform/frameworks/volley) ou o [Retrofit](http://square.github.io/retrofit/). O Volley também fornece ajudantes para carregar e fazer o _cache_ de imagens. Se escolher o Retrofit, considere o [Picasso](http://square.github.io/picasso/) para carregar e fazer o _caching_ de imagens, e [OkHttp](http://square.github.io/okhttp/) para requisições eficientes de HTTP. Todos os três, Retrofit, Picasso e OkHttp foram criados pela mesma empresa, portanto eles complementam-se muito bem. [OkHttp pode também ser utilizado em conexão com o Volley](http://stackoverflow.com/questions/24375043/how-to-implement-android-volley-with-okhttp-2-0/24951835#24951835).\n+\n+**RxJava** é uma biblioteca para Reactive Programming, por outras palavras, manipulação de eventos assíncronos. É um paradigma poderoso e promissor, o que pode tornar-se confuso devido ao fato de ser tão diferente. Recomendamos que tenha cuidado antes de usar esta biblioteca para arquitetar toda a sua aplicação. Há alguns projetos feitos por nós usando RxJava, se precisar de ajuda fale com uma destas pessoas:  Timo Tuominen, Olli Salonen, Andre Medeiros, Mark Voit, Antti Lammi, Vera Izrailit, Juha Ristolainen. Escrevemos também algumas postagens no blogue sobre ele: [[1]](http://blog.futurice.com/tech-pick-of-the-week-rx-for-net-and-rxjava-for-android), [[2]](http://blog.futurice.com/top-7-tips-for-rxjava-on-android), [[3]](https://gist.github.com/staltz/868e7e9bc2a7b8c1f754), [[4]](http://blog.futurice.com/android-development-has-its-own-swift).\n+\n+Se você não tiver qualquer experiência com Rx, comece por aplicá-lo apenas nas respostas da API. Alternativamente, comece aplicando-o para a simples manipulação de eventos UI, como eventos de clique ou eventos de digitação num campo de pesquisa. Se você está confiante nas capacidades de Rx e quer aplicá-lo em toda a arquitetura, então, escreva os Javadocs em todas as partes mais difíceis. Mantenha em mente que outro programador que não esteja familiarizado com o RxJava pode ter dificuldades em manter o projeto. Faça o seu melhor para ajudá-los a compreender o seu código e também Rx.\n+\n+**[Retrolambda](https://github.com/evant/gradle-retrolambda)** é uma biblioteca em Java que permite o uso de expressões lambda em Android ou outras plataformas antes da JDK8. Ajuda a manter o código limpo e legível, especialmente se usa um estilo de programação funcional como pode exemplo o RxJava. Para o usar, instale a JDK8, defina-a como a sua localização SDK na janela da estrutura do projeto no Android Studio, defina as variáveis de ambiente `JAVA8_HOME` e `JAVA7_HOME`, e no ficheiro build.gradle que se encontra na raiz do projeto:\n+\n+```groovy\n+dependencies {\n+    classpath 'me.tatarka:gradle-retrolambda:2.4.1'\n+}\n+```\n+\n+e no ficheiro build.gradle de cada módulo, coloque\n+\n+```groovy\n+apply plugin: 'retrolambda'\n+\n+android {\n+    compileOptions {\n+    sourceCompatibility JavaVersion.VERSION_1_8\n+    targetCompatibility JavaVersion.VERSION_1_8\n+}\n+\n+retrolambda {\n+    jdk System.getenv(\"JAVA8_HOME\")\n+    oldJdk System.getenv(\"JAVA7_HOME\")\n+    javaVersion JavaVersion.VERSION_1_7\n+}\n+```\n+\n+Após fazer isso, o Android Studio irá proporcionar suporte ao código que escreve para lambdas Java8. Se é novo no mundo dos lambdas, use o seguinte para começar:\n+\n+- Qualquer interface com apenas um método é \"amiga dos lambdas\" e pode ser compressa na sintaxe mais compacta proporcionada pelos lambdas;\n+- Se está na dúvida sobre parâmetros e isso, escreva uma classe interna anónima normal e deixe o Android Studio a comprimir num lambda automaticamente.\n+\n+**Esteja atento à limitação do número de métodos dex, e evite usar demasiadas bibliotecas.** As aplicações de Android, quando organizadas como um arquivo dex, têm um limite de 65536 métodos aos quais se podem fazer referências [[1]](https://medium.com/@rotxed/dex-skys-the-limit-no-65k-methods-is-28e6cb40cf71) [[2]](http://blog.persistent.info/2014/05/per-package-method-counts-for-androids.html) [[3]](http://jakewharton.com/play-services-is-a-monolith/). Durante a compilação irá encontrar um erro fatal se passar esse limite. Por essa razão, use o número mínimo de bibliotecas, e use a ferramenta [dex-method-counts](https://github.com/mihaip/dex-method-counts) para encontrar que bibliotecas usar para ficar abaixo desse limite. Especialmente evite usar a biblioteca Guava, visto que contém mais de 13 mil métodos.\n+\n+### Atividades e Fragmentos\n+\n+Não há um consenso dentro da comunidade nem entre os programadores da Futurice como melhor organizar a arquitetura do Android com Fragmentos e Atividades. O Square até tem\n+[uma biblioteca para construir uma arquitetura maioritariamente com Views](https://github.com/square/mortar), descartando a necessidade de Fragmentos, contudo isso ainda não é considerado uma boa prática dentro da comunidade.\n+\n+Devido à história das APIs Android, pode de forma ligeira considerar Fragmentos como peças de UI no ecrã. Por outras palavras, Fragmentos estão normalmente relacionados com UI. Atividades podem ser ligeiramente consideradas controladores, eles são especialmente importantes devido ao seu ciclo de vida e para gerir estados. Contudo, não se surpreenda se vir variações nestes papéis: atividades podem tomar papéis na UI ([fazendo transições entre ecrãs](https://developer.android.com/about/versions/lollipop.html)), e [fragmentos podem ser usados apenas como controladores](http://developer.android.com/guide/components/fragments.html#AddingWithoutUI). Sugerimos que navegue com cuidado, tomando decisões informadas visto que há contrapartidas ao uso de arquiteturas apenas com fragmentos, ou apenas com atividades, ou apenas com views. Seguem alguns conselhos do que ter mais cuidado, mas leve-os com uma pitada de sal:\n+\n+- Evite usar [fragmentos dentro de fragmentos](https://developer.android.com/about/versions/android-4.2.html#NestedFragments) em excesso, porque [matryoshka bugs](http://delyan.me/android-s-matryoshka-problem/) podem ocorrer. Use fragmentos dentro de fragmentos apenas quando isso faz sentido (por exemplo, fragmentos num ViewPager que desliza horizontalmente dentro de um fragmento tipo ecrã) ou se é uma decisão bem informada.\n+\n+- Evite colocar demasiado código dentro das atividades. Sempre que possível, mantenha-as como contentores de peso leve, existindo primariamente na sua aplicação pelo ciclo de vida e outras interfaces importantes da API do Android. Dê preferência a atividades com apenas um fragmento ao invés de apenas atividades - coloque o seu código UI no fragmento da atividade. Isto irá fazer com que o código seja reutilizável no caso de por exemplo o querer modificar e colocar dentro de uma tabbed layout, ou num ecrã de tablete com múltiplos fragmentos. Evite ter uma atividade sem um fragmento correspondente, a não se que saiba o que está a fazer.\n+\n+- Não abuse das APIs do Android, como pode exemplo colocar demasiado peso nos Intent para o funcionamento interno da sua aplicação. Isso pode afetar o sistema operativo do Android e outras aplicações, criando bugs ou lag. Por exemplo, é um fato que se utilizar Intents para a comunicação interna na sua aplicação entre os packages, poderá fazer com que exista um lag de alguns segundos na experiência do utilizador se a app foi aberta depois do sistema operativo tiver sido iniciado.\n+\n+### Arquitetura dos pacotes de Java\n+\n+A arquitetura do Java para aplicações Android pode ser mais ou menos aproximada ao modelo [Model-View-Controller](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller). No Android, [Fragmentos e Atividades são na verdade classes de controlo](http://www.informit.com/articles/article.aspx?p=2126865). Por outro lado, elas são parte explícita da interface do utilizador, portanto são também views.\n+\n+Por este motivo, é difícil classificar fragmentos (ou atividades) como restritamente controladores ou views. É melhor as deixa ficar no seu próprio pacote `fragments`. Atividades podem ficar no pacote mais algo desde que sigam os conselhos da secção anterior. Se está a planear ter mais do que 2 ou 3 atividades, então crie também um pacote `activities`.\n+\n+Caso contrário, a arquitetura pode ser semelhante ao típico MVS, com um pacote `models` contendo POJOs que serão populados através de JSON parser com respostas à API, e um pacote `views` contendo as Views criadas por si, notificações, views da action bar, widgets, etc. Adapters são uma matéria cinzenta, estando entre os dados e as views. Contudo, eles tipicamente precisam de exportar alguma View através do `getView()`, portanto poderá incluir o sub-pacote `adapters` dentro de `views`.\n+\n+Algumas classes de controladores são para toda a aplicação e perto do sistema Android. Estas podem estar no pacote `managers`. Classes de processamento de dados várias, como \"DateUtils\", ficam dentro do pacote `utils`. Classes têm a responsabilidade de interagir com o servidor ficam no pacote `network`.\n+\n+No final de contas, organizadas do mais perto do servidor para o mais perto do utilizador:\n+\n+```\n+com.futurice.project\n+├─ network\n+├─ models\n+├─ managers\n+├─ utils\n+├─ fragments\n+└─ views\n+   ├─ adapters\n+   ├─ actionbar\n+   ├─ widgets\n+   └─ notifications\n+```\n+\n+### Recursos\n+\n+**Dar o nome.** Siga a convenção de colocar o prefixo como tipo, por exemplo `type_foo_bar.xml`. Exemplos:  `fragment_contact_details.xml`, `view_primary_button.xml`, `activity_main.xml`.\n+\n+**Organizar os layout XMLs.** Se não tem a certeza de como formatar o layout XML, as seguintes convenções podem ajudar:\n+\n+- Um atributo por linha, indentação de 4 espaços\n+- `android:id` sempre como o primeiro atributo\n+- `android:layout_****` atributo no topo\n+- `style` atributo no fundo\n+- A Tag de fechar `/>` na sua própria linha, para facilitar a ordenação e adicionar novos atributos.\n+- Ao invés de colocar o texto diretamente em `android:text`, considere usar os [atributos designtime](http://tools.android.com/tips/layout-designtime-attributes) disponíveis para Android Studio.\n+\n+```xml\n+<?xml version=\"1.0\" encoding=\"utf-8\"?>\n+<LinearLayout\n+    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n+    xmlns:tools=\"http://schemas.android.com/tools\"\n+    android:layout_width=\"match_parent\"\n+    android:layout_height=\"match_parent\"\n+    android:orientation=\"vertical\"\n+    >\n+\n+    <TextView\n+        android:id=\"@+id/name\"\n+        android:layout_width=\"match_parent\"\n+        android:layout_height=\"wrap_content\"\n+        android:layout_alignParentRight=\"true\"\n+        android:text=\"@string/name\"\n+        style=\"@style/FancyText\"\n+        />\n+\n+    <include layout=\"@layout/reusable_part\" />\n+\n+</LinearLayout>\n+```\n+\n+Regra geral, atributos `android:layout_****` devem ser definidos no layout XML, ao passo que outros atributos `android:****` devem ficar num XML de estilo. Esta regra tem excepções, mas de forma geral funciona bem. A ideia é manter apenas o layout (posicionamento, margem, tamanho) e atributos de conteúdo nos ficheiros de layout, mantendo todos os detalhes de aparência (cores, espaçamento, tipo de letra) em ficheiros de estilo.\n+\n+As excepções são:\n+\n+- `android:id` deverá ficar obviamente no ficheiro de layout\n+- `android:orientation` para um `LinearLayout` normalmente faz mais sentido num ficheiro de layout\n+- `android:text` deverá ficar no ficheiro de layout porque ele define conteúdo\n+- Por vezes irá fazer sentido definir um estilo genérico `android:layout_width` e `android:layout_height` mas por definição estes deverão aparecer no ficheiro de layout\n+\n+**Use estilos.** Quase todos os projeto precisam de usar estilos de forma adequada, isto porque é muito comum ter de repetir a aparência de uma view. No mínimo deverá ter um estilo comum para a maioria do conteúdo de texto na sua aplicação, por exemplo:\n+\n+```xml\n+<style name=\"ContentText\">\n+    <item name=\"android:textSize>@dimen/font_normal</item>\n+    <item name=\"android:textColor\">@color/basic_black</item>\n+</style>\n+```\n+\n+Aplicado às TextViews:\n+\n+```xml\n+<TextView\n+    android:layout_width=\"wrap_content\"\n+    android:layout_height=\"wrap_content\"\n+    android:text=\"@string/price\"\n+    style=\"@style/ContentText\"\n+    />\n+```\n+\n+Provavelmente irá ter de fazer o mesmo para botões, mas não pare já por aqui. Vá mais além e mova um grupo de atributos `android:****` que estejam relacionados e sejam repetidos para um estilo comum.\n+\n+**Divida um ficheiro de estilo grande em outros ficheiros.** Não precisa de ter apenas um ficheiro `styles.xml`. A Android SDK suporta outros ficheiros, e não há nada de mágico acerca do nome `styles`, o que importa são as tags de XML `<style>` dentro do ficheiro. Assim poderá ter os ficheiros `styles.xml`, `styles_home.xml`, `styles_item_details.xml`, `styles_forms.xml`. Ao contrário dos nomes dos diretório de recursos que têm algum significado para o sistema de compilação, nomes de ficheiros dentro de `res/values` podem ser arbitrários. \n+\n+**`colors.xml` é uma palete de cores.** Não deverá existir mais nada no seu `colors.xml` do que apenas um mapeamento do nome da cor a um valor RGBA. Não o use para definir valores RGBA para diferentes tipos de botões.\n+\n+*Não faça isto:*\n+\n+```xml\n+<resources>\n+    <color name=\"button_foreground\">#FFFFFF</color>\n+    <color name=\"button_background\">#2A91BD</color>\n+    <color name=\"comment_background_inactive\">#5F5F5F</color>\n+    <color name=\"comment_background_active\">#939393</color>\n+    <color name=\"comment_foreground\">#FFFFFF</color>\n+    <color name=\"comment_foreground_important\">#FF9D2F</color>\n+    ...\n+    <color name=\"comment_shadow\">#323232</color>\n+```\n+\n+Pode facilmente começar a repetir valores RGBA desta forma, e isso faz com que seja mais difícil alterar uma cor básica se isso for necessário. Além disso, essas definições estão relacionadas a algum contexto, como pode exemplo \"button\" ou \"comment\", e devem ficar no estilo do botão, não em `colors.xml`.\n+\n+Ao invés, faça isto:\n+\n+```xml\n+<resources>\n+\n+    <!-- grayscale -->\n+    <color name=\"white\"     >#FFFFFF</color>\n+    <color name=\"gray_light\">#DBDBDB</color>\n+    <color name=\"gray\"      >#939393</color>\n+    <color name=\"gray_dark\" >#5F5F5F</color>\n+    <color name=\"black\"     >#323232</color>\n+\n+    <!-- basic colors -->\n+    <color name=\"green\">#27D34D</color>\n+    <color name=\"blue\">#2A91BD</color>\n+    <color name=\"orange\">#FF9D2F</color>\n+    <color name=\"red\">#FF432F</color>\n+\n+</resources>\n+```\n+\n+Peça esta palete ao designer da aplicação. Os nomes não precisam de ser nomes de cores como \"green\", \"blue\", etc. Nomes como \"brand_primary\", \"brand_secondary\", \"brand_negative\" são também totalmente aceites. Formatar as cores desta forma irá fazer com que as alterar ou fazer a refatorização de cores seja mais fácil, e também irá mostrar de forma explícita as diferentes cores que estão a ser utilizadas. Normalmente para um UI com bom aspeto, é importante reduzir a variedade das cores que estão a ser utilizadas.\n+\n+**Trate o dimens.xml como o colors.xml.** Deverá também definir uma \"palete\" de espaçamentos e tamanhos de letra típicos, devido basicamente às mesmas razões que para as cores. Um bom exemplo de um ficheiro dimens:\n+\n+```xml\n+<resources>\n+\n+    <!-- font sizes -->\n+    <dimen name=\"font_larger\">22sp</dimen>\n+    <dimen name=\"font_large\">18sp</dimen>\n+    <dimen name=\"font_normal\">15sp</dimen>\n+    <dimen name=\"font_small\">12sp</dimen>\n+\n+    <!-- typical spacing between two views -->\n+    <dimen name=\"spacing_huge\">40dp</dimen>\n+    <dimen name=\"spacing_large\">24dp</dimen>\n+    <dimen name=\"spacing_normal\">14dp</dimen>\n+    <dimen name=\"spacing_small\">10dp</dimen>\n+    <dimen name=\"spacing_tiny\">4dp</dimen>\n+\n+    <!-- typical sizes of views -->\n+    <dimen name=\"button_height_tall\">60dp</dimen>\n+    <dimen name=\"button_height_normal\">40dp</dimen>\n+    <dimen name=\"button_height_short\">32dp</dimen>\n+\n+</resources>\n+```\n+\n+Nas margens e espaçamentos deverá usar as dimensões `spacing_****` para o layout, ao invés de colocar valores fixos, da mesma forma que o strings são tratados. Isto irá dar um look-and-feel consistente, ao mesmo tempo que irá fazer com que seja mais fácil organizar e modificar estilos e layouts.\n+\n+**strings.xml**\n+\n+Dê o nome aos strings com keys que fazem lembrar namespaces, e não tenha receio de repetir um valor para duas ou mais keys. Linguagens são complexas, portanto namespaces são necessários para trazer contexto e quebrar ambiguidade.\n+\n+**Mau**\n+```xml\n+<string name=\"network_error\">Network error</string>\n+<string name=\"call_failed\">Call failed</string>\n+<string name=\"map_failed\">Map loading failed</string>\n+```\n+\n+**Bom**\n+```xml\n+<string name=\"error.message.network\">Network error</string>\n+<string name=\"error.message.call\">Call failed</string>\n+<string name=\"error.message.map\">Map loading failed</string>\n+```\n+\n+Não escreva os valores do strings em letras maiúsculas. Mantenha-se dentro das convenções normais de texto (exemplo: coloque o primeiro caráter em letras maiúscula). Se precisa de mostrar o string em letras maiúsculas, então use por exemplo o atributo [`textAllCaps`](http://developer.android.com/reference/android/widget/TextView.html#attr_android:textAllCaps) na própria TextView.\n+\n+**Bad**\n+```xml\n+<string name=\"error.message.call\">CALL FAILED</string>\n+```\n+\n+**Good**","path":"translations/Portuguese/README.pt.md","position":407,"original_position":407,"commit_id":"322b59a9ee5431b86a41acd8f1f7faf7f6ff2184","original_commit_id":"322b59a9ee5431b86a41acd8f1f7faf7f6ff2184","user":{"login":"staltz","id":90512,"avatar_url":"https://avatars.githubusercontent.com/u/90512?v=3","gravatar_id":"","url":"https://api.github.com/users/staltz","html_url":"https://github.com/staltz","followers_url":"https://api.github.com/users/staltz/followers","following_url":"https://api.github.com/users/staltz/following{/other_user}","gists_url":"https://api.github.com/users/staltz/gists{/gist_id}","starred_url":"https://api.github.com/users/staltz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/staltz/subscriptions","organizations_url":"https://api.github.com/users/staltz/orgs","repos_url":"https://api.github.com/users/staltz/repos","events_url":"https://api.github.com/users/staltz/events{/privacy}","received_events_url":"https://api.github.com/users/staltz/received_events","type":"User","site_admin":false},"body":"This should be translated too","created_at":"2015-11-11T08:23:09Z","updated_at":"2015-11-11T08:23:09Z","html_url":"https://github.com/futurice/android-best-practices/pull/82#discussion_r44510460","pull_request_url":"https://api.github.com/repos/futurice/android-best-practices/pulls/82","_links":{"self":{"href":"https://api.github.com/repos/futurice/android-best-practices/pulls/comments/44510460"},"html":{"href":"https://github.com/futurice/android-best-practices/pull/82#discussion_r44510460"},"pull_request":{"href":"https://api.github.com/repos/futurice/android-best-practices/pulls/82"}}},"pull_request":{"url":"https://api.github.com/repos/futurice/android-best-practices/pulls/82","id":50033870,"html_url":"https://github.com/futurice/android-best-practices/pull/82","diff_url":"https://github.com/futurice/android-best-practices/pull/82.diff","patch_url":"https://github.com/futurice/android-best-practices/pull/82.patch","issue_url":"https://api.github.com/repos/futurice/android-best-practices/issues/82","number":82,"state":"open","locked":false,"title":"Portuguese translation","user":{"login":"luisramalho","id":286655,"avatar_url":"https://avatars.githubusercontent.com/u/286655?v=3","gravatar_id":"","url":"https://api.github.com/users/luisramalho","html_url":"https://github.com/luisramalho","followers_url":"https://api.github.com/users/luisramalho/followers","following_url":"https://api.github.com/users/luisramalho/following{/other_user}","gists_url":"https://api.github.com/users/luisramalho/gists{/gist_id}","starred_url":"https://api.github.com/users/luisramalho/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/luisramalho/subscriptions","organizations_url":"https://api.github.com/users/luisramalho/orgs","repos_url":"https://api.github.com/users/luisramalho/repos","events_url":"https://api.github.com/users/luisramalho/events{/privacy}","received_events_url":"https://api.github.com/users/luisramalho/received_events","type":"User","site_admin":false},"body":"Portuguese translation for the README.md","created_at":"2015-11-07T11:15:51Z","updated_at":"2015-11-11T08:23:09Z","closed_at":null,"merged_at":null,"merge_commit_sha":"b4abc46b9882da7791f98c061df5dc7a129e358f","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/futurice/android-best-practices/pulls/82/commits","review_comments_url":"https://api.github.com/repos/futurice/android-best-practices/pulls/82/comments","review_comment_url":"https://api.github.com/repos/futurice/android-best-practices/pulls/comments{/number}","comments_url":"https://api.github.com/repos/futurice/android-best-practices/issues/82/comments","statuses_url":"https://api.github.com/repos/futurice/android-best-practices/statuses/322b59a9ee5431b86a41acd8f1f7faf7f6ff2184","head":{"label":"luisramalho:master","ref":"master","sha":"322b59a9ee5431b86a41acd8f1f7faf7f6ff2184","user":{"login":"luisramalho","id":286655,"avatar_url":"https://avatars.githubusercontent.com/u/286655?v=3","gravatar_id":"","url":"https://api.github.com/users/luisramalho","html_url":"https://github.com/luisramalho","followers_url":"https://api.github.com/users/luisramalho/followers","following_url":"https://api.github.com/users/luisramalho/following{/other_user}","gists_url":"https://api.github.com/users/luisramalho/gists{/gist_id}","starred_url":"https://api.github.com/users/luisramalho/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/luisramalho/subscriptions","organizations_url":"https://api.github.com/users/luisramalho/orgs","repos_url":"https://api.github.com/users/luisramalho/repos","events_url":"https://api.github.com/users/luisramalho/events{/privacy}","received_events_url":"https://api.github.com/users/luisramalho/received_events","type":"User","site_admin":false},"repo":{"id":45733028,"name":"android-best-practices","full_name":"luisramalho/android-best-practices","owner":{"login":"luisramalho","id":286655,"avatar_url":"https://avatars.githubusercontent.com/u/286655?v=3","gravatar_id":"","url":"https://api.github.com/users/luisramalho","html_url":"https://github.com/luisramalho","followers_url":"https://api.github.com/users/luisramalho/followers","following_url":"https://api.github.com/users/luisramalho/following{/other_user}","gists_url":"https://api.github.com/users/luisramalho/gists{/gist_id}","starred_url":"https://api.github.com/users/luisramalho/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/luisramalho/subscriptions","organizations_url":"https://api.github.com/users/luisramalho/orgs","repos_url":"https://api.github.com/users/luisramalho/repos","events_url":"https://api.github.com/users/luisramalho/events{/privacy}","received_events_url":"https://api.github.com/users/luisramalho/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/luisramalho/android-best-practices","description":"Do's and Don'ts for Android development, by Futurice developers","fork":true,"url":"https://api.github.com/repos/luisramalho/android-best-practices","forks_url":"https://api.github.com/repos/luisramalho/android-best-practices/forks","keys_url":"https://api.github.com/repos/luisramalho/android-best-practices/keys{/key_id}","collaborators_url":"https://api.github.com/repos/luisramalho/android-best-practices/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/luisramalho/android-best-practices/teams","hooks_url":"https://api.github.com/repos/luisramalho/android-best-practices/hooks","issue_events_url":"https://api.github.com/repos/luisramalho/android-best-practices/issues/events{/number}","events_url":"https://api.github.com/repos/luisramalho/android-best-practices/events","assignees_url":"https://api.github.com/repos/luisramalho/android-best-practices/assignees{/user}","branches_url":"https://api.github.com/repos/luisramalho/android-best-practices/branches{/branch}","tags_url":"https://api.github.com/repos/luisramalho/android-best-practices/tags","blobs_url":"https://api.github.com/repos/luisramalho/android-best-practices/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/luisramalho/android-best-practices/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/luisramalho/android-best-practices/git/refs{/sha}","trees_url":"https://api.github.com/repos/luisramalho/android-best-practices/git/trees{/sha}","statuses_url":"https://api.github.com/repos/luisramalho/android-best-practices/statuses/{sha}","languages_url":"https://api.github.com/repos/luisramalho/android-best-practices/languages","stargazers_url":"https://api.github.com/repos/luisramalho/android-best-practices/stargazers","contributors_url":"https://api.github.com/repos/luisramalho/android-best-practices/contributors","subscribers_url":"https://api.github.com/repos/luisramalho/android-best-practices/subscribers","subscription_url":"https://api.github.com/repos/luisramalho/android-best-practices/subscription","commits_url":"https://api.github.com/repos/luisramalho/android-best-practices/commits{/sha}","git_commits_url":"https://api.github.com/repos/luisramalho/android-best-practices/git/commits{/sha}","comments_url":"https://api.github.com/repos/luisramalho/android-best-practices/comments{/number}","issue_comment_url":"https://api.github.com/repos/luisramalho/android-best-practices/issues/comments{/number}","contents_url":"https://api.github.com/repos/luisramalho/android-best-practices/contents/{+path}","compare_url":"https://api.github.com/repos/luisramalho/android-best-practices/compare/{base}...{head}","merges_url":"https://api.github.com/repos/luisramalho/android-best-practices/merges","archive_url":"https://api.github.com/repos/luisramalho/android-best-practices/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/luisramalho/android-best-practices/downloads","issues_url":"https://api.github.com/repos/luisramalho/android-best-practices/issues{/number}","pulls_url":"https://api.github.com/repos/luisramalho/android-best-practices/pulls{/number}","milestones_url":"https://api.github.com/repos/luisramalho/android-best-practices/milestones{/number}","notifications_url":"https://api.github.com/repos/luisramalho/android-best-practices/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/luisramalho/android-best-practices/labels{/name}","releases_url":"https://api.github.com/repos/luisramalho/android-best-practices/releases{/id}","created_at":"2015-11-07T11:05:45Z","updated_at":"2015-11-07T11:05:46Z","pushed_at":"2015-11-07T11:09:44Z","git_url":"git://github.com/luisramalho/android-best-practices.git","ssh_url":"git@github.com:luisramalho/android-best-practices.git","clone_url":"https://github.com/luisramalho/android-best-practices.git","svn_url":"https://github.com/luisramalho/android-best-practices","homepage":null,"size":1190,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"futurice:master","ref":"master","sha":"22d3ffc9e3a55d50d85d46d5aba0fd3b0c01bdd7","user":{"login":"futurice","id":852157,"avatar_url":"https://avatars.githubusercontent.com/u/852157?v=3","gravatar_id":"","url":"https://api.github.com/users/futurice","html_url":"https://github.com/futurice","followers_url":"https://api.github.com/users/futurice/followers","following_url":"https://api.github.com/users/futurice/following{/other_user}","gists_url":"https://api.github.com/users/futurice/gists{/gist_id}","starred_url":"https://api.github.com/users/futurice/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/futurice/subscriptions","organizations_url":"https://api.github.com/users/futurice/orgs","repos_url":"https://api.github.com/users/futurice/repos","events_url":"https://api.github.com/users/futurice/events{/privacy}","received_events_url":"https://api.github.com/users/futurice/received_events","type":"Organization","site_admin":false},"repo":{"id":22374063,"name":"android-best-practices","full_name":"futurice/android-best-practices","owner":{"login":"futurice","id":852157,"avatar_url":"https://avatars.githubusercontent.com/u/852157?v=3","gravatar_id":"","url":"https://api.github.com/users/futurice","html_url":"https://github.com/futurice","followers_url":"https://api.github.com/users/futurice/followers","following_url":"https://api.github.com/users/futurice/following{/other_user}","gists_url":"https://api.github.com/users/futurice/gists{/gist_id}","starred_url":"https://api.github.com/users/futurice/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/futurice/subscriptions","organizations_url":"https://api.github.com/users/futurice/orgs","repos_url":"https://api.github.com/users/futurice/repos","events_url":"https://api.github.com/users/futurice/events{/privacy}","received_events_url":"https://api.github.com/users/futurice/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/futurice/android-best-practices","description":"Do's and Don'ts for Android development, by Futurice developers","fork":false,"url":"https://api.github.com/repos/futurice/android-best-practices","forks_url":"https://api.github.com/repos/futurice/android-best-practices/forks","keys_url":"https://api.github.com/repos/futurice/android-best-practices/keys{/key_id}","collaborators_url":"https://api.github.com/repos/futurice/android-best-practices/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/futurice/android-best-practices/teams","hooks_url":"https://api.github.com/repos/futurice/android-best-practices/hooks","issue_events_url":"https://api.github.com/repos/futurice/android-best-practices/issues/events{/number}","events_url":"https://api.github.com/repos/futurice/android-best-practices/events","assignees_url":"https://api.github.com/repos/futurice/android-best-practices/assignees{/user}","branches_url":"https://api.github.com/repos/futurice/android-best-practices/branches{/branch}","tags_url":"https://api.github.com/repos/futurice/android-best-practices/tags","blobs_url":"https://api.github.com/repos/futurice/android-best-practices/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/futurice/android-best-practices/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/futurice/android-best-practices/git/refs{/sha}","trees_url":"https://api.github.com/repos/futurice/android-best-practices/git/trees{/sha}","statuses_url":"https://api.github.com/repos/futurice/android-best-practices/statuses/{sha}","languages_url":"https://api.github.com/repos/futurice/android-best-practices/languages","stargazers_url":"https://api.github.com/repos/futurice/android-best-practices/stargazers","contributors_url":"https://api.github.com/repos/futurice/android-best-practices/contributors","subscribers_url":"https://api.github.com/repos/futurice/android-best-practices/subscribers","subscription_url":"https://api.github.com/repos/futurice/android-best-practices/subscription","commits_url":"https://api.github.com/repos/futurice/android-best-practices/commits{/sha}","git_commits_url":"https://api.github.com/repos/futurice/android-best-practices/git/commits{/sha}","comments_url":"https://api.github.com/repos/futurice/android-best-practices/comments{/number}","issue_comment_url":"https://api.github.com/repos/futurice/android-best-practices/issues/comments{/number}","contents_url":"https://api.github.com/repos/futurice/android-best-practices/contents/{+path}","compare_url":"https://api.github.com/repos/futurice/android-best-practices/compare/{base}...{head}","merges_url":"https://api.github.com/repos/futurice/android-best-practices/merges","archive_url":"https://api.github.com/repos/futurice/android-best-practices/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/futurice/android-best-practices/downloads","issues_url":"https://api.github.com/repos/futurice/android-best-practices/issues{/number}","pulls_url":"https://api.github.com/repos/futurice/android-best-practices/pulls{/number}","milestones_url":"https://api.github.com/repos/futurice/android-best-practices/milestones{/number}","notifications_url":"https://api.github.com/repos/futurice/android-best-practices/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/futurice/android-best-practices/labels{/name}","releases_url":"https://api.github.com/repos/futurice/android-best-practices/releases{/id}","created_at":"2014-07-29T09:09:44Z","updated_at":"2015-11-11T06:53:48Z","pushed_at":"2015-11-07T11:15:51Z","git_url":"git://github.com/futurice/android-best-practices.git","ssh_url":"git@github.com:futurice/android-best-practices.git","clone_url":"https://github.com/futurice/android-best-practices.git","svn_url":"https://github.com/futurice/android-best-practices","homepage":null,"size":1190,"stargazers_count":6868,"watchers_count":6868,"language":"Java","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":1203,"mirror_url":null,"open_issues_count":26,"forks":1203,"open_issues":26,"watchers":6868,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/futurice/android-best-practices/pulls/82"},"html":{"href":"https://github.com/futurice/android-best-practices/pull/82"},"issue":{"href":"https://api.github.com/repos/futurice/android-best-practices/issues/82"},"comments":{"href":"https://api.github.com/repos/futurice/android-best-practices/issues/82/comments"},"review_comments":{"href":"https://api.github.com/repos/futurice/android-best-practices/pulls/82/comments"},"review_comment":{"href":"https://api.github.com/repos/futurice/android-best-practices/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/futurice/android-best-practices/pulls/82/commits"},"statuses":{"href":"https://api.github.com/repos/futurice/android-best-practices/statuses/322b59a9ee5431b86a41acd8f1f7faf7f6ff2184"}}}}