Entendendo Fragments

Introdução

Link oficial sobre Fragments no site Android Developer: http://developer.android.com/guide/components/fragments.html

O Fragment é uma das grandes novidades da API do Android, que surgiu após a versão Android 3.0 HoneyComb, graças a chegada dos tablets no mercado.

Como o próprio nome sugere, Fragment pode ser definido como um fragmento de uma tela em um aplicativo Android.

Obs: Entenda tela como um Layout XML (View) vinculado a uma Activity (Controller). Se esta com dificuldades em entender esses termos leia este post

Por ser um “pedaço” de uma tela, podemos utilizar o Fragment em vários locais, esta reutilização de funcionalidades o torna uma estrutura muito poderosa.

É como se fosse uma mini Activity, com seu próprio ciclo de vida.

Outro problema bem comum que essa estrutura veio para resolver é o de manter uma boa experiência de Interface gráfica em todos os dispositivos Android, independente do tamanho da tela.

Vamos a um exemplo para entender este problema:
Imagine um aplicativo de notícias, que tem como requisito rodar bem em Smartphones e Tablets. Basicamente, o app conta com uma lista de nomes de notícias, que ao ser clicada mostrará uma tela com a notícia completa. Em um smartphone a melhor maneira de atender esta situação é ter uma Lista em uma tela, e depois dessa lista ser clicada o usuário seria direcionado para a tela de detalhes. Já em um tablet, a melhor maneira seria exibir em uma mesma tela, a lista e o detalhes de uma notícia selecionada juntos. Veja o esboço do layout dessas duas situações: layout_tablet

Formas de resolver este problema

Sem os Fragments, você teria que preparar um layout para cada esquema de tela (Tablet e Smartphone), até ai tudo bem.

Você também deveria ter uma Activity, que teria que realizar varias comparações para saber se o app esta sendo executado em um tablet ou em um smartphone, para assim saber como montar a tela ou saber como proceder quando um item for clicado.

No final das contas teria uma Activity de código grande e de difícil manutenção. Usando Fragment para resolver esse problema. Você teria um Fragment que conseguiria listar o titulo das notícias. E outro que conseguiria exibir os detalhes da notícia clicada.

Como resultado sua Activity ficaria muito mais leve, uma vez que as responsabilidades de exibir lista e mostrar detalhes foram delegadas para dois Fragments, e não ficará apenas em uma Activity.

Eventualmente, ainda pode existir validações pra saber se o app esta rodando em tablet ou smartphone para o aplicativo saber proceder da melhor maneira em alguma determinada situação. Porém essas validações seriam menos comuns do que no caso anterior onde não utilizamos Fragment.

Exemplo prático

O primeiro exemplo que utilizaremos para entender como utilizar Fragments, será um caso mais simples do que o esboçado logo acima. Mas também muito encontrado no universo do desenvolvimento para dispositivos móveis.

Imagine um cenário onde você tenha que desenvolver um aplicativo que tenha muitas telas, sendo que em cada tela exista um espaço de propaganda. Essa propaganda consiste em uma descrição de um site e um Button que ao ser clicado redirecionará o usuário para uma URL alvo da propaganda. Podemos resolver esse problema criando um Fragment que tem a responsabilidade de exibir a View da propaganda e tratar o comportamento dos componentes nela apresentados, no caso o Button.

Chamaremos esse Fragment de FragmentPropaganda. Podemos observar o código dele logo abaixo:

public class FragmentPropaganda extends Fragment {

	private static final String URL = "http://timespender.com/";

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
		View view = inflater.inflate(R.layout.layout_fragment, container);

		Button buttonCliqueAqui = (Button) view.findViewById(R.id.button_clique_aqui);
		buttonCliqueAqui.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				irParaSite();
			}
		});

		return view;
	}

	private void irParaSite() {
		Uri uriVideo = Uri.parse(URL);
		Intent intent = new Intent(Intent.ACTION_VIEW, uriVideo);
		startActivity(intent);
	}

}

Obs: O Fragment que utilizei é o android.support.v4.app.Fragment, ou seja pertence a library android-support-v4.jar. Essa biblioteca foi disponibilidade para que possamos utilizar diversos recursos como o Fragments em versões do Android Abaixo da 3.0. Conforme foi explicado no início do artigo, o Fragment é como se fosse uma mini Activity. Tal como a Activity, o Fragment possui um ciclo de vida, na imagem abaixo você poderá ver este ciclo do Fragment:

Ciclo de vida Fragment

 

Assim como a Activity tem o método onCreate(), que é responsável pela criação da Activity, no Fragment temos o onCreateView(), que também representa o local onde será criado o Fragment. É la que vincularemos o Fragment a um layout XML, após isso podemos colocar comportamento nas Views, tal como foi feito no botão.

