Android Fragment transaction - replacing fragment leaves the old one with strange state - android

I have strange behaviour. Every time i replace the same type of fragment in Activity (using transaction), the new Fragment instance is added to Fragment List. The old instances remains active in Fragment Manager and after orientation change are visible on the screen (although not clickable).
My Activity Layout:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
-->
<!-- A DrawerLayout is intended to be used as the top-level content view using match_parent for both width and height to consume the full space available. -->
<android.support.v4.widget.DrawerLayout
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.cubesoft.zenfolio.moments.app.activity.MainActivity" >
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</FrameLayout>
<fragment
android:id="#+id/navigation_drawer"
android:name="com.cubesoft.zenfolio.moments.app.fragment.NavigationDrawerFragment"
android:layout_width="#dimen/navigation_drawer_width"
android:layout_height="match_parent"
android:layout_gravity="start"
tools:layout="#layout/fragment_navigation_drawer" />
</android.support.v4.widget.DrawerLayout>
<fragment
android:id="#+id/fragmentConnectionStatus"
android:layout_width="match_parent"
android:layout_height="wrap_content"
class="com.cubesoft.zenfolio.fragment.ConnectionStatusFragment" />
My code that changes fragments:
#Override
public void onNavigationDrawerItemSelected(int position) {
mCurrentDrawerPosition = position;
// update the main content by replacing fragments
List<Fragment> fragmemts = getSupportFragmentManager().getFragments();
switch (position) {
case 0:{
if ( getMyApplication().getGroupModel().getUsersCount() > 0 ) {
final Fragment fragment = UserSelectionFragment.newInstance();
final FragmentManager fragmentManager = getSupportFragmentManager();
//fragmentManager.popBackStack();
final FragmentTransaction tr = fragmentManager
.beginTransaction();
tr.replace(R.id.container, fragment);
tr.addToBackStack(null);
tr.setCustomAnimations(R.anim.abc_fade_in, R.anim.abc_fade_out);
tr.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
tr.commit();
} else {
final Fragment fragment = MomentsFragment.newInstance(mUsername);
final FragmentManager fragmentManager = getSupportFragmentManager();
//fragmentManager.popBackStack();
final FragmentTransaction tr = fragmentManager
.beginTransaction();
tr.replace(R.id.container, fragment);
//tr.setCustomAnimations(R.anim.abc_fade_in, R.anim.abc_fade_out);
tr.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
tr.addToBackStack(null);
tr.commit();
}
break;
}
case 1: {
final Fragment fragment = DownloadFragment.newInstance();
final FragmentManager fragmentManager = getSupportFragmentManager();
//fragmentManager.popBackStack();
final FragmentTransaction tr = fragmentManager
.beginTransaction();
tr.replace(R.id.container, fragment);
tr.addToBackStack(null);
tr.commit();
break;
}
/*case 2:
fragment = UserSelectionFragment.newInstance();
break;*/
}
}
The UserSelectionFragment is displayed incorrectly after several orientation changes, old instances of UserSelectionFragment remains in Fragment List but their View objects are null.
What is wrong?

Try removing
tr.addToBackStack(null);
To me this adds your frgament to the backstack and thats the reason why they are kept in your fragment list. Their view are null because they have been destroyed before going to backgroud.

Related

Fragments overlapping on FrameLayout

I am trying to add multiple fragments to a FrameLayout. I need to add them one below another. But they are overlapping.
main_layout.xml
<?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>
MainActivity.java
public class MainActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
// Create instance of fragments
FragmentPrimaryList firstFrag = new FragmentPrimaryList();
FragmentSecondaryList secFrag = new FragmentSecondaryList();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
// add fragment to the fragment container layout
fragmentTransaction.add(R.id.fragment_container,firstFrag);
fragmentTransaction.add(R.id.fragment_container,secFrag);
fragmentTransaction.commit();
}
}
They looks like this. How can I solve this?
Use the replace method instead of the add method.
The replace method hides the current fragment before adding new one, the add method simply adds the new fragment without disposing off the older fragment.
In order to retain the back stack, use the fragment transaction with backstack management.
I need to display both fragments at same time, one below another
You can try the following layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<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>
</LinearLayout>
Now add fragmments using:
fragmentTransaction.add(R.id.fragment_container1,firstFrag);
make sure you Fragment's layout_height = "wrap_content"
Add background to your fragments and make "android:clickable="true" to parent layout.
Do this way:
First fragment
FragmentPrimaryList firstFrag = new FragmentPrimaryList();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
// add fragment to the fragment container layout
fragmentTransaction.add(R.id.fragment_container,firstFrag);
fragmentTransaction.commit();
second fragment
FragmentSecondaryList secFrag = new FragmentSecondaryList();
fragmentManager = getSupportFragmentManager();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.fragment_container,secFrag);
fragmentTransaction.commit();

