A programação para dispositivos móveis vem ganhando cada vez mais mercado no mundo moderno, pois a grande maioria da população possui os tão cobiçados smartphones ou tablets e em quantidade cada vez maior.

Junto com essa evolução, as tecnologias para o desenvolvimento de aplicações mobile vem evoluindo continuamente, possibilitando ao desenvolvedor criar aplicativos que possam facilitar a vida dos usuários.

O Android é a plataforma que roda na maior parte dos dispositivos mobile existentes mundo a fora, e existem inúmeras formas de se desenvolver um aplicativo para ele. Nesse artigo será abordado o conceito de Fragments e o seu ciclo de vida dentro do sistema operacional Android.

Fragments

As fragments nada mais são que fragmentos de código que podem ser chamados pela sua activity para executar determinadas tarefas. O conceito de fragments foi introduzido na versão 3.0 do Android (Honeycomb) para atender aos tablets, que possuem uma tela maior, podendo aproveitar melhor o espaço da tela para interagir com o usuário, suportando designs mais flexíveis e dinâmicos.

Um exemplo bem simples para facilitar o entendimento seria um aplicativo de notícias que tem duas fragments: uma para exibir a lista de notícias e outra para exibir o conteúdo da notícia selecionada. Lembre-se que sempre atrás de uma fragment deve-se ter uma activity responsável pelo controle e manutenção dessas fragments que estão sendo exibidas.

Para criar uma fragment, sua classe deve ser estendida da classe Fragment, que entrou em vigor a partir da API 11, para que APIs que sejam menores sejam utilizadas por todos os aparelhos que rodam o sistema operacional Android, independentemente do tamanho da tela. Nesse artigo não serão utilizadas bibliotecas de suporte, portanto os códigos só funcionarão a partir da API 11.

A Listagem 1 mostra como deve ser a declaração de sua classe.


import android.app.Fragment;
public class MeuFragment extends Fragment{
            //Seu código aqui…..
}
Listagem 1. Declaração de uma classe que estende a classe Fragment

O ciclo de vida de uma fragment pode ser visto na Figura 1.

Ciclo de Vida de uma Fragment
Figura 1. Ciclo de Vida de uma Fragment

Ao analisar essa figura pode-se notar vários métodos que são chamados automaticamente pelo Sistema Operacional, e cada um desses são executados em um determinado momento.

O método onAttach é o primeiro método chamado quando a fragment está sendo criada e é o responsável por “juntar" a Fragment com a Activity e receber como parâmetro a Activity em questão. Sua assinatura é:


public void onAttach(Activity activity)

Seguindo com o ciclo de vida, o próximo método chamado é o onCreate, que é bem parecido com o onCreate da Activity, ou seja, ele cria a Fragment e, assim como na Activity, recebe um Bundle que pode conter alguma informação salva em execuções passadas. É importante notar que o esse método dentro da Fragment não acessa elementos de tela, ou seja não se pode fazer chamadas para elementos gráficos dentro desse método. Ele é muito utilizado para criar threads que serão responsáveis por processamentos demorados. Sua assinatura é:


public void onCreate(Bundle savedInstanceState)

O próximo método é o onCreateView, que é o local onde se deve fazer o contato com o layout da Fragment e carregá-lo. Lembre-se os elementos acessados aqui são apenas os elementos da Fragment. A assinatura desse método é um pouco maior, pois aqui se tem que inflar o XML para transformá-lo em um objeto do tipo View (mais a frente será mostrado como se fazer isso):


public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
Listagem 1. NOME

Seguindo com seu ciclo de vida, o método onActivityCreated é chamado apenas depois que a Activity já está criada (método onCreate da Activity já terminou), ou seja, aqui é o local onde se pode acessar ou modificar elementos de tela. A assinatura do método onActivityCreated é a seguinte:


public void onActivityCreated(Bundle savedInstanceState)

Os próximos métodos que serão invocados serão os métodos onStart, onResume e onPause, e não serão comentados, pois possuem a mesma funcionalidade do que quando chamados dentro de uma Activity. Suas assinaturas podem ser vistas na Listagem 2.


public void onStart()
public void onPause()
public void onStop()
Listagem 2. Assinatura dos métodos onStart, onResume, onPause

A seguir, o método onSaveInstanceState é chamado (não está listado na Figura 1). Este é muito importante se em sua aplicação é preciso salvar algum tipo de informação que deve ser utilizada futuramente: as informações podem ser salvas em um objeto Bundle que faz parte do parâmetro do método. A assinatura desse método é a seguinte:


