Make your users happy, (please) use the BackupManager

Every developer wants to make they users happy. This way the users keep using their application, or better yet, keep buying.

Is there anything more frustrating for a user than losing all ‘three star’ phases of his favorite game?
Or have to fill in lots of data fields after a new installation of an application that he uses, in his new and recently acquired ‘latest generation smartphone’?

Android provides a very simple feature to back up settings and preferences on the Cloud, the BackupManager

Using the BackupManager you can backup your SharedPreferences and configuration files on the cloud (do not use it for large binary files).

And the best of all is that it is very simple to use:

  • First you need to register an API KEY at http://code.google.com/android/backup/signup.html
  • Then we need to create a class that extends the BackupAgentHelper:
    import android.app.backup.BackupAgentHelper; 
    import android.app.backup.SharedPreferencesBackupHelper; 
    
    public class MyBackupAgent extends BackupAgentHelper {
        // The names of the SharedPreferences groups that the application maintains.  These
        // are the same strings that are passed to getSharedPreferences(String, int). 
        static final String PREFS_DISPLAY = "displayprefs"; 
        static final String PREFS_SCORES = "highscores"; 
    
        // An arbitrary string used within the BackupAgentHelper implementation to
        // identify the SharedPreferenceBackupHelper's data. 
        static final String MY_PREFS_BACKUP_KEY = "myprefs"; 
    
        // Simply allocate a helper and install it 
        void onCreate() { 
            SharedPreferencesBackupHelper helper = 
                    new SharedPreferencesBackupHelper(this, PREFS_DISPLAY, PREFS_SCORES);
            addHelper(MY_PREFS_BACKUP_KEY, helper); 
        } 
    }
  • On yout AndroidManifest.xml tag add android:allowBackup=”true” to enable the backup and android:BackupAgent=”MyBackupAgent” to tell what your BackupAgent is.
    Still on the application tag, add:

    <meta-data android:name="com.google.android.backup.api_key" 
            android:value="YOUR API KEY HERE" />
  • Each time you change some data in the SharedPreferences groups you want to backup (in our example “displayprefs” and “highscores”) you need to call DataChanged() on an instance of BackupManager:
    BackupManager backupManager = new BackupManager(context);
    ... 
    backupManager.dataChanged();

Okay, that’s all you need to back up and restore settings in/from the cloud and especially keep your users happy.

So, if you are a developer, make your users happy, and if you are a user, ask the developers to make you happy.

The BackupManager is available from android 2.2 froyo.

Sample source code available at BackupManagerTest

Faça seus usuários felizes, (por favor) use o BackupManager

Acredito que o que todo desenvolvedor quer, é que seus usuários sejam felizes para que continuem usando, ou melhor ainda, continuem comprando seus aplicativos.

Existe algo mais frustrante para um usuário do que perder todos as fases com 3 estrelinhas do seu joguinho preferido.
Ou ter que preencher vários dados após uma nova instalação de uma aplicativo que ele já usa, em seu novo e recém adquirido smartphone de última geração?

O Android prove uma funcionalidade muito simples para se fazer backup de configurações e preferências na Cloud, através do BackupManager.

Usando o BackupManager você pode fazer backup na cloud de suas SharedPreferences ou de arquivos de configuração/informação simples (não use para arquivos binários grandes).