Fragment elements remain even when the fragment has been changed

I'm using a navigation drawer to switch fragments, but elements from the first fragment stay present even on changing fragments.
The code of the main activity:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
...
Drawer result = new DrawerBuilder()
.withActivity(this)
.withToolbar(toolbar)
.addDrawerItems(
item1,
new DividerDrawerItem(),
item2,
new SecondaryDrawerItem().withName(R.string.drawer_item_settings)
)
.withOnDrawerItemClickListener(new Drawer.OnDrawerItemClickListener() {
#Override
public boolean onItemClick(View view, int position, IDrawerItem drawerItem) {
// do something with the clicked item :D
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
Fragment fragment = new Fragment();
switch (position)
{
case 0:
fragment = new HomeFragment();
Log.d("Switch", "Search");
break;
case 1:
break;
case 2:
fragment = new InventoryFragment();
Log.d("Switch", "Inventory");
break;
case 3:
fragment = new SettingsFragment();
Log.d("Switch", "Settings");
break;
}
transaction.replace(R.id.main_frame, fragment);
transaction.commit();
return false;
}
})
.build();
}
The following is the code for activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:background="?android:windowBackground"
tools:context="com.example.nihal.xchange.MainActivity">
...
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:id="#+id/main_frame">
<fragment
android:name="com.example.nihal.xchange.HomeFragment"
android:id="#+id/current_fragment"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</FrameLayout>
</android.support.design.widget.CoordinatorLayout>
Elements from Home Fragment remain present across fragments but this behavior is not exhibited by elements of other fragment.
How do I prevent this from happening?
Don't include the Home Fragment in the xml. Keep your container FrameLayout empty and add the initial fragment as soon as the activity starts. In your Activity's onCreate method, add the Home fragment dynamically in the beginning.
activity_main.xml -
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:id="#+id/main_frame">
<!-- Removed the fragment from here -->
</FrameLayout>
In the onCreate(), add it dynamically -
if (findViewById(R.id.main_frame) != null) {
if (savedInstanceState != null)
return;
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(R.id.main_frame, new HomeFragment());
transaction.commit();
}

Navigation Drawer- Displaying home fragment as default

I have attached navigation drawer to main Activity of my application.
Navigation drawer have 4 options that will navigate user to 4 different fragments f1, f2, f3 and f4.
I have created a home page Fragment fh.
I am not adding fh as a choices in Navigation Drawer.
Fragment fh populates data making http call.
Whenever user selects f1, f2, f3 or f4; the respective fragments need to be shown back.
Till here everything is working fine.
However, whenever user press back button, then fh should be displayed. ie. content_frame should contain fh.
I am unable to do this portion.
Right now, whenever user press back button, the default view is blank.
Also, since fh makes a http call to populate data, so fh that was added to stack needs to be shown.
Here is my implementation:
MainActivity- OnCreate
mDrawerLayout.closeDrawer(mDrawerList);
setUpHomeFragment();
Here is how I am managing fragment, on navigation drawer item clicked...
private void showFrg(Fragment fragment){
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.addToBackStack(null);
fragmentTransaction.replace(R.id.content_frame, fragment).commit();
}
The setUpHomeFragment Function, that is called just once on activity oncreate()
private void setUpHomeFragment(){
mLandingPageFragment=new ReadyMyOrderCollections();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.replace(R.id.content_frame, mLandingPageFragment);
ft.addToBackStack(null);
ft.commit();
}
MainActivity XML Layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<include layout="#layout/toolbar" />
<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/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<include
android:layout_width="#dimen/drawer_width"
android:layout_height="match_parent"
android:layout_gravity="start"
layout="#layout/list_view" />
</android.support.v4.widget.DrawerLayout>
</LinearLayout>
I found the cleanest approach for this issue here:
https://stackoverflow.com/a/21093352/1348550
Call setUpLandingFragment just once on activity onCreate.
private void setUpLandingFragment(){
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.popBackStack();
fragmentManager.beginTransaction()
.add(R.id.content_frame, new LandingFragment()).commit();
}
On navigation drawer item click:
private void changeFrag (Fragment f) {
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.popBackStack();
fragmentManager.beginTransaction()
.add(R.id.content_frame, f).addToBackStack("fragBack").commit();
}
The coolest part about this solution is, onBackPressed is not needed at all.
My work around for this is
private int getFragmentCount() {
return getSupportFragmentManager().getBackStackEntryCount();
}
In your Activity
#Override
public void onBackPressed() {
if(getFragmentCount()>0) {
getSupportFragmentManager().popBackStackImmediate();
}else{
super.onBackPressed();
}
}