public void onSaveInstanceState(Bundle outState)

O método onStop tem a mesma função do onStop da Activity e tem a seguinte assinatura:


public void onStop()

Continuando com o Ciclo de Vida, o método onDestroyView é chamado até ele ser executado ainda com a Fragment acessível, ou seja, sua hierarquia ainda pode ser acessada. Após a execução do método, a Fragment passa a não ser mais acessível, seu objeto ainda existe, mas não pode mais ser acessada. A assinatura desse método é:


public void onDestroyView()

Outro método chamado é o onDestroy quando a Fragment não está mais sendo utilizada, mas o objeto ainda existe, pois ainda está ligada com a Activity. Sua assinatura é:


public void onDestroy()

Por fim, tem-se o método onDetach, que é quando finalmente a Fragment não está mais ligada a nenhuma Activity, ou seja, não está mais associada a nada. Sua assinatura é:


public void onDetach()

Agora veremos a demonstração de uma pequena aplicação que mostra o ciclo de vida da Fragment sendo executado juntamente com o ciclo de vida da Activity. O objetivo desse código é demonstrar quando esses métodos são chamados e executados, e isso será visto no Log do Android. A tela será algo bem simples, pois terão apenas dois elementos: o layout que será chamado pela Activity, e a chamada da Fragment que, por sua vez, irá também chamar um layout a ser “encaixado" estaticamente dentro do layout da Activity.

A Listagem 3 mostra o código do layout da Activity que chamará estaticamente a Fragment.


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"
    android:background="#00FFCC">
 
    <fragment
        android:layout_margin="20dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:name="br.com.home.fragmentlifecicle.FragmentA"
        android:id="@+id/fragment"/>
 
</RelativeLayout>
Listagem 3. Código XML da tela da Activity

Notem que a tag fragment faz uma referência direta a classe FragmentA, que é a classe que extende à superclasse "Fragment" e contém toda a lógica que será executada pela FragmentA.

O código da Listagem 4 mostra o layout da Fragment, responsável pela interface gráfica que o usuário irá ver “encaixado" dentro do layout da Activity.


<?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="#FF0000">

  <TextView
      android:layout_margin="20dp"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:textAppearance="?android:attr/textAppearanceLarge"
      android:text="Dentro da Fragment"
      android:id="@+id/textView"
      android:layout_gravity="center_horizontal" />
</LinearLayout>
Listagem 4. Código XML da Fragment

O código possui apenas um TextView que é apresentado na tela. O resultado das duas telas pode ser visualizado na Figura 2.

Resultado dos layouts
Figura 2. Resultado dos layouts

Note que ainda temos apenas uma tela como qualquer outra, que não mostra nada do ciclo de vida. Para poder visualizá-lo é necessário implementar todos os métodos do ciclo e colocar mensagens de log nele para observarmos. A Listagem 5 mostra o código completo da classe FragmentA.


package br.com.home.fragmentlifecicle;
 
import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
 
/**
 * Created by allanromanato on 8/9/15.
 */
public class FragmentA extends Fragment {
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        Log.d("Ciclo", "Fragment: Metodo onAttach() chamado");
    }
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("Ciclo", "Fragment: Metodo onCreate() chamado");
    }
 
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
    Bundle savedInstanceState) {
        Log.d("Ciclo", "Fragment: Metodo onCreateView() chamado");
        return inflater.inflate(R.layout.fragment_a,container,false);
 
    }
 
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        Log.d("Ciclo", "Fragment: Metodo onActivityCreated() chamado");
    }
 
    @Override
    public void onStart() {
        super.onStart();
        Log.d("Ciclo", "Fragment: Metodo onStart() chamado");
    }
 
    @Override
    public void onResume() {
        super.onResume();
        Log.d("Ciclo", "Fragment: Metodo onResume() chamado");
    }
 
    @Override
    public void onPause() {
        super.onPause();
        Log.d("Ciclo", "Fragment: Metodo onPause() chamado");
    }
 
    @Override
    public void onStop() {
        super.onStop();
        Log.d("Ciclo", "Fragment: Metodo onStop() chamado");
    }
 
    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.d("Ciclo", "Fragment: Metodo onSavedInstanceState() chamado");
    }
 
    @Override
    public void onDestroyView() {
        super.onDestroyView();
        Log.d("Ciclo", "Fragment: Metodo onDestroyView() chamado");
    }
 
    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("Ciclo", "Fragment: Metodo onDestroy() chamado");
    }
 
    @Override
    public void onDetach() {
        super.onDetach();
        Log.d("Ciclo", "Fragment: Metodo onDetach() chamado");
    }
}
Listagem 5. Código completo FragmentA

