Back Button with strange behaviour on fragments - android

Here's my navigation:
HomeFragment -> LoginFragment -> CreateEventFragment
My HomeFragment is my first Fragment inside my MainActivity.
In my code, I'm replacing each one of them using the same view id( a FrameLayout inside my MainActivity's layout: R.id.container).
So every replace() is being called like this:
FragmentManager fragmentManager = mContext.getSupportFragmentManager();
fragmentManager.beginTransaction()
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
.replace(containerId, nextFragment).addToBackStack(null).commit();
Except for LoginFragment to CreateEventFragment, because after the user logs in, he doesn't have to go back to LoginFragment so I don't call addToBackStack().
But something strange is happening:
When I'm on CreateEventFragment, after logging in successfully, and press the back button, my CreateEventFragment onDestroy() is not being called.
Debugging it I noticed that it isn't removed from the backStack, what am I doing wrong?
EDIT
Some code:
Common replace fragment method, inside BaseFragment, parent class of all three Fragments
public void replaceFragment(int containerId, Fragment nextFragment, boolean addToBackStack){
FragmentManager fragmentManager = mContext.getSupportFragmentManager();
if (addToBackStack)
fragmentManager.beginTransaction()
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
.replace(containerId, nextFragment).addToBackStack(null).commit();
else
fragmentManager.beginTransaction()
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
.replace(containerId, nextFragment).commit();
}
On HomeFragment:
BaseFragment nextFragment =
(PreferencesHandler.isLogged()) ?
CreateEventFragment.newInstance() :
LoginFragment.newInstance("create_event") ;
replaceFragment(R.id.main_fragment_container, nextFragment, true);
On LoginFragment:
public void goToNextFragment(){
Fragment nextFragment;
switch (mIntent){
case "create_event":
nextFragment = new CreateEventFragment();
break;
case "participate":
nextFragment = new ListsFragment();
break;
default:
nextFragment = new HomeFragment();
break;
}
replaceFragment(R.id.main_fragment_container, nextFragment, false);
}
My MainActivity's layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
android:id="#+id/toolbar_actionbar"
layout="#layout/toolbar_actionbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white"
android:layout_below="#+id/toolbar_actionbar"
tools:context=".MainActivity">
<FrameLayout
android:id="#+id/main_fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/toolbar_actionbar"
/>
<fragment android:id="#+id/navigation_drawer"
android:layout_width="#dimen/navigation_drawer_width"
android:layout_height="match_parent"
android:layout_gravity="start"
android:name="Fragments.`NavigationDrawerFragment`"
tools:layout="#layout/fragment_navigation_drawer" />
</android.support.v4.widget.DrawerLayout>
</RelativeLayout>
EDIT 2
Noticed that pressing back button calls LoginFragment onDestroy, but not CreateFragment's. Also noticed that backStack has LoginFragment, guess it shouldn't, right?

Related

Fragment to fragment to fragment get crash

I have a main activity , it contains lots of fragments.
Main activity layout looks like this:
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.user.taiwandigestionsociety_v11.MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FFFFFF">
<include layout="#layout/toolbar"/>
//switch fragment over here
<FrameLayout
android:id="#+id/mainFrame"
android:layout_gravity="end"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
</android.support.design.widget.AppBarLayout>
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#android:color/transparent"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header">
</android.support.design.widget.NavigationView>
</android.support.v4.widget.DrawerLayout>
and I click the drawer item it will change to first fragment:
#Override
public void onClick(View view) {
int id = view.getId();
if (id == R.id.activitiesContents) {
//change to first fragment successful
switchFragment(ActivityList.newInstance());
toolbar.setTitle(R.string.activitiesContents);
drawerLayout.closeDrawer(GravityCompat.START);
}
}
my switch fragment function:
public void switchFragment(Fragment fragment) {
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.mainFrame, fragment, null);
//transaction.addToBackStack(null);
transaction.commit();
}
then i click the button in first fragment, it changes to second fragment too:
//take me to second fragment succeed
switchFragment(ActivityHomePage.newInstance());
finally i click the button in second fragment, it crashed
//i want to switch to third fragment , just the same with previous
switchFragment(NewsInformation.newInstance());
the error log:
Why i got crash when i switch to third fragment? I completely have no clue.
I found the crash function function , because I set the class:
public class CommonSwitch extends Fragment {
//switch Fragment
public void switchFragment(Fragment fragment) {
FragmentManager manager = getActivity().getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.mainFrame, fragment, null);
//transaction.addToBackStack(null);
transaction.commit();
}
}
and I try to call it new CommonSwitch.switchFragment(goToFragment);
now I have set public void switchFragment every Fragment class.
Why when I set new CommonSwitch will cause crash ?
Your Activity state is Not Maintain.
On second layer use Activity instead of Fragment . Follow Android Standards.
According to standards Third Fragment should be Activity. otherwise you have to maintain MainActivity state.
Thanks

