sexta-feira, 12 de fevereiro de 2016

Dominando o Android 2 edição: correções e melhorias

Olá povo,

Quem me vê no dia a dia, sabe que eu ando com um exemplar do meu livro o tempo todo. Além de utiliza-lo como forma de consulta, eu saio anotando nele:
  • as novidades em APIs que saíram após o lançamento do livro; 
  • novos tópicos para colocar em versões futuras; 
  • e obviamente erros que os leitores vão reportando. 
Na primeira edição, o exemplar que eu andava foi muito útil para melhorar a segunda edição, mas quase que eu perco o livro quando ele caiu em uma poça d'água! o.O
Por isso resolvi compartilhar com vocês minhas anotações, assim vocês já vão sabendo o que está errado, o que já mudou em termos de API, e o que pode mudar para a próxima ;) A medida que for achando mais problemas, vou atualizando esse post.
Ah! Antes que vocês perguntem, não tem nenhuma previsão para a próxima edição. Mas provavelmente o que vai acontecer é eu começar a trabalhar no livro após o Google I/O desse ano que vai acontecer entre 18 e 20 de maio.
Segue abaixo o que eu anotei até agora. Eu dividi em duas categorias: melhorias e erros.

Melhorias

Capítulo 0 / Pág. 29 - essa seção deve receber uma atualização com as novidades do emulador 2.0.
http://tools.android.com/tech-docs/emulator

Capítulo 3 - vou adicionar mais uma seção nesse capítulo falando dos layouts percentuais PercentFrameLayout e PercentRelativeLayout que eu falei nesse post aqui.

Capítulo 4 / Pág. 132 - esqueci de falar de uma propriedade bacana do TextInpuLayout que mostra a quantidade de caracteres digitados.
http://developer.android.com/reference/android/support/design/widget/TextInputLayout.html#setCounterEnabled(boolean)
<android.support.design.widget.TextInputLayout
    ...
    app:counterEnabled="true">
    <EditText
        ...
        android:maxLength="100"/>

Capítulo 4 / Pág. 163 - esqueci de mencionar que o método performFiltering() é executado em uma thread separada, enquanto que o método publishResults() é executado na UI thread.

Capítulo 6 / Pág. 254 - deveria ter criado um estilo para a Toolbar.

Capítulo 7 / Pág. 297 - era para ter enfatizado que, se uma classe implementar OnPreferenceChangeListener, caso uma SharedPreference seja modificada em qualquer ponto da aplicação, essa classe será notificada (obviamente se ela estiver instanciada).

Capítulo 7 / Pág. 310 - o trecho do método onClick() deveria estar em negrito.

Capítulo 7 / Pág. 325 - deveria estar realizando as operação com o ContentProvider utilizando a classe AsyncQueryHandler como falei nesse post aqui.

Capítulo 10 / Pág. 388 - substituir a enum Status por annotations como falei nesse post.

Capítulo 14 / Pág. 473 - no método onMessageReceived(), checar se from.equals(senderId) e se !data.isEmpty().

Capítulo 15 / Pág. 519 - o método getMap() tornou-se obsoleto (deprecated), em seu lugar, deve-se usar o método getMapAsync().
https://developers.google.com/android/reference/com/google/android/gms/maps/SupportMapFragment.html#getMapAsync(com.google.android.gms.maps.OnMapReadyCallback)

Capítulo 15 / Pág. 551 - podemos enviar localização fictícia com o emulador 2.0 do Android ou com o Genymotion.

Capítulo 20 - Falar sobre TransitionManager. Depois de ver essa palestra do Lúcio Maciel, me arrependi de não ter colocado esse assunto nesse capítulo.
https://www.youtube.com/watch?v=GKjPf0NI9ps

Capítulo 23 - Muitos fundamentos interessantes que são mostrados no treinamento de Gradle do Udacity seriam interessantes de colocar no livro. Principalmente linha de comando.
https://www.udacity.com/course/gradle-for-android-and-java--ud867

Capítulo 26 / Pág. 843 - Colocar alguns detalhes interessantes no uso da RecyclerView que eu coloquei nesse post.

Capítulo 26 / Pág. 891 - A biblioteca Otto foi recentemente marcada como deprecated em favor do RxJava e RxAndroid. Mas não se preocupem, o Otto continua funcionando. Uma outra opção seria usar o EventBus.

Capítulo 27 - Colocar um exemplo de DataBinding com listas.
http://developer.android.com/intl/pt-br/tools/data-binding/guide.html


Erros

Capítulo 1 / Pág. 39 e 49 - Quando falo das pasta res/mipmap eu menciono quatro pastas, quando na verdade são 5.

Capítulo 2 / Página 81 - Ao girar a activity sem selecionar um estado, o texto do botão fica em branco. Para contornar isso, basta colocar o código a seguir no onCreate.

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    if (savedInstanceState != null) {
        estado = savedInstanceState.getString(STATE_ESTADO);
        if (estado != null) botaoEstado.setText(estado);
    }
}

