Solucionado (ver solução)
Solucionado
(ver solução)
15
respostas

Mudando o layout para o modo paisagem

Estou tentando utilizar um layout em modo paisagem em outro app e preciso que ele não execute o método onCreate ao rotacionar, essa Activity só possuí Buttons e TextViews.

Declarei no manifest na tag da activity: android:configChanges="orientation", rotaciona sem executar o onCreate, mas o layout permanece o mesmo.

Tentei usar o método onSaveInstanceState, mas acho que de maneira incorreta. Se alguém puder dar uma explicação de como usar método nesse caso seria ótimo.

Obrigado.

15 respostas

Oi Marcos, tudo bem? Vejamos se eu entendi a sua dúvida, você está tentando usar um layout tanto como portrait tanto como landscape, porém, você quer que o onCreate seja chamado apenas uma única vez independentemente da orientação e, além disso, você quer manter o estado utilizando o onSaveInstanceState?

Se for isso, me fale se é em uma Activity ou Fragment que você está tentando fazer.

Tudo bem. Vamos lá, é em uma Activity, tenho os dois layouts portrait e landscape, os dois layouts possuem as mesmas views, só muda algumas posições e tamanhos, o onCreate só precisa ser chamado uma vez. Sobre o método onSaveInstanceState, acredito que seja a única maneira de fazer, mas não estou conseguindo.

Sobre o primeiro problema, tente alterar o android:configChanges para:

android:configChanges="orientation|screenSize"

Pois quando você altera muda a rotação para landscape, você também modifica o tamanho da tela, por isso precisa do screenSize também.

Pelo o que eu entendi, você quis dizer que só resolveria esse problema usando o onSaveInstanceState, então, eu compreendo que esteja resolvido, certo? Ou ainda falta mais uma coisa?

Já fiz o teste acrescentando screenSize e alguns outros parâmetros, ele rotaciona, não chama o onCreate, mas continua usando o mesmo layout. Sobre o método onSaveInstanceState, gostaria de saber como usar.

Marcos,

minha primeira sugestão para resolver seu problema é:

Não use configChanges.

Quando usamos esse atributo em alguma activity, dizemos para o Android que nossa activity será responsável por tratar alterações de orientação (nesse caso) do aparelho. Ou seja, perdemos qualquer auxílio do Android quando o aparelho rotaciona.

O primeiro reflexo disso é: o onCreate na activity, de fato, não é chamado.

O problema disso é que justamente no onCreate o Android seta automaticamente o layout correto de acordo com a orientação do aparelho.

Logo, se o onCreate não é chamado, seu layout não é alterado automaticamente. Causando esse bug que você está vendo.

Para resolver seu problema...

Caso você tenha dois layouts diferentes:

Crie um layout (normal) na pasta res/layout. Crie outro layout (que será exibido com o aparelho horizontal) na pasta res/layout-land.

Quando o onCreate for chamado, o Android colocará o layout correto na tela e você poderá usar seus componentes (fazendo um findViewById antes).

Caso você tenha apenas um layout:

Ao rotacionar a tela o Android chamará o onCreate e tudo funcionará normalmente. Basta seu layout estar na pasta res/layout.

Um detalhe importante nesse tópico que estou curioso desde o começo é, por qual motivo você não quer que chame o onCreate? Provavelmente, existem soluções mais viáveis para resolver a sua necessidade sem causar os problemas que o Felipe mencionou.

Então, nessa activity imagine um contador, no onCreate dela eu seto um nome para ele por um AlertDialog, depois disso na Activity os Buttons setam valores nesse contador, quando rotaciono a tela ele abre o AlertDialog e zera o contador, chamando o onCreate. Acho que deu pra explicar, basicamente é isso.

solução!

Entendi o problema, uma possível solução é o seguinte, a partir do Bundle recebido no onCreate() podemos verificar se algum valor existe a partir de uma chave, portanto, inicialmente, podemos verificar se existe a chave "numero". Por exemplo:

    private int numero;

   @Override
    protected void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        if(bundle != null && !bundle.containsKey("numero")){
            //inicializa o número nesse caso iniciei com 0 como exemplo.
            numero = 1;
        }
    }

Veja que dentro do onCreate() verificamos se o bundle é null e, ao mesmo tempo, verificamos se ele não contém a chave "numero", caso esse teste dê certo, significa que não temos algum número salvo, ou seja, podemos inicializá-lo, nesse exemplo eu coloquei o valor 0, no seu caso, você adiciona o valor inicial que desejar. Note também que estou utilizando um atributo para armazenar esse valor, justamente para que ele possa ser utilizado nos outros métodos da Activity que salva e recupera o valor.

Então, adicionamos o método onSaveInstanceState:

     @Override
    protected void onSaveInstanceState(Bundle bundle) {
        super.onSaveInstanceState(bundle);
        //Assim que rotacionar ou acontecer qualquer evento que reinicie a activity
        //Vai salvar o atributo numero com a chave "numero"
        bundle.putInt("numero", numero);
    }

A partir desse método, antes que a Activity seja reiniciada ou destruída, o atributo numero será salvo a partir da chave "numero". Mas aí, como recuperamos esse valor? Simples! Basta implementar o método onRestoreInstanceState:

    @Override
    protected void onRestoreInstanceState(Bundle bundle) {
        super.onRestoreInstanceState(bundle);
        //você verifica se o bundle existe, caso sim, você verifica se tem essa chave "numero"
        //Se tiver, você atribui o valor do inteiro por meio da chave "numero"
        if (bundle != null && bundle.containsKey("numero")){
            //Dessa forma você recupera o valor que estava anteriormente
            numero = bundle.getInt("numero");
        }
    }

A partir desse método todas as vezes que a activity for reiniciada, ele será chamado, ou seja, o valor do atributo numero será atribuído novamente, em outras palavras, será recuperado.

Acredito que isso resolva o seu problema, tenta aí e veja se da certo.

Abraços.

No caso, uso o setContentView e os métodos que preciso no onCreate fora do if, correto? Ainda assim quando rotaciono o dispositivo ele acessa os métodos.

Então, tudo que você precisa configurar apenas uma única vez, será adicionado dentro do if. setContentView() e referências de views como o findViewById() ficam fora do if. Portanto, se você não quer que acesse os métodos novamente, adicione dentro do if.

Mas com essa condição no if não está acessando.

Marcos, se der, manda o código do onCreate() e das chamadas de métodos que você precisa fazer apenas uma vez, acredito que dessa forma fica mais fácil de entender o problema real.

Estou confuso um pouco com esses métodos onSaveInstanceState e onRestoreInstanceState, ainda não tinha utilizado. Eu vou rever os métodos e tentar encontrar o problema. Agora já deu uma luz sobre o funcionamento na rotação do dispositivo e ele está setando o layout correto em portrait e landscape. Se cair os cabelos, posto o código aqui rs. Obrigado

Uma dica legal quando queremos testar ciclos de vidas no Android é adicionar logs, ou seja, adicione logs dentro de cada método e veja quando é chamado, dessa forma você vai ver como cada um funciona em cada situação que você está passando.

Ok, muito obrigado.