Quando é criada a view “public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {“, o retorno é um tipo view, portanto é necessário fazer um inflate, que é um método contido dentro da classe LayoutInflater, responsável por “inflar” o XML de layout. Em outras palavras, ele transforma o XML em um objeto do tipo View. É um processo custoso, pois ele pega o XML e cria um objeto Java desse XML, setando todos os atributos, e recursivamente faz isso para todos as tags filhas que estão no XML.

Na Listagem 6 pode-se ver o código da Activity inicial que fará a chamada da Fragment. Primeiramente o teste será apenas feito com o ciclo de vida da Fragment.


package br.com.home.fragmentlifecicle;
 
import android.app.Activity;
import android.os.Bundle;
 
/**
 * Created by allanromanato on 8/9/15.
 */
 
public class MainActivity extends Activity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}
Listagem 6. Código da Activity

O código é apenas de fazer a ligação da Activity com o layout que foi feito anteriormente. O resultado do ciclo de vida da fragment pode ser visto na Listagem 7. Para vê-lo em seu ambiente, filtre os logs com a palavra Ciclo.

Nota: Quando o emulador iniciar a aplicação, o log mostrará até o método onResume, e para os demais (que são de desligamento) serem executados é necessário que a aplicação seja fechada.

08-09 22:35:32.900  10033-10033/br.com.home.fragmentlifecicle D/Ciclo﹕ 
Fragment: Metodo onAttach() chamado
08-09 22:35:32.901  10033-10033/br.com.home.fragmentlifecicle D/Ciclo﹕ 
Fragment: Metodo onCreate() chamado
08-09 22:35:32.901  10033-10033/br.com.home.fragmentlifecicle D/Ciclo﹕ 
Fragment: Metodo onCreateView() chamado
08-09 22:35:32.901  10033-10033/br.com.home.fragmentlifecicle D/Ciclo﹕ 
Fragment: Metodo onActivityCreated() chamado
08-09 22:35:32.903  10033-10033/br.com.home.fragmentlifecicle D/Ciclo﹕ 
Fragment: Metodo onStart() chamado
08-09 22:35:32.904  10033-10033/br.com.home.fragmentlifecicle D/Ciclo﹕ 
Fragment: Metodo onResume() chamado
08-09 22:35:34.911  10033-10033/br.com.home.fragmentlifecicle D/Ciclo﹕ 
Fragment: Metodo onPause() chamado
08-09 22:35:35.334  10033-10033/br.com.home.fragmentlifecicle D/Ciclo﹕ 
Fragment: Metodo onStop() chamado
08-09 22:35:35.334  10033-10033/br.com.home.fragmentlifecicle D/Ciclo﹕ 
Fragment: Metodo onDestroyView() chamado
08-09 22:35:35.334  10033-10033/br.com.home.fragmentlifecicle D/Ciclo﹕ 
Fragment: Metodo onDestroy() chamado
08-09 22:35:35.334  10033-10033/br.com.home.fragmentlifecicle D/Ciclo﹕ 
Fragment: Metodo onDetach() chamado
Listagem 7. Log de criação

A dúvida agora é com o ciclo de vida da Activity, pois onde entra dentro disso tudo? Ele é feito antes do ciclo de vida da Fragment, ou depois? A resposta é bem simples: ele é feito durante, ou seja, o ciclo de vida da Fragment depende do ciclo de vida da Activity.

O que será feito agora é uma pequena alteração no código do exemplo anterior para o ciclo de vida da Activity também se mostrado pelo log, e assim será mais fácil de se compreender onde e quando cada método é chamado. A Listagem 8 mostra o código da Activity modicada para que mostre seu ciclo de vida no log.


package br.com.home.fragmentlifecicle;
 
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
 
/**
 * Created by allanromanato on 8/9/15.
 */
 