Capítulo 3 / Pág. 110 - a biblioteca de compatibilidade do GridLayout é melhor do que a versão nativa, pois ela teve vários bugs corrigidos.
http://developer.android.com/tools/support-library/features.html#v7-gridlayout
Basta adicionar a dependência no build.gradle.
compile 'com.android.support:gridlayout-v7:+'
E no layout modificar para
<android.support.v7.widget.GridLayout ...

Capítulo 5 / Pág. 170 - a figura 5.6 está errada... ela deveria estar mostrando as marcações na ferramenta draw9patch. Ao invés disso está mostrando o GIMP :P

Capítulo 6 / Pág. 212 - No último parágrafo, a primeira frase deve ser "... o parâmetro savedInstanceState é igual a nulo, ..."

Capítulo 6 / Pág. 255 - o exemplo está com problema na Toolbar quando rodamos a aplicação no KitKat. A correção do bug já está no GitHub nesse commit aqui. E eu fiz até um vídeo explicando a solução :)

Capítulo 10 / Pág. 385 - na definição da tabela Hotel, o campo "estrelas" deve usar o tipo DECIMAL(2,1). Essa modificação já está no GitHub.
https://github.com/nglauber/dominando_android2/blob/master/server/hotel_service/webservice.php

Capítulo 14 / Pág. 511 - no último parágrafo, falei que após o realizar o login com a conta do Google, uma boa opção seria utilizar o ID da conta e enviar para o seu serviço web. Mas a solução recomendada pelo Google é o uso do Token.
http://android-developers.blogspot.com.br/2016/01/using-google-sign-in-with-your-server.html

Capítulo 24 / Pág. 764 - a figura 24.8 ficou "estranha".

Capítulo 25 / Pág. 839 - esse foi o pior erro do livro. Ficou faltando praticamente uma página.
Notei que um trecho grande do capítulo 26 (1ª impressão) acabou ficando de fora do livro. Creio que foi no momento da diagramação do livro na editora. Na página 839, no segundo parágrafo, após o texto "... que estamos executando." deveria vir o texto abaixo:

Biblioteca 1: ButterKnife
O ButterKnife (http://jakewharton.github.io/butterknife/) é um biblioteca desenvolvida por Jake Wharton (Google Developer Expert de Android) que facilita a atribuição de views à classes sem precisar utilizar o método findViewById(int).
Vejamos o exemplo a seguir:
public class MainActivity extends Activity {
  @Bind(R.id.txtTitulo) TextView mTxtTitulo;
  @Bind(R.id.edtNome) EditText mEdtNome;
  @Bind(R.id.listview) ListView mListPessoas;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ButterKnife.bind(this);
    // Pronto! Pode usar os atributos!
  }
}
Perceba que anotamos os atributos da classe que representam componentes no arquivo de layout com a anotação @Bind(int) passando o id do componente. No método onCreate(Bundle) inicializamos esses atributos simplemente invocando ButterKnife.bind(this). O ButterKnife também funciona em Fragments e Adapters como veremos mais adiante. Essa biblioteca ainda possui outros recursos interessantes como definir evento de clique em botões.
@OnClick(R.id.botao1)
public void onClickBotao1(View view) {
}

@OnClick(R.id.botao2)
public void onClickBotao2() {
}
Perceba que no evento de clique do segundo botão, não colocamos o parâmetro, pois para a biblioteca ele é opcional. Vamos utilizar o ButterKnife em nosso aplicativo. Para isso, adicione a dependência no build.gradle.
dependencies {
    …
    compile 'com.jakewharton:butterknife:7.0.1'
}

Biblioteca 2: OkHttp
No capítulo 8 vimos como acessar um servidor web utilizando a classe HttpUrlConnection. Ela funciona muito bem, o único incoveniente é quando precisamos ler o retorno do servidor,

x.x.x.x.x.x.x.x.x.x.x

Peço desculpas pelo inconveniente, mas pelos menos agora vocês vão entender porque o texto está maluco :)
------------------

Quero deixar meu muito obrigado a todos os leitores que reportam os erros encontrados no livro. E se você adquiriu ou livro, não se esqueça de se cadastrar no grupo de discussão da segunda edição do "Dominando o Android".

4br4ç05,
nglauber

14 comentários:

Kiko disse...

Se segui corretamente as instruções, à página 62, ao final do parágrafo que inicia como "No onCreate(Bundle)", há o texto ..."com o seu o arquivo de layout apenas com o 'Hello World', porém o erro é que não há esse Hello World porque foi utilizada uma Empty Activity.

Nelson Glauber disse...

Oi Kiko,

Muito obrigado pela observação! É que em versões anteriores do Android Studio, mesmo a Empty activity exibia o texto "Hello world". Desculpe pelo inconveniente e corrigirei para a próxima edição/impressão do livro.

Se achar mais problemas, posta lá no grupo de discussão do livro ;)

4br4ç05,
nglauber

Max Schrappe disse...

Olá,

Na página 274 faltou a referência ao tema da ActivitySpinner no AndroidManifest.xml, o que causa um efeito indesejado no menu que não é exibido corretamente e passa a ser parcialmente oculto pela barra de status do aparelho.