E o melhor de tudo, ele é muito simples de usar:

  • Primeiro você precisa registrar uma chave de acesso (API Key) em http://code.google.com/android/backup/signup.html
  • Depois precisamos criar uma Classe que estende a BackupAgentHelper:
    import android.app.backup.BackupAgentHelper; 
    import android.app.backup.SharedPreferencesBackupHelper;  
    
     public class MyBackupAgent extends BackupAgentHelper {
         // O nome dos grupos de SharedPreferences mantidas pela aplicação, 
         // são as mesmas strings que você passa para o 
         // getSharedPreferences(String, int). 
         static final String PREFS_DISPLAY = "displayprefs"; 
         static final String PREFS_SCORES = "highscores";  
    
         // Uma string arbitraria usada pelo BackupAgentHelper para
         // identificar os dados do SharedPreferenceBackupHelper 
         static final String MY_PREFS_BACKUP_KEY = "myprefs";  
    
         // Simplesmente aloca um helper e o instala... 
         void onCreate() { 
             SharedPreferencesBackupHelper helper = 
                     new SharedPreferencesBackupHelper(this, PREFS_DISPLAY,
                                                             PREFS_SCORES); 
             addHelper(MY_PREFS_BACKUP_KEY, helper); 
         } 
     }
  • No seu AndroidManifest.xml na tag <application> adicione
    android:allowBackup="true"

    para habilitar o backup e

    android:backupAgent="MyBackupAgent"

    para informar qual o seu BackupAgent
    Ainda na tag application, adicione:

     <meta-data android:name="com.google.android.backup.api_key" 
            android:value="SUA API KEY" /> 
    
  • Cada fez que alterar algum dado nos grupos de SharedPreferences que você está querendo fazer backup (no nosso exemplo “displayprefs” e “highscores”) você precisa chamar dataChanged() em uma instancia de BackupManager:
    BackupManager backupManager = new BackupManager(context);
    ... 
    backupManager.dataChanged();

Pronto, isso é tudo o que você precisa para fazer o backup e recuperação das configurações na cloud e principalmente manter os seus usuários felizes.

Código disponível em BackupManagerTest

Até a próxima.

O que não fazer em Interfaces Android (ou como melhorá-las…)

Essa semana irei falar sobre o que NÃO fazer em interfaces (de usuário) Android.

O que me inspirou a escrever sobre isso foi o lançamente de um aplicativo iPhone de sucesso para Android.
Estou falando do Viber

De uma olhada nessa foto:

Então, que versão do Viber estou mostrando???