public class MainActivity extends Activity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.e("Ciclo", "Activity: Metodo onCreate() chamado");
        setContentView(R.layout.activity_main);
        Log.e("Ciclo", "Activity : Metodo onCreate() Finalizado.");
    }
 
    @Override
    protected void onStart() {
        super.onStart();
        Log.e("Ciclo", "Activity: Metodo onStart() chamado");
    }
 
    @Override
    protected void onRestart() {
        super.onRestart();
        Log.e("Ciclo", "Activity: Metodo onRestart() chamado");
    }
 
    @Override
    protected void onResume() {
        super.onResume();
        Log.e("Ciclo", "Activity: Metodo onResume() chamado");
    }
 
    @Override
    protected void onPause() {
        super.onPause();
        Log.e("Ciclo", "Activity: Metodo onPause() chamado");
    }
 
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.e("Ciclo", "Activity: Metodo onSavedInstanceState() chamado");
    }
 
    @Override
    protected void onStop() {
        super.onStop();
        Log.e("Ciclo", "Activity: Metodo onStop() chamado");
    }
 
    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.e("Ciclo", "Activity: Metodo onDestroy() chamado");
    }
}
Listagem 8. Código modificado da Activity

Observem na Listagem 9 o log que mostra sequencialmente todas as chamadas dos métodos do ciclo de vida, tanto da Activity quando da Fragment.


08-09 22:33:39.815    9215-9215/br.com.home.fragmentlifecicle E/Ciclo﹕ 
Activity: Metodo onCreate() chamado
08-09 22:33:39.819    9215-9215/br.com.home.fragmentlifecicle D/Ciclo﹕ 
Fragment: Metodo onAttach() chamado
08-09 22:33:39.819    9215-9215/br.com.home.fragmentlifecicle D/Ciclo﹕ 
Fragment: Metodo onCreate() chamado
08-09 22:33:39.819    9215-9215/br.com.home.fragmentlifecicle D/Ciclo﹕ 
Fragment: Metodo onCreateView() chamado
08-09 22:33:39.819    9215-9215/br.com.home.fragmentlifecicle E/Ciclo﹕ 
Activity : Metodo onCreate() Finalizado.
08-09 22:33:39.819    9215-9215/br.com.home.fragmentlifecicle D/Ciclo﹕ 
Fragment: Metodo onActivityCreated() chamado
08-09 22:33:39.830    9215-9215/br.com.home.fragmentlifecicle E/Ciclo﹕ 
Activity: Metodo onStart() chamado
08-09 22:33:39.830    9215-9215/br.com.home.fragmentlifecicle D/Ciclo﹕ 
Fragment: Metodo onStart() chamado
08-09 22:33:39.830    9215-9215/br.com.home.fragmentlifecicle E/Ciclo﹕ 
Activity: Metodo onResume() chamado
08-09 22:33:39.830    9215-9215/br.com.home.fragmentlifecicle D/Ciclo﹕ 
Fragment: Metodo onResume() chamado
08-09 22:34:12.517    9215-9215/br.com.home.fragmentlifecicle D/Ciclo﹕ 
Fragment: Metodo onPause() chamado
08-09 22:34:12.517    9215-9215/br.com.home.fragmentlifecicle E/Ciclo﹕ 
Activity: Metodo onPause() chamado
08-09 22:34:13.478    9215-9215/br.com.home.fragmentlifecicle D/Ciclo﹕ 
Fragment: Metodo onStop() chamado
08-09 22:34:13.478    9215-9215/br.com.home.fragmentlifecicle E/Ciclo﹕ 
Activity: Metodo onStop() chamado
08-09 22:34:13.478    9215-9215/br.com.home.fragmentlifecicle D/Ciclo﹕ 
Fragment: Metodo onDestroyView() chamado
08-09 22:34:13.479    9215-9215/br.com.home.fragmentlifecicle D/Ciclo﹕ 
Fragment: Metodo onDestroy() chamado
08-09 22:34:13.479    9215-9215/br.com.home.fragmentlifecicle D/Ciclo﹕ 
Fragment: Metodo onDetach() chamado
08-09 22:34:13.479    9215-9215/br.com.home.fragmentlifecicle E/Ciclo﹕ 
Activity: Metodo onDestroy() chamado
Listagem 9. Log da Activity

Percebam que na fase de inicialização a Activity chama o primeiro método onCreate, e a Fragment executa o último método onResume. Já na fase de desligamento, quem executa o primeiro método onPause é a Fragment, e o último método onDestroy é da Activity.

Antes de trabalhar com as Fragments, é de extrema importância que seu ciclo de vida seja compreendido corretamente. Alguns recursos não podem ser chamados em determinados métodos, pois ainda podem não ter sido inicializados, por exemplo. Os recursos que são criados em uma Activity devem ser chamados dentro da Fragment, no método onActivityCreated, pois dentro dele é garantido que o onCreate já finalizou sua execução.

Espero que tenham gostado desse artigo e que ele possa ser de grande utilidade no dia a dia dos desenvolvedores Android.