Android Fragment animation on replacement doesn't work

I've got an activity in which there are 2 fragments which changes basing on a button click.
I'd like to show an animation when the replacement appens, so i searched for the code and here's what i concluded:
public void displayView(int page){
switch (page){
case 1:
FragmentHome fragmentHome = new FragmentHome();
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment, fragmentHome)
.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out).commit();
break;
case 2:
FragmentHomeBack fragmentHomeBack = new FragmentHomeBack();
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment, fragmentHomeBack)
.setCustomAnimations(android.R.anim.accelerate_decelerate_interpolator, android.R.anim.anticipate_interpolator).commit();
break;
}
}
I don't know why but the animations don't works, the new fragment just replace the other without animation.
Here's the activity layout code:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/activity_master"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="#dimen/space10"
tools:context="context">
<include
android:id="#+id/ll_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="#dimen/space5"
android:orientation="vertical"
android:layout_marginLeft="#dimen/space5"
android:layout_marginRight="#dimen/space15"
layout="#layout/menu"
android:layout_alignParentTop="true"
android:layout_above="#+id/imageView" />
<FrameLayout
android:id="#+id/fragment_holder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_toRightOf="#id/ll_left">
</FrameLayout>
<ImageView
app:srcCompat="#drawable/xlink"
android:id="#+id/imageView"
android:layout_width="150dp"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"
android:scaleType="fitEnd"
android:layout_height="70dp" />
The frame layout "fragment_holder" is where the Fragments are.
Thanks to everybody!
That should do the trick buddy. I have the same code and it works well.
getSupportFragmentManager()
.beginTransaction()
.setCustomAnimations(android.R.anim.fade_in,android.R.anim.fade_out)
.replace(R.id.layout_container, fragment)
.commit();
But..
I see what is the difference in our code. Try setting customAnimations before replace to see what happens.
And I have a suggestion to improve your code. In your "if" or "switch" statement set the fragment like
Fragment fragment;
if(page==0){
fragment = new MyFragment();
}else{
fragment = new MySecondFragment();
}
then you only have this code once
getChildFragmentManager()
.beginTransaction()
.setCustomAnimations(android.R.anim.fade_in,android.R.anim.fade_out)
.replace(R.id.layout_container, fragment)
.commit();

Fragment within fragment in an activity as main layout

I'm kinda new in android and I'm developing an application but I am blocked with something:
I have my activity_main:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
And this activity contains 1 fragment(drawer_layout_fragment) and my fragment(drawer_layout_fragment) contains another fragment(left_drawer) that is the nav drawer fragment:
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drawer_layout_fragment"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="DrawerLayoutFragment">
<!-- The navigation drawer -->
<fragment
android:id="#+id/left_drawer"
android:name="NavigationDrawerFragment"
android:layout_width="300dp"
android:layout_height="match_parent"
android:layout_gravity="start"
tools:layout="#layout/fragment_navigation_drawer"/>
</android.support.v4.widget.DrawerLayout>
Everything works fine when I add that fragment to the fragment manager but when I'm in the next view and I clicked back button I'm seeing this error: Duplicate id 0x7f0d00a5, tag null, or parent id 0x7f0d00f4 with another fragment
I have read that error happens because of I have nested fragments but not sure how can I handle this I have tried added my drawer_layout fragment with the getChildFragmentManager but same error.
And this is how I added my drawer_layout fragment to the fragment manager:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DrawerLayoutFragment fragment = new DrawerLayoutFragment();
getSupportFragmentManager()
.beginTransaction()
.add(R.id.fragment_container, fragment)
.commit();
}
And this is the code inside DrawerLayoutFragment that takes me to the next fragment. The only difference is that here I use .replace instead of .add :
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.add) {
NextFragment fragment = new NextFragment();
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragment_container, fragment)
.commit();
}
return super.onOptionsItemSelected(item);
}

