Solucionado (ver solução)

Importante

Você está vendo a versão anterior da nova experiência da Alura que estamos preparando para você. Em breve, ela ganha uma identidade visual novinha totalmente pensada em potencializar seus estudos!

Solucionado
(ver solução)
10
respostas

Fechar e Abrir diversos fragments

Bom dia, tudo certo?

Estou com uma dúvida. Seguinte:

Eu tenho 1 Activity, e entrando nela, abre automaticamente o Fragment_01, onde o usuário escolhe um item da lista e abre o Fragment_02, onde novamente ele escolhe um item e abre o Fragment_03.

No Fragment_03, ele pode acessar um site, que abre via navegador do celular. Mas ao fechar o navegador, o app está na tela do Fragment_02, sendo que deveria ter continuado no Fragment_03.

01 - Como fazer para não fechar o Fragment_03 quando o usuário clicar no site e abrir o navegador?

02 - Seria correto fechar cada Fragment assim que passo para o próximo? Qual seria o comando para fazer isso?

Obrigado.

10 respostas

Tenta fazer algo desse genero

Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.google.com"));
startActivity(browserIntent);

Seria melhor você postar o código fonte atual, para entender o que está acontecendo.

Olá Nicolas,

Vamos começar pela segunda dúvida. Quando você utiliza a operação replace(...) na FragmentTransaction, o Android se encarrrega de encerrar o fragment que está sendo substituído.

Agora na sua primeira dúvida, parece estranho que ele volte no segundo fragment. O que eu esperaria seria que ele voltasse no terceiro fragment normalmente a não ser que a activity tenha sido destruída (improvável no cenário que você descreveu). Mesmo que a activity tivesse sido destruída, deveria ter voltado no primeiro fragment. Para termos certeza do que está acontecendo vou pedir para você postar aqui o código da sua activity e dos seus fragments.

De qualquer maneira, a forma correta de lidar com esse tipo de coisa é utilizar os métodos do ciclo de vida da activity para salvar qual o fragment selecionado e quando você retornar para a activity, recarregar o fragment correspondente ao que você tinha armazenado.

Eu acho que me confundi, ele volta sim para o 1º Fragment.

É que são várias telas, coloco todas aqui??

Basicamente a Activity inicia colocando um 1º Fragment, que faz uma AsyncTASK com um webservice, gerando um ListView.

Desse ListView, escolho um item e vou para o 2º Fragment que faz outra AsyncTASK com o webservice, gerando mais um ListView.

Novamente selecionado, ele vai para o 3º Fragment, que faz outra AsyncTASK com o webservice, carregando os dados em um CardView.

Nesse 3º Fragment eu coloquei um Listener em um TextView, que ao ser clicado abre o site no navegador, mas ao fechar o navegador, ele volta ao 1º Fragment.

Caso precise colocar o código, coloco todas as telas, ou apenas os Fragments já basta?

PS: Esse Listener abre um PopupMenu que ao ser clicado vai para o navegador:


case R.id.menu_item_site:
    TextView txtSite = (TextView) view.findViewById(R.id.main_empresa_site);
    String site = (String) txtSite.getText();

    Intent intentSite = new Intent(Intent.ACTION_VIEW);

    if (!site.startsWith("http://")) {
        site = "http://" + site;
     }

    intentSite.setData(Uri.parse(site));
    startActivity(intentSite);
    return true;

Olá Nicolas,

Acho melhor você postar o código completo das activities, fragments e asynctasks, só para a gente ter uma ideia melhor do fluxo do aplicativo.

Bom dia, tudo bem?

Segue o código da Activity e fragment. É basicamente o mesmo para os fragments em sequência, buscar uma informação no webservice através de uma task e carregar uma lista.

Quando estou no 3º Fragment, ao clicar e abrir o site via navegador do android, ele volta para esta Activity principal.

MainActivity:

package br.com.teste;

import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;

import br.com.teste.modelo.Categoria;
import br.com.teste.modelo.Cidade;
import br.com.teste.modelo.Empresa;

