Usuários de
aplicativos em geral podem requerer mudar a orientação do aparelho
para visualizar melhor os conteúdos sendo exibidos na tela.
Dependendo do que está sendo visto é comum girar a orientação da
tela para o sentido horizontal (landscape) ou sentido vertical
(portrait).
(1) Tela em modo Portrait |
Em aplicações Android
e iOS (smartphones e tablets) é comum implementar telas que vão
funcionar em diferentes perspectivas de orientação de tela. No
entanto, programadores de Android precisam estar atentos que quando
ocorrem mudanças de orientação no aplicativo, o comportamento
padrão do Android recria a Activity em execução, chamando os
métodos do ciclo de vida: onPause(), onStop(), onDestroy(), para em
seguida chamar o método onCreate() novamente, além dos métodos do
ciclo de vida: onStart() e onResume().
Problema / Solução
Se a tela atual da
sua aplicação apenas desenha elementos visuais sem obter dados de
fontes custosas (para memória em geral ou uso da Internet para
baixar os dados), então esse procedimento padrão do Android não
será um problema. Contudo, caso sua Activity requeira dados da
internet ou algum outro tipo de esquema de processamento “mais
pesado” para ser realizado, talvez seja necessário evitar
recarregar a instância da Activity, mantendo o estado dos objetos
carregados na memória. Desta forma podemos evitar consultar a rede
novamente, além de otimizar o uso do processamento do aparelho,
melhorando o consumo da bateria. :)
Esse comportamento pode
ser realizado de 2 formas: (que eu conheço)
- Salvar os dados atuais (o estado atual) utilizando o mecanismo do ciclo de vida da Activity do Android, através dos métodos onSaveInstanceState(bundle) para salvar, e o onRetainNonConfigurationInstance() para recuperar os dados do estado atual;
- Alterar o comportamento default do Android, descrito acima, evitando que a Activity seja automaticamente recriada. Desta forma o Android apenas irá notificar Activity que ocorreu uma mudança de orientação, através do método onConfigurationChanged(Configuration c).
Neste post vou mostrar
como podemos implementar abordagem (2), ou seja, como evitar que o
Android recrie Activity do ciclo de vida do aplicativo.
Essa dica eu encontrei
no site oficial do desenvolvedor Android. Está neste link: Handling
Runtime Changes:
http://developer.android.com/guide/topics/resources/runtime-changes.html
Vou descrever passo a
passo:
Passo 1: altere o
arquivo AndroidManifest.xml conforme o exemplo abaixo adicionando a
propriedade chamada (android:configChanges="orientation|screenSize")
da sua Activity:
Passo 2: implementar no
código Java da sua Activity o método conforme exemplo:
package br.com.blogspot.profdouglas.dicas3.orientationchange; import android.app.Activity; import android.content.res.Configuration; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.widget.TextView; public class OrientationChange extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_orientation_change); Log.d("DOUGLAS", "OrientationChange.onCreate"); TextView orientationTextView = (TextView) findViewById(R.id.orientationTextView); // detect the current orientation int currentOrientation = getResources().getConfiguration().orientation; if (currentOrientation == Configuration.ORIENTATION_LANDSCAPE) { // setting orientation landscape orientationTextView.setText(R.string.orientation_landscape); } else if (currentOrientation == Configuration.ORIENTATION_PORTRAIT) { // setting orientation portrait orientationTextView.setText(R.string.orientation_portrait); } } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_orientation_change, menu); return true; } @Override protected void onStart() { super.onStart(); Log.i("DOUGLAS", "OrientationChange.onStart"); } @Override protected void onResume() { super.onResume(); Log.i("DOUGLAS", "OrientationChange.onResume"); } @Override protected void onStop() { super.onStop(); Log.i("DOUGLAS", "OrientationChange.onStop"); } @Override protected void onPause() { super.onPause(); Log.i("DOUGLAS", "OrientationChange.onPause"); } @Override protected void onDestroy() { super.onDestroy(); Log.i("DOUGLAS", "OrientationChange.onDestroy"); } /** * Caution: Beginning with Android 3.2 (API level 13), the "screen size" * also changes when the device switches between portrait and landscape * orientation. Thus, if you want to prevent runtime restarts due to * orientation change when developing for API level 13 or higher (as * declared by the minSdkVersion and targetSdkVersion attributes), you must * include the "screenSize" value in addition to the "orientation" value. * That is, you must decalare * android:configChanges="orientation|screenSize". However, if your * application targets API level 12 or lower, then your activity always * handles this configuration change itself (this configuration change does * not restart your activity, even when running on an Android 3.2 or higher * device). */ @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); Log.d("DOUGLAS", "MainActivity.onConfigurationChanged"); TextView orientationTextView = (TextView) findViewById(R.id.orientationTextView); if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { Log.i("DOUGLAS", "MainActivity.onConfigurationChanged (ORIENTATION_PORTRAIT)"); // setting orientation portrait orientationTextView.setText(R.string.orientation_portrait); } else if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) { Log.i("DOUGLAS", "MainActivity.onConfigurationChanged (ORIENTATION_LANDSCAPE)"); orientationTextView.setText(R.string.orientation_landscape); } } }
Observe o javadoc que
deixei para que você entenda porque a propriedade do manifest
precisou utilizar dois valores. A figura (2) demonstra o log (da view LogCat) demonstrando que a Activity não foi recriada, mas o método onConfigurationChanged foi notificado.
(2) Tela em modo Landscape sem recriar a Activity após mudar orientação |
Conclusão
Ao executar seu
aplicativo agora, quando ocorrer mudanças de orientação de tela sua Activity não será recriada e o método onConfigurationChanged
será automaticamente notificada a cada mudança de orientação.
Como sugestão, caso queira fazer algo específico para cada modo de
orientação, pode-se usar a lógica da condição implementada no método, que atualmente possui instruções com
logs. Dependendo do cenário no qual seu aplicativo está sendo
usado, essa dica pode ser útil para você.
Assim que possível vou
fazer uma vídeo aula sobre isso também e colocar aqui. O código
fonte do exemplo do projeto pode ser baixado aqui.