Changing fragments is showing last fragment for 1 second

I am changing fragments inside framelayout.This is my main activity layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" xmlns:app="http://schemas.android.com/apk/res/com.impact.ribony">
<com.astuetz.PagerSlidingTabStrip
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="48dip"
android:visibility="gone"
app:pstsIndicatorColor ="#0B0B16"
app:pstsShouldExpand="true" />"
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/pager"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/tabs">
</android.support.v4.view.ViewPager>
</RelativeLayout>
Firstly I am showing login fragment then user logins I am hiding framelayout.Because I am using viewpager.If user wants go to settings I am loading settings fragment then I am showing framelayout again.
But I have a problem,you can see it here: http://youtu.be/H6AO7yYusjM
You can see when user goes to settings fragment,firstly login fragment showing for 1 second then settings fragment is loading.How can I prevent this ? (When I try to change fragment always showing last fragment for 1 second not just login fragment)
If user logins successfully I am removing login fragment with following lines:
pager.setVisibility(View.VISIBLE);
tabs.setVisibility(View.VISIBLE);
FrameLayout layout = (FrameLayout)findViewById(R.id.container);
layout.setVisibility(View.GONE);
I am loading login fragment with following code:
FrameLayout layout = (FrameLayout)findViewById(R.id.container);
layout.setVisibility(View.VISIBLE);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
LoginFragment conv = new LoginFragment();
loginObj=LoginFragment.newInstance("asd");
fragmentTransaction.replace(R.id.container, loginObj,"LoginFragment");
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
actionBar.hide();
pager.setVisibility(View.GONE);
I am loading settings fragment with following code:
FrameLayout layout=(FrameLayout)findViewById(R.id.container);
pager.setVisibility(View.GONE);
tabs.setVisibility(View.GONE);
FragmentManager fragmentManager=getSupportFragmentManager();
FragmentTransaction fragmentTransaction=fragmentManager.beginTransaction();
SettingsFragment conv=new SettingsFragment();
SettingsFragment.newInstance(LOGGED_USERNAME);
fragmentTransaction.replace(R.id.container,conv);
fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
layout.setVisibility(View.VISIBLE);

Changing to DrawerLayout in Portrait Mode in Android

I've got a question.
I have a fragment, which inflates two other fragments (Fragment A is left, Fragment B is right)
I want to hide Fragment A when the user changes the mode to portrait-mode.
I added in the layout-port/xml a DrawerLayout and added the code for the NavigationDrawer in my Fragment, but it doesn't work.
Does anyone have an idea, how to realize it?
Thanks :)
I've solved the first problem with this code:
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
orientation = newConfig.orientation;
switch (orientation) {
case Configuration.ORIENTATION_LANDSCAPE:
FragmentA fragmentleft = new FragmentA();
FragmentB fragmentright = new FragmentB();
FragmentTransaction transaction1 = getSupportFragmentManager()
.beginTransaction();
FragmentTransaction transaction2 = getSupportFragmentManager()
.beginTransaction();
transaction1.replace(R.id.framelayout_left, fragmentleft);
transaction2.replace(R.id.framelayout_right, fragmentright);
transaction1.commit();
transaction2.commit();
break;
case Configuration.ORIENTATION_PORTRAIT:
createNavigationDrawer();
Log.d("TEST", "Portrait");
break;
}
}
But now I have the problem, that i have to inflate FragmentA in my ListView of the DrawerLayout:
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<FrameLayout
android:id="#+id/framelayout_right"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ListView
android:id="#+id/framelayout_left_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#111"
android:choiceMode="singleChoice"
android:divider="#android:color/transparent"
android:dividerHeight="0dp" />
But how can I do this?
It doesn't work properly :(
I had also tried to change the ListView to a FrameLayout and inflate the FragmentA within it, but it didn't work too:(
I would be very thankful, if somebody could help me :)

Categories

Resources