Sim, essa é a versão Android. E com apenas um ‘screenshot’ começamos a ver os problemas…
Primeiro, esse aplicativo não parece Android, e isso me leva ao primeiro ponto.

  • Não use ‘bottom tabs’
    • Nunca use bottom tabs [1][2][3]. E essas são ainda piores, pois são exatamente iguais as tabs do iOS (e lembre-se você não está usando um device iOS).

      Tabs devem ser usadas no topo da tela. Algumas vezes você nem precisa, ou nem quer usar tabs, então você pode substituí-las por algum outro artifício mais ‘Android’, como por exemplo um dashboard, uma actionbar ou uma combinação de ambos.

      Aqui está um esboço de como o aplicativo Viber poderia ser no Android:

      Aqui eu usei uma ‘actionbar’ [4] (um design pattern comum em Android), com acesso às chamadas recentes e às mensagens de texto na barra superior.
      A lista de contatos é um ‘PageViewer’ (parecido com o do novo aplicativo do Market, ou do google+) com acesso a todos contatos, favoritos e contantos viber via um ‘arraste’ horizontal. Abaixo está o ‘dialing pad’ usando um ‘sliding drawer’ (basta arrastar o keypad para cima para ele aparecer).

      Está é apenas uma possibilidade, outra seria colocar o acesso ao dialpad como um icone na actionbar (e remover o sliding drawer), ou então utilizar um dashboard como pagina inicial, exatamente como o google+ faz.

      Com essas screenshots, podemos ver que ele se parece muito mais Android agora:

  • Não coloque botões de voltar na Interface.
    • O Android já tem um botão Voltar, e ele é obrigatório (diferente do botão search que é opcional). Todos os telefones PRECISAM ter um botão Voltar (com exceção do Honeycomb que tem o voltar em sua barra de navegação), então por que se preocupar em colocar outro botão Voltar para confundir o usuário?

      Relacionado a isso, nunca (certo, apenas em casos excepcionais e quando você realmente sabe o que está fazendo) sobrescreva o comportamento do botão Voltar, os usuários pressionam esse botão e esperam um certo comportamento, e eles tendem a ficar decepcionados (para não dizer com raiva) quando não acontece o que eles estão esperando.

      O que você pode (e é até recomendado) fazer, é ter um botão “Home” na Action Bar. Ele o leva direto para a “Home page” do seu aplicativo, e limpa a pilha de ‘atividades’ (backstack) do seu aplicativo. Ele não é uma navegação ‘voltar’, ele está indo para frente (forward navigation).

  • Não reinvente a roda (Use a API de Intents do Android)
    • Use a API de Intents do Android. Uma das funcionalidades mais comuns e mais usadas em aplicativos móveis é compartilhar conteúdo via redes sociais, ou email, sms, etc. Você não precisa implementar cada uma dessas interfaces de compartilhamento, você deve usar Intents para compartilhar o conteúdo.


      Intent sharingIntent = new Intent(Intent.ACTION_SEND);
      sharingIntent.setType("text/html");
      sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT,
      Html.fromHtml("<p>Este texto será compartilhado.</p>"));
      startActivity(Intent.createChooser(sharingIntent,"Compartilhe com"));

      Isso é tudo o que você precisa para compartilhar algum conteúdo pelo twitter, facebook, email, sms, google+, etc.
      (Você pode customizar essa interface, observe a terceira screenshot)

      O mau

      o bom

      e o bonito

    Por hoje é só, espero que tenham gostado e fiquem ligados nos próximos artigos.

    Referências:
    [1] http://www.androiduipatterns.com/2011/07/tabs-top-or-bottom.html
    [2] https://docs.google.com/fileview?id=0BxEWAcbuDzg1MjMxYjc3MjQtNzk1Zi00YjQ4LTkxNDgtMzMxNDM0ZjU0N2I1
    [3] http://blog.tomgibara.com/post/4071726024/an-accessibility-mistake
    [4] http://www.androidpatterns.com/uap_pattern/action-bar

    What not to do in Android UI’s (or how to do it better)

    This week I’m going to talk about what NOT to do in Android UI’s (and what you can do about it).

    What inspired me to write about this was the release of a pretty successful iPhone app for Android.

    I’m talking about Viber.

    Take a look at the picture:

    So, what version of Viber am I showing here?

    Yes, it is the Android version. And with only one screenshot we already start to see the problems…
    First, it doesn’t feel like Android, it doesn’t look like Android. And it also leads me to the first point

  • Don’t do bottom tabs
    • Never do bottom tabs [1][2][3]. And these are even worse, because they are exactly the same as the iOS tabs (and remember, you are not using an iOS device)

      Tabs should be used at the top of the screen. Some times you even don’t need or want to use tabs, so you can substitute by other “Androidish” elements like a dashboard, actionbar or a combination of both and others…

      Here is an example of how an Android Viber app could be:

      Here I’ve used the actionbar [4] design pattern, with access to recent calls and messaging via the top bar.
      The contacts list is a PageViewer (like the new Market app, or the google+ app) with access to Viber contacts, all contacts and ‘Viber only’ via a horizontal swype… At the bottom there is a sliding drawer with the dialing keypad.

      This is just one possibility, another one could add the dialpad icon to the actionbar and remove the sliding drawer. Another one could use a dashboard, just like google+ does.

      But with these screenshot you can see that it looks like alot more Android.

  • Don’t put back buttons in the UI.
    • Android already has a physical BACK button, and it is mandatory. All android phones MUST have a back button (except for the Honeycomb, but it has a back button in the navigation bar), so why bother to put another back button to confuse the user?
      Related to this, never (ok, only in exceptional cases, and when you really know what you are doing) override the Back button behavior, users press the back button expecting a certain behavior, and they will be mad if if doesn’t do what they expect.

      What you can do, is to have a “home” button in the Action Bar, but it is an “UP” navigation button. It takes you to the home screen of the app and clears the backstack, so it is not going back, it is going forward.

  • Don’t reinvent the wheel (Use the Android Intent API)
    • Use the Android Intent’s API. One of the most used and common features of apps is to share content through the social networks, or via email, sms, etc… You don’t need to implement each of these interfaces for sharing, you should use Intents to share content.


      Intent sharingIntent = new Intent(Intent.ACTION_SEND);
      sharingIntent.setType("text/html");
      sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT,
      Html.fromHtml("<p>This is the text that will be shared.</p>"));
      startActivity(Intent.createChooser(sharingIntent,"Share using"));

      This is all you need to do to share some content via twitter, facebook, email, sms, google+, etc.
      (You can also customize this interface, look at the third picture)

      The bad

      the good

      and the beauty

    So that’s it for today, hope you enjoy it.

    References:
    [1] http://www.androiduipatterns.com/2011/07/tabs-top-or-bottom.html
    [2] https://docs.google.com/fileview?id=0BxEWAcbuDzg1MjMxYjc3MjQtNzk1Zi00YjQ4LTkxNDgtMzMxNDM0ZjU0N2I1
    [3] http://blog.tomgibara.com/post/4071726024/an-accessibility-mistake
    [4] http://www.androidpatterns.com/uap_pattern/action-bar

    Layout Weights – Parte 2

    No artigo anterior vimos como usar layout_weight para nos dar um controle fino sobre a forma de dispor conteúdo dentro de um layout pai. Neste artigo falaremos sobre mais alguns aspectos de layout_weights.

    Continuando de onde paramos no último artigo, há uma outra coisa que podemos fazer, e que nos dá ainda mais controle. Até agora, temos usado layout_weights para dividir proporcionalmente um layout baseado no valor total de todos os layout_weights de seus filhos. No último exemplo, os pesos foram 2 e 1, respectivamente, de modo que o total é de 3 e 2/3 do espaço vai para o primeiro e 1/3 para o segundo. Podemos sobrescrever este comportamento, adicionando um weightSum ao layout do pai:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_width="match_parent"
        android:layout_height="match_parent" android:background="#FFFF00"
        android:weightSum="4">
        <LinearLayout android:background="#FF0000"
            android:layout_height="wrap_content" android:layout_width="match_parent"
            android:layout_weight="2" />
        <LinearLayout android:background="#00FF00"
            android:layout_height="wrap_content" android:layout_width="match_parent"
            android:layout_weight="1" />
    </LinearLayout>
    

    Aqui estamos dando ao layout pai um weightSum de 4, e configurando sua cor para amarelo:

    Os layouts são divididas como antes, mas como demos ao layout pai um weightSum de 4, o layout vermelho fica com 2/4 (ou seja, metade do espaço), o layout verde fica com 1/4 (metade da área remanescente), e o layout pai (amarelo) aparece no o 1/4 inferior da tela, provando que ainda preenche toda a tela (match_parent).

    Agora vamos ver como podemos usar layout_weight de uma forma ligeiramente diferente. Suponha que queiramos um layout onde temos um cabeçalho de tamanho fixo na parte superior, um rodapé de tamanho fixo na parte inferior, e um corpo que vai se expandir no espaço restante entre o cabeçalho e o rodapé. Enquanto poderíamos fazer isso usando posicionamento absoluto (em pixels) para dispositivos individuais, com layout_weight podemos fazer isso automaticamente para todos os dispositivos:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_width="match_parent"
        android:layout_height="match_parent">
        <LinearLayout android:background="#FF0000"
            android:layout_height="50dp" android:layout_width="match_parent" />
        <LinearLayout android:background="#00FF00"
            android:layout_height="wrap_content" android:layout_width="match_parent"
            android:layout_weight="1" />
        <LinearLayout android:background="#0000FF"
            android:layout_height="50dp" android:layout_width="match_parent" />
    </LinearLayout>
    

    Aqui estamos definindo uma altura fixa para o cabeçalho e o rodapé (poderiamos utilizar wrap_content caso eles tivessem conteúdo), e estabelecendo um layout_weight na seção central da tela (cor verde). Como esse é o único “filho” com um layout_weight, ele será expandido para ocupar toda área remanescente, após os outros filhos (cabeçalho e rodapé) serem posicionados:

    Vamos concluir com outra pegadinha trabalhando com larguras de layout. Vamos mudar para um LinearLayout horizontal, contendo dois TextViews, cada um com um layout_weight a 1, mas com textos de comprimentos diferentes um do outro:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="horizontal" android:layout_width="match_parent"
        android:layout_height="match_parent">
        <TextView android:layout_height="wrap_content" android:text="s"
            android:layout_width="wrap_content" android:layout_weight="1" />
        <TextView android:layout_height="wrap_content"
            android:text="This contains some much longer text"
            android:layout_width="wrap_content" android:layout_weight="1" />
    </LinearLayout>
    

    Seria de esperar que ambos os TextView ganhassem metade do espaço na tela, mas quando executamos esse layout obtemos:

    O TextView com o texto mais longo está recebendo mais espaço na tela apesar de termos dado pesos iguais a ambos textos. Isto ocorre porque quando é feito o calculo do layout, o tamanho dos TextView são calculados com o tamanho necessário para o texto (wrap_content) e o espaço restante é dividido de forma igual entro os dois (devido ao layout_weight). Como o segundo TextView é mais amplo (devido ao seu texto maior), ele parece estar levando vantagem no calculo dos pesos dos layouts. Mas há um jeito fácil de resolver isso, basta definirmos a largura (layout_width) em ambos os TextView para “0dp” para evitar que o tamanho do texto influencie no calculo do layout:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="horizontal" android:layout_width="match_parent"
        android:layout_height="match_parent">
        <TextView android:layout_height="wrap_content" android:text="s"
            android:layout_width="0dp" android:layout_weight="1" />
        <TextView android:layout_height="wrap_content"
            android:text="This contains some much longer text"
            android:layout_width="0dp" android:layout_weight="1" />
    </LinearLayout>
    

    O espaço disponível agora é dividido igualmente entre eles, forçando o segundo TextView a ter duas linhas:

    E para finalizar, vale lembrar que layout_weight pode ser usado com outros layouts e views que estendem o LinearLayout, como por exemplo o RadioGroup.

    Este texto é uma adaptação do original Layout Weights – Part 2 de Mark Allison, feita sob a expressa autorização do autor.

    Layout Weights – Parte 1

    Existe um recurso de layout, que muitas vezes é esquecido ou ignorado, e que é extremamente poderoso e que nos permite ter um controle muito fino sobre a distribuição e a proporção de componentes na tela:
    O LinearLayout usando Layout weights (layout_weight)

    Vamos começar com um exemplo bem simples. Suponha que queiramos dividir a tela ao meio verticalmente com o layout a seguir:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_width="fill_parent"
        android:layout_height="fill_parent">
        <LinearLayout android:background="#FF0000"
            android:layout_height="match_parent" android:layout_width="match_parent" />
        <LinearLayout android:background="#00FF00"
            android:layout_height="match_parent" android:layout_width="match_parent" />
    </LinearLayout>
    

    Não deveria ser uma grande surpresa ver que o primeiro layout “filho” (com o fundo vermelho) preencheu a tela inteira, porque o seu layout_height (altura) está definido para match_parent (ocupe todo o espaço disponível)

    Poderíamos mudar o layout_height para wrap_content (ocupe somente o espaço necessário), mas isso não faria o que queremos pois os dois layouts iriam diminuir para altura (height) 0, porque eles não tem “filhos” (conteúdo, como outras views.. imageview, button, textview, etc).

    Para conseguir o que queremos (dividir a tela ao meio, lembram), podemos aplicar o parametro layout_weight em ambos os “filhos”:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_width="fill_parent"
        android:layout_height="fill_parent">
        <LinearLayout android:background="#FF0000"
            android:layout_height="match_parent" android:layout_width="match_parent"
            android:layout_weight="1" />
        <LinearLayout android:background="#00FF00"
            android:layout_height="match_parent" android:layout_width="match_parent"
            android:layout_weight="1" />
    </LinearLayout>
    

    Agora este layout faz exatamente o que queremos:

    Então, o que está acontecendo aqui? Estamos definindo cada um dos layouts “filhos” com um layout_width de match_parent (ocupe todo o espaço possível), e definindo um valor para layout_weight (ou seja, alterando o valor deste atributo do seu padrão que é 0), podemos dizer ao layout pai para dividir o espaço disponível entre os filhos. Neste exemplo, atribuímos o mesmo valor para de layout_weight para ambos os filhos, e será dada uma parte igual do espaço disponível a cada um deles.

    Se quisermos dividir o espaço do layout “pai” em partes iguais, basta setar o layout_weight de todos os filhos (nesse casa são novos LinearLayout’s, mas poderiam ser Buttons, ImageViews, TextViews, etc…) para 1. Agora, se queremos dividi-los de forma desigual, podemos fazer isso de diversas maneiras. Podemos usar números fracionários que somem 1, ou podemos usar valores inteiros:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_width="fill_parent"
        android:layout_height="fill_parent">
        <LinearLayout android:background="#FF0000"
            android:layout_height="fill_parent" android:layout_width="fill_parent"
            android:layout_weight="0.66667" />
        <LinearLayout android:background="#00FF00"
            android:layout_height="fill_parent" android:layout_width="fill_parent"
            android:layout_weight="0.33333" />
    </LinearLayout>
    

    ou

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_width="fill_parent"
        android:layout_height="fill_parent">
        <LinearLayout android:background="#FF0000"
            android:layout_height="fill_parent" android:layout_width="fill_parent"
            android:layout_weight="2" />
        <LinearLayout android:background="#00FF00"
            android:layout_height="fill_parent" android:layout_width="fill_parent"
            android:layout_weight="1" />
    </LinearLayout>
    

    Ambas irão produzir o mesmo resultado:

    Espere um segundo. Enquanto certamente estamos vendo uma divisão de dois terços, nós demos ao layout vermelho um peso maior do que ao verde, então esperaríamos ver o vermelho ocupando dois terços do espaço disponível.
    Além disso, quando se joga com “pesos” de layout às vezes é possível ver as coisas funcionando como esperamos, e como vimos aqui. Esta é uma pegadinha comum com layout_weight, e a chave aqui é nós instruímos ambos os layouts filhos a tentar preencher o “pai” (usando layout_height = “match_parent“), e isso faz com que o comportamento seja o oposto do desejado. Nós podemos reverter esse comportamento alterando os layouts filhos setando layout_height = “wrap_content“:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_width="match_parent"
        android:layout_height="match_parent">
        <LinearLayout android:background="#FF0000"
            android:layout_height="wrap_content" android:layout_width="match_parent"
            android:layout_weight="2" />
        <LinearLayout android:background="#00FF00"
            android:layout_height="wrap_content" android:layout_width="match_parent"
            android:layout_weight="1" />
    </LinearLayout>
    

    E agora sim vemos o que estavamos esperando:

    Na segunda parte deste artigo veremos mais alguns truques que podemos fazer com layout_weights, e claro, mais algumas pegadinhas.

    Este texto é uma adaptação do original Layout Weights – Part 1 de Mark Allison, feita sob a expressa autorização do autor.

    HierarchyViewer

    O hierarchyviewer é uma ferramenta impressionante e muito útil para desenvolvedores android, que eu quase não uso(usava), pois ela necessita ou de um “developer phone (com developer build)” ou rodar a aplicação no emulador (que é incrivelmente lento, pesado e chato de trabalhar…)

    Mas, alguns dias atrás o googler Romain Guy (@romainguy – sigam ele…) postou no twitter esse código, habilitando o uso do hierarchyviewer em seu aparelho pessoal, pretty amazing hmm…

    Certo, mas o que é o hierarchyviewer afinal???
    “Hierarchy Viewer lhe permite debugar (sic) e otimizar sua interface de usuário. Ele prove uma representação visual da hierarquia das ‘Views’ do seu ‘layout’ (Layout View) e um inspetor ampliado da tela da aplicação (Pixel Perfect View).

    O HV mostra a representação em forma de “Arvore” do seu layout (lembre-se que ele é um xml com um root node e vários filhos) além de trazer algumas informações muito uteis, como o tempo de gasto com “Measure, Layout, Draw”. Com essa informação você pode ter uma ideia do que está deixando a sua interface pesada, por exemplo…

    Já no “Pixel Perfect” você tem uma visão magnificada da tela do aplicativo, onde você pode conferir questões de layout/design como espacamentos, cores, etc…

    Certo, mas como fazer para usar essa maravilha toda????

    Primeiro precisamos importar o ViewServer.java em nosso projeto.

    Depois disso é bem simples, basta em cada Activity do seu projeto chamar addWindow() no onCreate, setFocusedWindow() no onResume e removeWindow() no onDestroy

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            ViewServer.get(this).addWindow(this);
        }
    
        @Override
        public void onResume() {
            super.onResume();
            ViewServer.get(this).setFocusedWindow(this);
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            ViewServer.get(this).removeWindow(this);
        }
    

    Feito isso, basta rodar o aplicativo com o celular plugado no PC e rodar o hierarchyviewer (android-sdk/tools/hierarchyviewer)

    Já ia quase esquecendo, outra ferramenta interessante do HV é a possibilidade de exportar seu layout em um arquivo .psd (Photoshop) onde cada view do seu aplicativo é um layer separado, muito útil para utilizar para ajustes finos e testes no PS antes de voltar ao .xml e modificar seu app.