can't replace fragment within fragment

I've got a ListFragment with this:
public void fragmentSelection(Integer count) {
Fragment fr;
if (count == 0) {
fr = new Fragment1();
} else {
fr = new Fragment2();
}
FragmentManager fm = getFragmentManager();
FragmentTransaction fragmentTransaction = fm.beginTransaction();
fragmentTransaction.replace(R.id.content, fr, fr.getClass().getName());
fragmentTransaction.commit();
}
here I am trying to replace the fragment content with fr (depends on count value)..
the part from XML looks like this
<fragment
android:id="#+id/content"
android:name="com.test.app.DefaultContent"
android:layout_width="match_parent"
android:layout_height="match_parent">
</fragment>
Now when I want to replace fragment "content" with "fr" it do not replace it 1:1 - it adds fr down to the already current fragment (here DefaultContent) - so - why it does not replace it? What I have to do, that it replaces it and not puts the fr in addition below the current fragment
The View ID you pass to replace(), in your case R.id.content, has to be the ID of the Fragment's parent View, not the original Fragment itself.
That means you have to set android:id="#+id/content" to the Fragment's parent, like this:
<FragmentLayout
android:id="#+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:name="com.test.app.DefaultContent"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FragmentLayout>
Or, if that does not work for you, set a new ID to the parent and use it for replace().

Fragment Default View Wont Change

i really need help.
This is how my application looks like. I got two(2) fragments where the left side is for the buttons and for the right side is for my details.
The bigger fragment has a default display which i called splash. An image is viewed here, a bigger image that would take the height of the device.
So my case is when i click/press button 1, it would display the fragment for that but the image is still present.
My question now is, how to i get rid of the 'splash display'?
Here is my code
/**
* on main listener
*/
#Override
public void onMainListener(String whatPress){
Fragment fr = null;
if(whatPress.equals("button1"))
fr = new FragmentOne();
if(whatPress.equals("button2"))
fr = new FragmentTwo();
if(whatPress.equals("button3"))
fr = new FragmentThree();
FragmentManager fm = getFragmentManager();
FragmentTransaction fragmentTransaction = fm.beginTransaction();
fragmentTransaction.replace(R.id.detailFragment, fr, whatPress);
fragmentTransaction.commit();
}
The code above is the one handles which button is pressed.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<fragment
android:id="#+id/menuFragment"
android:name="FragmentMenu"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
class="com.mizsh.Fragment_Menu" />
<fragment
android:id="#+id/detailFragment"
android:name="com.mizsh.Fragment_Splash"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent" />
</LinearLayout>
The code above is my main.xml
You should replace the detailFragment with FrameLayout
<FrameLayout android:id="#+id/detailFragment" android:layout_weight="1"
android:layout_width="0px" android:layout_height="match_parent" />
and replace it with Fragment_Splash in the onCreate of the activity
FragmentTransaction fragmentTransaction = fm.beginTransaction();
fragmentTransaction.replace(R.id.detailFragment, fragmentSplash, null);
fragmentTransaction.commit();
then replace with chosen fragment on click
FragmentTransaction fragmentTransaction = fm.beginTransaction();
fragmentTransaction.replace(R.id.detailFragment, chosenFragment, null);
fragmentTransaction.commit();

Categories

Resources