O código completo:


Israel Tavares disse...

Nelson, em seu livro no capitulo da WebService, se eu quisesse colocar o ip da minha conta que tenho da Hostgator da cpanel pessoal, o processo seria o mesmo? (Colocar o meu ip,talz?)

Nelson Glauber disse...

oi Israel,

Desculpa a demora em responder... mas seria sim :)

4br4ç05,
nglauber

Israel Tavares disse...

Olá, Glauber... Me desculpe pela persistencia em meu nome estar nesta lista de duvidas rsrs...
É uma pequena coisa que nao funciona. Adaptei o seu codigo do WebService de cadastramento de Hotéis para outro teste, e adaptei juntamente com meu codigo php sobre o inserir,atualizar e deletar, para ver se através do site, ao inserir,atualizar e deletar, modifica "remotamente" ao aplicativo conectado na lista de Hotéis. O engraçado, a unica função que nao funciona corretamente é o de DELETAR. Apago diretamente do site, mas na lista do aplicativo de Hoteis nao é apagada remotamente. Só é apagada no proprio site e no meu Banco de Dados. O que é preciso para essa função funcionar corretamente? Tentei modificar varias e varias vezes a logica a função do Apagar no IDE Android Studio, mas nada funciona. Como eu disse antes, só funciona o inserir,e atualizar. Exceto o Deletar... Entende a minha duvida? rs

RESUMO
-Se deleto um nome do Hotel cadastrado do aplicativo, o nome do Hotel da lista no SITE é apagada normalmente.(NORMAL,funcionando perfeitamente);
-Se deleto um nome do Hotel cadastrado do SITE, o nome do Hotel da lista no APLICATIVO nao é deletado. (Não funciona)

Fiz abaixo só um pequeno passo e simples para te mostrar diante do meu codigo php para o DELETE para ver se tem algo errado, mas acho que nao tem nada ver. Acho que é mais a ver com o codigo da IDE Android Studio mesmo que tá faltando algo.

query($sql);

header("Location: index.php");

} else {
header("Location: index.php");
}
?>

Nelson Glauber disse...

Oi Israel,

Quando você exclui o hotel no seu webservice como você está avisando a aplicação mobile para excluir o registro localmente? via GCM/FCM?
Ou você está dizendo que mesmo excluindo no servidor e sincronizando os dados do app com o servidor o registro não é excluído?
Se puder, compartilha o código com as etapas que você está fazendo que assim que puder dou uma olhada.

4br4ç05,
nglauber

www.areapirataria.net disse...

Oi Glauber,

Isso mesmo, "Ou você está dizendo que mesmo excluindo no servidor e sincronizando os dados do app com o servidor o registro não é excluído?"

Só não é excluido na lista de Hotéis no APLICATIVO... só no servidor que mostra como excluido ...

Tudo o que funciona é o Inserir e Atualizar do acionando do Servidor para o Aplicativo... menos o Excluir....
O código que utilizei foi todo igual da WebService do seu livro 2ª edição, aliás baixei pelo GitHub o codigo pronto, mas deu no mesmo.

AQUI ESTÁ O LINK PARA BAIXAR A IMAGEM:
https://mega.nz/#F!puBy2bjY!U_BPJLdguO5FrQDcF5CVXQ

Nelson Glauber disse...

Oi Israel,

Muitíssimo obrigado! Era realmente um bug. =(
Acabei de corrigir e postei o código no GitHub. As alterações estão nesse commit:
https://github.com/nglauber/dominando_android2/commit/97085999dd6dcd14377ddcd975c0704098886cd6

4br4ç05,
nglauber

Israel Tavares disse...

Meu caro, eu que agradeço, tudo funfando! Muito obrigado! Jesus Cristo o abençoe!!! =]

Israel Tavares disse...

Glauber,boa tarde, o que fazer quando aparecer esse erro: "Error:Configuration with name 'default' not found." ao abrir um projeto? No caso eu abri o Projeto HTTP do cap. 8, do assunto sobre Volley etc... Qual procedimento?

Nelson Glauber disse...

Oi Israel,

Desculpa a demora em responder, isso normalmente acontece pq o arquivo "*.iml" não existe ou está com outro nome. Isso está impedindo o exemplo de executar?

4br4ç05,
nglauber

Israel Tavares disse...

Oi Glauber, o arquivo ".iml" ta igual. Felizmente, dei uma pesquisada no site do Android Developer, e só fiz substituir "compile project(':volley')" por "compile 'com.android.volley:volley:1.0.0' " , E voltou ao normal. Só que o estranho é que as Imagens diante da lista dos livros, não aparecem... (Lembrando que o arquivo é o mesmo do seu Repositorio, só fiz abri-lo para testar) Alguma sugestão?

Nelson Glauber disse...

Oi Israel,

Ainda bem que resolveu. O problema com as imagens é que a novatec mudou o endereço das imagens dele. Eu atualizei o caminho das imagens no GitHub. Tenta baixar o código novamente e vê se funciona.

4br4ç05,
nglauber