public class MainActivity extends AppCompatActivity {

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    protected void onResume() {
        super.onResume();
        FragmentManager manager = getSupportFragmentManager();
        FragmentTransaction tx = manager.beginTransaction();
        MainFragmentListaCategorias fragmentListaCategorias = new MainFragmentListaCategorias();

        Intent intent = getIntent();
        Cidade cidade = (Cidade) intent.getSerializableExtra("cidade");

        Bundle params = new Bundle();
        params.putSerializable("cidade", cidade);
        fragmentListaCategorias.setArguments(params);

        tx.replace(R.id.frame_principal, fragmentListaCategorias);
        tx.commit();
    }

    public void carregaCategoria(Cidade cidade, Categoria categoria) {
        FragmentManager manager = getSupportFragmentManager();
        FragmentTransaction tx = manager.beginTransaction();
        MainFragmentListaEmpresas fragmentListaEmpresas = new MainFragmentListaEmpresas();

        Bundle params = new Bundle();
        params.putSerializable("cidade", cidade);
        params.putSerializable("categoria", categoria);
        fragmentListaEmpresas.setArguments(params);

        tx.replace(R.id.frame_principal, fragmentListaEmpresas);
        tx.addToBackStack(null);
        tx.commit();
    }

    public void carregaEmpresa(Empresa empresa) {
        FragmentManager manager = getSupportFragmentManager();
        FragmentTransaction tx = manager.beginTransaction();
        MainFragmentEmpresa fragmentEmpresa = new MainFragmentEmpresa();

        Bundle params = new Bundle();
        params.putSerializable("empresa", empresa);
        fragmentEmpresa.setArguments(params);

        tx.replace(R.id.frame_principal, fragmentEmpresa);
        tx.addToBackStack(null);
        tx.commit();
    }
}

MainFragmentListaCategorias:

package br.com.teste;

import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;

import java.util.List;

import br.com.teste.modelo.Categoria;
import br.com.teste.modelo.Cidade;
import br.com.teste.scripts.BuscaListaCategoriasTASK;

public class MainFragmentListaCategorias extends Fragment {
    private String idCidade;
    private View view;
    private Context context;
    private ListView lista;

    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.fragment_main_lista_categorias, container, false);
        context = view.getContext();
        lista = (ListView)  view.findViewById(R.id.main_lista_categorias_list);

       Bundle params = getArguments();
        final Cidade cidade = (Cidade) params.getSerializable("cidade");
        idCidade = cidade.getId();

       lista.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
               Categoria categoria = (Categoria) parent.getItemAtPosition(position);

                MainActivity mainActivity = (MainActivity) getActivity();
                mainActivity.carregaCategoria(cidade, categoria);
            }
        });

         new BuscaListaCategoriasTASK(this, idCidade).execute();

        return view;
    }

    public void onResume() {
        super.onResume();
    }

    public void populaList(List<Categoria> categorias) {
        ArrayAdapter adapterCategorias = new ArrayAdapter(context, android.R.layout.simple_list_item_1, categorias);
        lista.setAdapter(adapterCategorias);
    }
}

BuscaListaCategoriasTASK:

package br.com.teste.scripts;

import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.widget.Toast;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;

import br.com.teste.MainFragmentListaCategorias;
import br.com.teste.converter.CidadeConverter;
import br.com.teste.modelo.Categoria;
import br.com.teste.receiver.WebClientBuscaCategorias;

public class BuscaListaCategoriasTASK extends AsyncTask<Void, Void, String> {
    private final String idCidade;
    private MainFragmentListaCategorias fragmentCategorias;
    private ProgressDialog dialog;
    private Context context;

    public BuscaListaCategoriasTASK(MainFragmentListaCategorias fragmentCategorias, String idCidade){
        this.fragmentCategorias = fragmentCategorias;
        this.idCidade = idCidade;
        this.context = fragmentCategorias.getContext();
    }

    protected void onPreExecute() {
        dialog = ProgressDialog.show(context, "","", true, true);
    }