Neste exemplo, vinculei o meu Fragment ao layout layout_fragment, podemos vê-lo logo abaixo:

<!--?<span class="hiddenSpellError" pre="" data-mce-bogus="1"-->xml version="1.0" encoding="utf-8"?>
<xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    android:gravity="center" >

    <TextView
        android:layout_weight="1"
        android:textSize="20sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/propaganda" />

    <Button
        android:layout_weight="0"
        android:id="@+id/button_clique_aqui"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/clique_aqui" />

</LinearLayout>

Podemos ver que é um layout bem simples, apenas um TextView que faz uma descrição do site que estamos anunciando, e um botão que abrirá o browser com o site alvo. Logo abaixo, segue o arquivo Strings.xml deste projeto:

<!--?<span class="hiddenSpellError" pre="" data-mce-bogus="1"-->xml version="1.0" encoding="utf-8"?>
<resources>

    name="app_name">Fragments
    name="action_settings">Settings
    name="hello_world">Hello world!
    name="propaganda">Conheça o TimeSpender, programa-se ao ver videos!
    name="clique_aqui">Clique Aqui!
    name="layout_tela_um">Layout da tela UM
    name="layout_tela_dois">Layout da tela DOIS
    name="ir_para_tela_dois">Ir para a tela DOIS

</resources>

Bom, nesse momento temos um Fragment funcional, pronto para ser utilizado em qualquer Activity do nosso projeto. É isso que devemos fazer. Crie em seu projeto uma Activity chamada ActivityPropagandaUm. Ela terá o seguinte código:

public class ActivityPropagandaUm extends FragmentActivity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.layout_activity_um);
	}

	public void onClickTelaDois(View view) {
		Intent intent = new Intent(this, ActivityPropagandaDois.class);
		startActivity(intent);
	}
}

Três coisas devem ser ressaltadas:

– Estamos herdando da classe FragmentActivity e não diretamente da classe Activity do Android.Se tiver trabalhando com Fragment dentro de uma Activity, lembre-se sempre de herdar FragmentActivity, esquecer isso é um erro comum.

– Criamos um método onClickTelaDois. Este método esta vinculado ao botão informado no layout XML, R.layout.layout_activity_um. Ele simplesmente chama a Activity ActivityPropagandaDois. Criaremos essa classe mais a frente nesse artigo.

– Estamos vinculando a nossa Activity ao layout layout_activity_um, o nosso Fragment foi declarado dentro deste XML, ou seja, fizemos um vinculo com a funcionalidade de propaganda sem usar código java.

Veja como o código ficou simples de ser analisado, este é um benefício de se usar Fragment.
Analise logo abaixo o layout layout_activity_um:

<xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/layout_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:gravity="center"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:orientation="vertical" >

        <TextView
            android:textSize="22dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/layout_tela_um" />

        <Button
            android:text="@string/ir_para_tela_dois"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="onClickTelaDois"
            />
    </LinearLayout>

<LinearLayout
    android:layout_gravity="bottom"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical" >

    <fragment
        android:layout_margin="2dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        class="com.example.tudofragment.FragmentPropaganda" />

</LinearLayout>

</LinearLayout>

Se trata de um layout muito simples, com um TextView indicando qual Activity o usuário esta, e um botão para muda-lo de Activity. O ponto que queremos chamar a atenção esta mais embaixo, assim como declaramos qualquer View também declaramos um Fragment. A única particularidade é o atributo class=”com.example.tudofragment.FragmentPropaganda”, é nessa tag que informamos a classe do Fragment que queremos utilizar.

No final das contas teremos a seguinte tela a nossa disposição:

tela_um_fragment

Para deixar o projeto ainda mais flexível, vamos criar um outro layout XML que encapsulará o nosso Fragment, o chamaremos de layout_propaganda, e ficará desse jeito:

<!--?<span class="hiddenSpellError" pre="" data-mce-bogus="1"-->xml version="1.0" encoding="utf-8"?>
<xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical" >

    <fragment
        android:layout_margin="2dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        class="com.example.tudofragment.FragmentPropaganda" />

</LinearLayout>

Após a criação deste layout, vamos vincula-lo ao layout da nossa <strong>Activity</strong>, ao invés de apontar para o <strong>Fragment</strong>  direto, fazemos isso usando a tag <strong>include</strong>.
Que nos possibilita incluir um layout XML dentro do outro. É um ótimo recurso para ajudar a reutilizar layouts ente <strong>Activitys</strong>.

Nosso <em>layout_activity_um</em> ficará desse jeito:


<xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/layout_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:gravity="center"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:orientation="vertical" >

        <TextView
            android:textSize="22dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/layout_tela_um" />

        <Button
            android:text="@string/ir_para_tela_dois"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="onClickTelaDois"
            />
    </LinearLayout>

    <include
        android:layout_gravity="bottom"
        layout="@layout/layout_propaganda"/>

</LinearLayout>

Para concluir nosso exemplo, crie uma outra Activity e a chame de ActivityPropagandaDois. Essa Activity terá o seguinte código:

public class ActivityPropagandaDois extends FragmentActivity {

	@Override
	protected void onCreate(Bundle arg0) {
		super.onCreate(arg0);
		setContentView(R.layout.layout_activity_dois);
	}

}

Volte no código da ActivityPropagandaUm para ver que existe um método que vai abrir a ActivityPropagandaDois. Bem simples né!? Apenas faz vínculo ao layout XML que chamamos de layout_activity_dois. Podemos ver o código deste layout logo abaixo:

<xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/layout_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:gravity="center"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:orientation="vertical" >

        <TextView
            android:textSize="22dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/layout_tela_dois" />
    </LinearLayout>

    <include
        android:layout_gravity="bottom"
        layout="@layout/layout_propaganda"/>

</LinearLayout>

Observe que novamente, fazemos referência ao layout_propaganda. Ou seja, estamos reutilizando a funcionalidade de exibir uma propaganda em duas Activitys diferentes com um esforço muito pequeno.
Imagine se esse Fragment invés de mostrar uma propaganda, faça uma chamada no servidor para mostrar as condições climáticas, ou mostre o resultado do último jogo de seu time favorito.

As possibilidade são muitas, e uma vez feito você poderá utiliza-lo novamente em qualquer Activity do seu aplicativo.

FragmentTransaction e FragmentManager - Criando e trocando fragments dinamicamente

Em muitas situações você deverá ter uma activity que troque Fragments dinamicamente. Como por exemplo imagine que você tenha um menu no topo da tela do seu app, com base na opção que o usuário clicar você irá trocar o Fragment que esta posicionado no centro desta tela. Qual é a melhor maneira de fazermos isso? A API do Android nos fornece a classe FragmentTransaction, que te possibilita adicionar, remover, e substituir um determinado Fragment em uma tela.

Vejamos como funciona em um exemplo funcional. Crie uma Activity com o nome de ActivityFragmentDinamico. Esta Activity, estará vinculada a um layout que basicamente terá dois botões la embaixo da tela, com os dizeres UM e Dois. Pressionando o botão UM, o layout no centro da tela receberá o FragmentUm. Pressionando o botão Dois, o layout no centro da tela receberá o FragmentDois. Começaremos então com a criação dos Fragments: Código do Fragment UM:

public class FragmentUm extends Fragment {

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,  Bundle savedInstanceState) {
		View view = inflater.inflate(R.layout.layout_fragment, container,false);
		return view;
	}

}

Código do Fragment DOIS:

public class FragmentDois extends Fragment {

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
		View view = inflater.inflate(R.layout.layout_fragment_dois, container,false);
		return view;
	}

}

Ambos estão vinculados a layouts bem parecidos, vejamos eles:

<!--?xml <span class="hiddenSpellError" pre="xml " data-mce-bogus="1"-->version="1.0" encoding="utf-8"?>
<xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="@android:color/black">

    <TextView
        android:textColor="@android:color/white"
        android:layout_centerInParent="true"
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="FRAGMENT DOIS"
        android:textAppearance="?android:attr/textAppearanceLarge" />

</RelativeLayout>

Veja que se trata apenas de um layout simples que possui um TextView que indica qual Fragment o usuário esta vendo. Basicamente, teremos dois arquivos iguais a este acima, o primeiro com os dizeres FRAGMENT UM e o segundo com os dizeres FRAGMENT DOIS. Com os Fragments criados, voltamos então a Activity que irá troca-los e adiciona-los de forma dinâmica. Vejamos o código para posteriormente ver as explicações:

public class ActivityFragmentDinamico extends FragmentActivity {

	Fragment fragmentUm = new FragmentUm();
	Fragment fragmentDois = new FragmentDois();	

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.layout_activity_um);

		addFragment(fragmentDois);
	}

	public void onClickFragmentOne(View view) {
		replaceFragment(fragmentUm);
	}

	public void onClickFragmentTwo(View view) {
		replaceFragment(fragmentDois);
	}

	private void addFragment(Fragment fragment) {
		FragmentTransaction  transaction = getSupportFragmentManager().beginTransaction();

		transaction.add(R.id.layout_fragments, fragment);
		transaction.addToBackStack(null);

		transaction.commit();
	}

	private void replaceFragment(Fragment fragment) {
		FragmentTransaction  transaction = getSupportFragmentManager().beginTransaction();

		transaction.replace(R.id.layout_fragments, fragment);
		transaction.addToBackStack(null);

		transaction.commit();
	}
}

