Understanding fragment stack - android

I have a action bar (actionbarsherlock) with tab navigation and I have a couple of action items as well. One of my action items displays a ListFragment and here is how I call it:
case R.id.menuitem_info:
// Create new fragment and transaction
SherlockListFragment aboutListFragment = new AboutListFragment();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
ft.replace(R.id.root, aboutListFragment);
ft.addToBackStack(null);
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
// Commit the transaction
ft.commit();
return true;
My problem is that when I hit the back button, I get an IllegalArgumentException. I'm not sure how to remove the fragment from the view and display the previous view?
Here is my home button code:
case android.R.id.home:
FragmentManager fm = getSupportFragmentManager();
if (fm.getBackStackEntryCount() > 0) {
fm.popBackStack();
}
return true;
Any suggestions would be appreciated!

I did the following in case android.R.id.home:
case android.R.id.home:
FragmentManager fm = getSupportFragmentManager();
if(fm.getBackStackEntryCount()>0){
onBackPressed();
}
return true;
I hope this help you, for me works like a charm

Related

Android Fragment reset when replacing it

I'm currently developing a Android studio App using fragment and a bottom navigation bar.
When I click on a navigation bar's item, it's replacing the current fragment by another one which correspond the fragment I wanted for this item.
The problem is, the objects in my fragment are all reset after replacing fragment.
I'm not removing the fragment from the container so I don't really understand why all the objects are reset after doing this.
Here is my code to add and replace fragment to my FrameLayout :
private void setFragment(Fragment fragment) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.setCustomAnimations(android.R.anim.slide_in_left, android.R.anim.fade_out);
if (getSupportFragmentManager().findFragmentById(R.id.main_frame) == null) {
fragmentTransaction.add(R.id.main_frame, fragment);
}
else
{
fragmentTransaction.replace(R.id.main_frame, fragment);
}
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
and here is the bottom navigation bar code to execute the previous function and change the displayed fragment:
homeFragment = new HomeFragment();
programFragment = new ProgramFragment();
bluetoothFragment = new BluetoothFragment();
mMainNav.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
test = mMainNav.getMenu().getItem(2);
switch (item.getItemId()) {
case R.id.nav_home:
//mMainNav.setItemBackgroundResource(R.color.colorPrimary);
HQ_logo_IV.setVisibility(View.VISIBLE);
setFragment(homeFragment);
return true;
case R.id.nav_program:
//mMainNav.setItemBackgroundResource(R.color.colorAccent);
HQ_logo_IV.setVisibility(View.INVISIBLE);
setFragment(programFragment);
return true;
case R.id.nav_bluetooth:
//mMainNav.setItemBackgroundResource(R.color.colorPrimaryDark);
HQ_logo_IV.setVisibility(View.INVISIBLE);
setFragment(bluetoothFragment);
return true;
default:
return false;
}
}
});
I found the way to stop this thing.
I used an AsyncTask to refresh my fragment state.
I just put new "yourAsyncTaskName"().execute() at the beginning of my onCreate() method to refresh the fragment when it's created or replaced.
Hope this will help.

prevent same fragment multiple times in backstack

Hi guys here is my code
navigationView.setNavigationItemSelectedListener(new NavigationView
.OnNavigationItemSelectedListener() {
#Override public boolean onNavigationItemSelected(#NonNull MenuItem item) {
if (item.isChecked()) {
//item already selected. Do nothing
drawerLayout.closeDrawer(GravityCompat.START);
return true;
}
switch (item.getItemId()) {
case R.id.home:
FragmentTransaction transaction = getSupportFragmentManager()
.beginTransaction();
transaction.replace(R.id.fragment, new HomeFragment())
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE).commit();
break;
case R.id.other:
transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment, new OtherFragment())
.addToBackStack(null).setTransition(FragmentTransaction
.TRANSIT_FRAGMENT_FADE).commit();
break;
default:
break;
}
drawerLayout.closeDrawer(GravityCompat.START);
return true;
}
});
I basically only have 2 fragments and merely the HomeFragment should be added to the backstack. After switching between HomeFragment and OtherFragment for a while and clicking on the back button while on the HomeFragment, I end up with the HomeFragment getting displayed several times.
Within the HomeFragment lies a recyclerview. When I scroll up and down I can really see that the rows are displayed multiple times.
How can I make sure that the HomeFragment is added to the backstack only once.
Thanks
You could easily check your fragment with
YourFragment.isAdded
And if you have a multiple fragment you could create a new class to manage all the fragment and create state to check if fragment have been added or not.
When you click on the Home menu item try to find out whether there is any fragment in the backstack or not. If yes, call popBackStack() or replace a fragment as you do now otherwise. Use this code: if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack();
}

Changing content_main.xml onNavigationItemSelected

Is it possible to use multiple content_main.xml to change the MainActivity onNavigationItemSelected or is there a better way to do this?
the right way to It would be using multiple fragments in the main activity
GO to android studio and create a new project select the navigation drawer template you will get an example code now create fragments and add them on the navigation menu onNavigationItemSelected event.
If what you are looking for is to have different layouts for your items in
NavigationDrawer. Better consider using Fragments.
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_list) {
ListFragment fragment = new ListFragment();
android.support.v4.app.FragmentTransaction fragmentTransaction =
getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment);
fragmentTransaction.commit();
} else if (id == R.id.nav_gallery) {
GalleryFragment fragment = new GalleryFragment();
android.support.v4.app.FragmentTransaction fragmentTransaction =
getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment);
fragmentTransaction.commit();
}
return true;
}
this would help you to navigate to different fragment in your NavigationItem.
Hope it helps.

Replace fragments in FrameLayout layout

I have tried every tutorial on the first google page about android fragments, but I can't get anything to work.
So I have one navigation bar activity, MainActivity.
Now I'd like to change fragments on a click in the drawer.
In my content_main (default fragment in the MainActivity activity), I have a framelayout that I wish to put the fragments in. I have the following fragments: fragment_main, fragment_one and fragment_two. And I wish to show these when I click on a button in the nav drawer.
The reason I want to use fragments is so that the nav drawer will stay on top.
Thanks in advance!
Edit: Here is the function I'll use to change fragments:
It's just to test, not finished.
public void setFragment() {
android.support.v4.app.FragmentTransaction transaction;
transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, new LoginFragment());
transaction.commit();
}
I solved it!
Apparently, I had to use android.support.v4.app.Fragment; instead of android.app.Fragment;.
This is the code I got it to work with:
protected void setFragment(Fragment fragment) {
android.support.v4.app.FragmentTransaction t = getSupportFragmentManager().beginTransaction();
t.replace(R.id.fragment_container, fragment);
t.commit();
}
And to set it (from the nav bar onNavigationItemSelected(), you do this:
setFragment(new RoosterFragment());
I hope this helps others out with the same frustrating problem.
Accroding to your question,
This is FrameLayout
<FrameLayout
android:id="#+id/main_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/view"
android:layout_marginTop="#dimen/medium_margin"></FrameLayout>
Now , call displayview method onCreate() of your activity,
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//rest of your code here
displayView(0); // fragment at 0 position
}
displayView method, which have three fragements
public void displayView(int position) {
switch (position) {
case 0:
tvTitle.setText(getResources().getString(R.string.signin_tile));
showFragment(new LoginFragment(), position);
break;
case 1:
tvTitle.setText(getResources().getString(R.string.forgot_password_tile));
showFragment(new ForgotPasswordFragment(), position);
break;
case 2:
tvTitle.setText(getResources().getString(R.string.change_password_tile));
showFragment(new ChangePasswordFragment(), position);
break;
}
}
showFragment method called from displayView method,
public void showFragment(Fragment fragment, int position) {
FragmentTransaction mTransactiont = getSupportFragmentManager().beginTransaction();
mTransactiont.replace(R.id.main_container, fragment, fragment.getClass().getName());
mTransactiont.commit();
}
Did you try this? Click here
This link will Help you, to create fragment.
and this is what you want for navigation drawerClick here
Try this one. it is my newbie code easier to understand :)
FragmentTransaction transaction;
switch (id){
case R.id.button_fragment_one:
transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_layout, new FragmentOne());
transaction.addToBackStack(null);
transaction.commit();
break;
case R.id.button_fragment_two:
transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_layout, new FragmentTwo());
transaction.commit();
break;
default:
break;
}

setCustomAnimations not working on back button press

I've got this issue where transitions from fragment A to B working fine but on backPress they do not. Looking around I saw many with this issue but none of the answers seems to help me out. I must be doing something wrong but have no idea what and I would love some help, it drives me nuts!
This is my logic:
Fragment A calling fragment B:
private void loadNextFragment(WeatherComplete[] weatherDataArrayList) {
FragmentManager fm = getFragmentManager();
MainFragment mf = MainFragment.newInstance();
mf.setVars(choosenCity, weatherDataArrayList);
FragmentTransaction ft = fm.beginTransaction();
ft.setCustomAnimations(R.anim.slide_in, R.anim.slide_iout, R.anim.slide_in, R.anim.slide_iout);
ft.addToBackStack(null);
ft.replace(R.id.frame, mf);
ft.commit();
}
Fragment B calling fragment C (Settings) from menu:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_settings:
final FragmentManager fm = getActivity().getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.setCustomAnimations(R.anim.slide_in, R.anim.slide_iout, R.anim.slide_in, R.anim.slide_iout);
ft.replace(R.id.frame, new Settings(), "settings");
ft.commit();
break;
I'm passing an object array from fragment A to fragment B, thus when clicking the back button on fragment C it will go back to fragment B but there is no object array to work with so in that case I want fragment C to go back to fragment A instead - I'm popping the backStack:
if (weatherDataObj == null) {
Log.d(TAG, "WEATHER DATA IS NULL");
FragmentTransaction ft = getFragmentManager().beginTransaction();
getFragmentManager().popBackStack();
// ft.remove(this);
ft.commit();
}
Try using this:
ft.setCustomAnimations(R.anim.slide_in, R.anim.slide_iout,
R.anim.slide_in, R.anim.slide_iout);

Categories

Resources