    protected String doInBackground(Void... params) {
        CidadeConverter conversor = new CidadeConverter();
        String json = conversor.converteParaJSON(idCidade);

        WebClientBuscaCategorias client = new WebClientBuscaCategorias();
        String resposta = client.post(json);

        return resposta;
    }

    protected void onPostExecute(String resposta) {
        dialog.dismiss();

        try {
            JSONObject json = new JSONObject(resposta);
            JSONArray categoriasJSONArray = json.getJSONArray("categorias");
            List<Categoria> categoriasList = new ArrayList();

            for (int i = 0; i < categoriasJSONArray.length(); i++) {
                Categoria categoria = new Categoria();

                JSONObject categoriaJSONObject = categoriasJSONArray.getJSONObject(i);
                String idCategoria   = categoriaJSONObject.getString("id");
                String nomeCategoria = categoriaJSONObject.getString("nome");
                String qtdeCategoria = categoriaJSONObject.getString("quantidade");

                categoria.setId(idCategoria);
                categoria.setNome(nomeCategoria);
                categoria.setQtde(qtdeCategoria);

                categoriasList.add(categoria);
            }
            fragmentCategorias.populaList(categoriasList);

        } catch (JSONException e) {
            e.printStackTrace();
            Toast.makeText(context, "Erro ao carregar lista de categorias...", Toast.LENGTH_SHORT).show();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
solução!

Olá Nicolas,

Parece que o problema está no código que está no onResume(...) da MainActivity. O onResume(...) é chamado sempre que a Activity é colocada em primeiro plano para que o usuário possa interagir com o seu aplicativo. Isso significa que ele vai ser chamado a primeira vez que o seu aplicativo for aberto. Nesse caso, faz sentido colocar o primeiro Fragment na tela para que ele possa escolher. Depois que ele fizer as seleções e abrir o navegador, o Android irá invocar os métodos onPause(...) e depois onStop(...) na MainActivity. Novamente, até aqui não temos nenhum problema. Quando fecharmos o navegador, a MainActivity deverá voltar para o primeiro plano e nesse caso o Android vai invocar os métodos onRestart(...), onStart(...) e onResume(...)! Se ele invoca novamente o onResume(...) ao retornar do navegador, qual vai ser o Fragment que vai ser sempre exibido? Vamos ver no código:

public class MainActivity extends AppCompatActivity {

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    protected void onResume() {
        super.onResume();
        FragmentManager manager = getSupportFragmentManager();
        FragmentTransaction tx = manager.beginTransaction();
        MainFragmentListaCategorias fragmentListaCategorias = new MainFragmentListaCategorias();

        Intent intent = getIntent();
        Cidade cidade = (Cidade) intent.getSerializableExtra("cidade");

        Bundle params = new Bundle();
        params.putSerializable("cidade", cidade);
        fragmentListaCategorias.setArguments(params);

        tx.replace(R.id.frame_principal, fragmentListaCategorias);
        tx.commit();
    }

    // resto do código

}

Perceba que o Fragment que será exibido é o MainFragmentListaCategorias independente do Fragment que estava selecionando antes de abrir o navegador. Para corrigir esse comportamento, você pode mudar esse código do onResume(...) para o onCreate(...) pois você só quer mostrar esse Fragment quando a Activity for aberta a primeira vez. Para as demais vezes, você quer mostrar o mesmo Fragment que estava selecionado antes de sair da Activity e isso o próprio Android vai fazer pra gente.

Jeferson, muito obrigado pela ajuda.

Nem me liguei nos comportamentos. Havia colocado no onResume(...) justamente para sempre atualizar a lista de categorias, mas isso atrapalhou todo o resto.

Poderia me indicar algum material sobre esses métodos?

onPause(...), onResume(...), onStart(...) ???

Muito obrigado pela ajuda!!!

Olá Nicolas,

O material que eu recomendo é a própria documentação do Android que pode ser encontrada aqui:

https://developer.android.com/guide/components/activities.html

Aqui fica detalhado o que significa cada um desses métodos e quais são as transições possíveis entre eles na seção de ciclo de vida das activities.

Obrigado.