O código acima cria os objetos FragmentUm e FragmentDois. E no método onCreate adiciona o fragmentUm em seu layout dinamicamente. Utilizando o método addFragment, que recebe como paramêtro o Fragment que desejamos adicionar e passamos o R.id.layout_fragments, que representa o local do nosso layout no qual o fragment será inserido, observe o layout XML abaixo para identificar esse local, veja que esta no centro da tela.

<xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/layout_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white"
    android:orientation="vertical" >

    <LinearLayout
        android:background="#8A2BE2"
        android:id="@+id/layout_fragments"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:gravity="center"
        android:orientation="vertical" >

    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#7FFF00"
        android:gravity="center"
        android:orientation="horizontal" >

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:onClick="onClickFragmentOne"
            android:text="UM" />

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:onClick="onClickFragmentTwo"
            android:text="DOIS" />
    </LinearLayout>

</LinearLayout>

Basicamente a ação de adicionar é feita utilizando a classe FragmentTransaction que possui o método add, após adicionarmos o Fragment no local do layout que desejamos, acionamos o método commit também do FragmentTransaction para efetivara a ação. A mesma coisa é feita no método replace, que é acionado quando os botões forem clicados. Pretendo atualizar este post com novas informações sobre Fragments, vejo você novamente mais tarde =]

LINK PARA DOWNLOAD DO PROJETO

Anúncios

, ,

  1. #1 by Igor Borges on Agosto 14, 2015 - 12:42 am

    Mano vc explica mt bem.. vlw msm ajudou muito…

  2. #2 by Wanderson on Agosto 5, 2015 - 12:29 am

    Mano, como que faço um Fragment_dialog_about , com uma imagem , que , quando clicada, aparece as informações do app e meu Web site, email, Facebook, etc?

  3. #3 by Lucas Medina on Maio 22, 2015 - 1:24 pm

    Bom dia, estou utilizando fragment em meu projeto, pelo fato de ser em Material Design. Estou precisando clicar numa ImageButton e abrir outra fragment. Como faço isso?
    Obrigado
    Obs.: Segui este tutorial para fazer o Material Design.
    http://www.androidhive.info/2015/04/android-getting-started-with-material-design/

  4. #4 by Heitor on Maio 21, 2015 - 8:55 pm

    Ótimo post! parabéns!
    Ficou muito fácil de entender!
    Abraço!

  5. #5 by Leonardo Casasanta on Abril 16, 2015 - 2:24 pm

    Rony,

    Meu processo de desenvolver interface é bem arcaico.

    Eu penso na funcionalidade e procuro exemplos de interface similares

    Tipo quando eu vou desenvolver alguma função de mapa, ai eu analiso os exemplos abaixo:

    Depois disso eu já tenho uma idéia de como a minha tela deve ficar, ai eu já começo a desenvolver.

    Tem uma galera que usa o balsamiq pra fazer protótipo:
    https://balsamiq.com

  6. #9 by Clemente Martire on Novembro 10, 2014 - 6:41 pm

    Vc tem como disponibilizar o codigo do projeto (Android Studio). Consertei algumas coisas que estavam erradas no código, mas não consegui fazer funcionar. Principalmente pelo fato dele chamar o Main e não existir ele no projeto.

  7. #12 by Heitor on Outubro 29, 2014 - 6:14 pm

    Ótimo post!
    Ficou fácil de entender!
    Valeu

  8. #13 by Silvio on Abril 27, 2014 - 3:33 pm

    Poderia por favor postar o codigo do projeto ?
    Obrigado

  9. #15 by ovictorpinto on Janeiro 31, 2014 - 12:44 pm

    “Fragment pode ser definido como um fragmento de uma tela em um aplicativo Android”
    Vale lembrar que um fragmento pode não ser visível. Muito comum quando se usa o setRetainInstance().

Deixe uma Resposta

Preencha os seus detalhes abaixo ou clique num ícone para iniciar sessão:

Logótipo da WordPress.com

Está a comentar usando a sua conta WordPress.com Terminar Sessão / Alterar )

Imagem do Twitter

Está a comentar usando a sua conta Twitter Terminar Sessão / Alterar )

Facebook photo

Está a comentar usando a sua conta Facebook Terminar Sessão / Alterar )

Google+ photo

Está a comentar usando a sua conta Google+ Terminar Sessão / Alterar )

Connecting to %s

%d bloggers like this: