Bhargav Jhaveri
Bhargav Jhaveri

Reputation: 2183

addToBackStack() method is not working without overriding the onBackPressed() method in android

Here is the code of MainActivity which I have written. I am loading the list of fragment in the first screen. When the user taps on any of the list items, the planet name will be shown to the user in the detail fragment which I have defined in a separate class.

I am adding the transaction of "Fragment Planet List" -> "Fragment Planet Detail" to back stack. So what I expect is when I press the back button from the fragment of planet detail, it should load planet list in the phone. But it is not happening this way.

import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.FrameLayout;

import com.meditab.fragments.fragment.FragmentPlanetDetail;
import com.meditab.fragments.fragment.FragmentPlanetList;

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


public class MainActivity extends ActionBarActivity implements Callback {

    private FrameLayout frmPlanetList;
    private FrameLayout frmPlanetDetail;
    private boolean isPhone;


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

        frmPlanetList = (FrameLayout) findViewById(R.id.frmPlanetList);
        frmPlanetDetail = (FrameLayout) findViewById(R.id.frmPlanetDetail);

        if (null != frmPlanetDetail) {
            isPhone = false;
        } else {
            isPhone = true;
        }

        FragmentManager fragmentManager = getFragmentManager();

        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

        fragmentTransaction.replace(R.id.frmPlanetList, new FragmentPlanetList());

        fragmentTransaction.commit();

    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onListItemClicked(int intPosition) {

        FragmentManager fragmentManager = getFragmentManager();

        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

        List<String> lstPlanetArray = getPlanetArray();
        String strPlanetName = lstPlanetArray.get(intPosition);

        FragmentPlanetDetail fragmentPlanetDetail = FragmentPlanetDetail.newInstance(strPlanetName);
        if (isPhone) {
            fragmentTransaction.addToBackStack(null);
            fragmentTransaction.replace(R.id.frmPlanetList, fragmentPlanetDetail);
        } else {
            fragmentTransaction.replace(R.id.frmPlanetDetail, fragmentPlanetDetail);
        }

        fragmentTransaction.commit();

    }

    private List<String> getPlanetArray() {
        List<String> lstPlanets = new ArrayList<>(10);
        lstPlanets.add("Mercury");
        lstPlanets.add("Venus");
        lstPlanets.add("Earth");
        lstPlanets.add("Mars");
        lstPlanets.add("Jupiter");
        lstPlanets.add("Saturn");
        lstPlanets.add("Uranus");
        lstPlanets.add("Neptune");
        lstPlanets.add("Saturn");

        return lstPlanets;
    }

}

However if I override the backPress method and pop the back stack programatically, it works just fine.

@Override
public void onBackPressed() {
    if (getFragmentManager().getBackStackEntryCount() != 0) {
        getFragmentManager().popBackStack();
    } else {
        super.onBackPressed();
    }
}

Do I need to override the onBackPressed() method this way if I want to achieve this behavour? It is not documented that you need to override this method in this link.Android Back Press Fragment Documentation

Fragment Planet Detail Class

import android.app.Fragment;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.meditab.fragments.R;

/**
 * Created by BHARGAV on 25-Dec-14.
 */
public class FragmentPlanetDetail extends Fragment {

    private String strPlanetName;

    public FragmentPlanetDetail() {

    }

    public static FragmentPlanetDetail newInstance(String strPlanetName) {
        FragmentPlanetDetail fragmentPlanetDetail = new FragmentPlanetDetail();

        Bundle bundle = new Bundle();
        bundle.putString("Planet_Name", strPlanetName);
        fragmentPlanetDetail.setArguments(bundle);
        return fragmentPlanetDetail;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Bundle bundle = getArguments();
        if (null != bundle) {
            strPlanetName = bundle.getString("Planet_Name");
        }
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.planet_name, container, false);

        TextView txtPlanetName = (TextView) rootView.findViewById(R.id.txtPlanetName);
        txtPlanetName.setText(strPlanetName);

        return rootView;
    }
}

Fragment Planet List Class:

import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.support.annotation.Nullable;
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 com.meditab.fragments.Callback;
import com.meditab.fragments.R;

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

/**
 * Created by BHARGAV on 25-Dec-14.
 */
public class FragmentPlanetList extends Fragment {

    private ListView listView;
    private ArrayAdapter<String> stringArrayAdapter;

    private Callback callback;


    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        final View rootView = inflater.inflate(R.layout.listview, container, false);

        listView = (ListView) rootView.findViewById(R.id.listView);
        stringArrayAdapter = new ArrayAdapter<>(getActivity(),
                android.R.layout.simple_list_item_1, getPlanetArray());
        listView.setAdapter(stringArrayAdapter);

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                callback.onListItemClicked(position);
            }
        });
        return rootView;
    }



    @Override
    public void onAttach(Activity activity) {

        super.onAttach(activity);

        callback = (Callback) activity;
    }

    private List<String> getPlanetArray() {
        List<String> lstPlanets = new ArrayList<>(5);
        lstPlanets.add("Mercury");
        lstPlanets.add("Venus");
        lstPlanets.add("Earth");
        lstPlanets.add("Mars");
        lstPlanets.add("Jupiter");
        lstPlanets.add("Saturn");
        lstPlanets.add("Uranus");
        lstPlanets.add("Neptune");
        lstPlanets.add("Saturn");

        return lstPlanets;
    }

}

Callback Interface:

/**
 * Created by BHARGAV on 26-Dec-14.
 */
public interface Callback {

    public void onListItemClicked(int intPosition);
}

Thanks. Please let me know if any additional detail or code is needed.

Upvotes: 3

Views: 1964

Answers (5)

Bhargav Jhaveri
Bhargav Jhaveri

Reputation: 2183

Ok. So the reason why it is not working is the conflict of ActionBarActivty and Activity class differences. And the differnce between getSupportFragmentManager() and getFragmentManager() methods of FragmentTransaction.

ActionBarActivity:

I was using ActionBarActivity which is android.support.v7.app.ActionBarActivity. This means I was using v7 compat library

FragmentManager: Fragment Manager were not from the compat library. It was directly

import android.app.FragmentManager;
import android.app.FragmentTransaction;

as you can see in the MainActivity class.

Fragment: android.app.Fragment; is the class which is imported in the separate fragment classes.

So once I changed from ActionBarActivity to Activity class, things were working fine. The same holds true when I changed the FragmentManager,FragmentTransaction and Fragment classes to support library classes.

So after any of the modification, things started working normally. Thanks.

Upvotes: 6

mt0s
mt0s

Reputation: 5821

Well I was having the same problem with you. What worked for me and I think its the solution for you too is to change the :

1.fragment with the fragment from the support library :

import android.support.v4.app.Fragment;

and

  1. getFragmentManager() with the getSupportFragmentManager() :

Upvotes: 0

Tejash Thakkar
Tejash Thakkar

Reputation: 1

You are using actionbar activity which extends fragment activity. Now, to have perfect behaviour, you need support fragments to work with actionbar activity.

Here you are using actionbar activity with normal fragments (not support v4 fragments) and that's what is causing the issue. So to have perfect behaviour, change your fragments to support fragments and it should work fine.

Let me know if that doesn't work.

Upvotes: 0

Hirak Chhatbar
Hirak Chhatbar

Reputation: 3181

Wierd, but I think

addToBackStack(null)

is the problem

Try replcing it with

addToBackStack("planetDetail");

Upvotes: 0

Rohit5k2
Rohit5k2

Reputation: 18112

Of course you don't need to override the onBackPressed() method. It's just a hack.

Your this condition is messing it up.

if (isPhone) {
        fragmentTransaction.addToBackStack(null);

why don't you use this statement without condition once to see if it works. You can keep rest as it is. Just move this statement outside of the if condition.

Upvotes: 0

Related Questions