Chegaram 4 novos estagiários aqui no projeto e coube "a minha pessoa" orientá-los. Durante a aula, o assunto enveredou para tratamento de mudança de orientação do aparelho (portrait e landscape | retrato e paisagem).
Por padrão, ao girar o telefone o método onCreate é chamado novamente e com isso, dados que foram carregados dinamicamente (como itens de um ArrayList que estão preenchendo um ListView) são perdidos.
Vejamos o exemplo abaixo:
Arquivo de layout.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:background="#0000FF"> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Digite o nome" /> <EditText android:id="@+id/editText1" android:layout_width="fill_parent" android:layout_height="wrap_content"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="meuBotaoClick" android:text="Adicionar" /> <ListView android:id="@+id/listView1" android:layout_width="fill_parent" android:layout_height="fill_parent" /> </LinearLayout>
Classe da Activity
public class TelaPrincipalActivity extends Activity { EditText edt; ArrayList<String> nomes; ArrayAdapter<String> adapter; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); edt = (EditText) findViewById(R.id.editText1); ListView listView = (ListView) findViewById(R.id.listView1); adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, nomes); listView.setAdapter(adapter); } public void meuBotaoClick(View v) { nomes.add(edt.getText().toString()); edt.setText(""); adapter.notifyDataSetChanged(); } }
No código acima, ao clicar no botão, o texto digitado no EditText é inserido na lista, e em seguida o adapter é atualizado através do método notifyDataSetChanged.
O exemplo é bem simples, mas se você girarmos o aparelho os dados que estão sendo exibidos são perdidos, uma vez que a lista inicia vazia e (como já falei) o onCreate é chamado novamente.
Para isso não acontecer você tem 3 alternativas:
1)Forçar uma orientação
Na declaração da sua Activity, no AndroidManifest.xml, você pode usar a propriedade android:screenOrientation para manter sua aplicação em uma orientação específica (portrait/landscape).
<activity android:name="TelaPrincipalActivity" android:screenOrientation="portrait" />
2)Avisar o Android para não chamar o onCreate
Essa é a melhor opção quando você quer utilizar a tela nas duas orientações e impedir que o Android chame o onCreate cada vez que você girar o aparelho. Para isso basta dizer que ao mudar a configuração (configChanges) de orientação, ele não recrie a Activity.
<activity android:name="TelaPrincipalActivity" android:configChanges="orientation|keyboardHidden|screenSize"/>
3) Salvar o estado da Activity
A opção número dois é perfeita quando você quer usar o mesmo layout nas duas orientações. Mas, e se eu quiser usar layouts diferentes? Neste caso você dever permitir que a Activity seja recriada. Entretanto, devemos salvar seu estado com o método onSaveInstanceState e no onCreate recuperar esse estado.
No exemplo que fiz os "estags", criei a pasta "layout-land" com o mesmo layout definido acima, só mudando o background (apenas para notarmos os diferentes layouts). Depois implementamos o método onSaveInstanceState para salvar os itens da lista.
@Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putStringArrayList("nomes", nomes); }
Se vocês notaram, o método onSaveInstanceState usa um objeto da classe Bundle para salvar o estado. Esse estado é passado para o método onCreate da Activity como parâmetro, que utilizaremos para restaurar o seu estado.
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Código já apresentado if (savedInstanceState != null) { nomes = savedInstanceState. getStringArrayList("nomes"); } else { nomes = new ArrayList<String>(); } }
Com isso podemos ter, para a mesma tela, um layout diferente para cada orientação, desde que tenhamos os mesmos componentes (e com os mesmos ids).
Ficou com dúvida? Deixe seu comentário.
4br4ç05,
nglauber
Ótimas dicas sobre orientação. Essa postagem me ajudou a resolver uma CR =D
ResponderExcluirAchei bastante interessante a abordagem, muito útil. Mas estou com uma certa dúvida na hora de armazenar os valores de uma matriz, qual seria a função para isso?
ResponderExcluirPerfeito!!
ResponderExcluirEstava procurando exatamente o que você escreveu!!
Parabéns.
muito obrigado por ter me ajudado com a dica da orientacao, caso tenha algum tutorial sobre bluetooth ta agradeceria muito.
ResponderExcluirOi Anônimo,
ResponderExcluirEscrevi um artigo para a revista Mobile Magazine (http://nglauber.blogspot.com/2011/04/artigo-comunicacao-via-bluetooth-no.html).
Mas você pode achar um exemplo no próprio diretório do SDK.
4br4ç05,
nglauber
Excelente Glauber, foi muito útil para mim.
ResponderExcluirExcelente tutorial, parabéns! Era exatamente o que eu estava procurando... me ajudou muito
ResponderExcluirExcelente tutorial, sem dúvidas vai me ajudou muito!
ResponderExcluirSó tenho uma dúvida:
No exemplo, você usou um único layout, e criou a pasta para o layout em paisagem, o "/layout-land". Já no meu caso estou trabalhando com quatro pastas: "layout", "layout-large", "layout-small" e "layout-xlarge". No meu caso, como devo nomear as pastas para layout pasagem? Seria "/layout-small-land", por exemplo?
Obrigado desde já. Seu blog é otimo!
Oi Rodrigo,
ResponderExcluirVocê pode encontrar a resposta aqui:
http://developer.android.com/guide/topics/resources/providing-resources.html
Segundo a documentação, o tamanho vem antes da orientação. Então fica layout-small-land, por exemplo.
4br4ç05,
nglauber
Perfeito!!!
ResponderExcluirFaz um tempão que eu estava procurando a solução numero 2!!!
Parabens e obrigado!!!
Oi Nelson, gostaria de saber se é possível colocar em um mobile site html uma função script que não deixe o tablet/smartphone girar, deixar ele sempre em portrait?
ResponderExcluirObrigado.
Oi Maurício,
ResponderExcluirVocê não tem um controle tão grande sobre o browser do Android (pelo menos não que eu saiba). Mas você pode saber quando a orientação mudou e tomar alguma ação. O jQuery Mobile, por exemplo, dá esse suporte.
4br4ç05,
nglauber
Valeu! Mto boa ajuda
ResponderExcluirBom eu gostei muito dessa postagem, eu usei na minha aplicação e funcionou quanto eu utilizei smartphone,
ResponderExcluirmais quando eu utilizei tablets não funcionou, tem como me ajudar para funcionar em tablets.
Oi Enzo,
ResponderExcluirQual foi o problema?
4br4ç05,
nglauber
cara ajudou muito!!! usei quase tudo na minha aplicação..
ResponderExcluirobrigado e parabens!
Vlw ,
ResponderExcluirMe ajudou bastante
Quando uso a opção 2 da problema, oque pode ser?
ResponderExcluirOi joão paulo,
ResponderExcluirQual é o problema??
4br4ç05,
nglauber
Estou criando um APP que mostra a galeria de vídeo da minha página do Wordpress. O APP roda direitinho mas quando mudo a orientação de Retrato para Paisagem o vídeo recarrega novamente. Li seu tutorial só que no exemplo você fez a recuperação com String. Como ficaria a recuperação para os vídeos continuarem de onde estavam, quando giramos a tela?Utilizo WebView. .
ResponderExcluirOi Sérgio,
ResponderExcluirO seu caso é uma exceção mesmo. Como é uma Webview e é um vídeo, é melhor utilizar a solução número 2 e seguir essas recomendações aqui.
https://developer.android.com/guide/topics/resources/runtime-changes.html
4br4ç05,
nglauber