Android Fragment switching from navigation drawer causes app to quit - android

I have the slider menu displayview method as:
private void displayView(int position) {
// update the main content by replacing fragments
Fragment fragment = null;
switch (position) {
case 0:
fragment = new HomeFragment();
FragmentManager fm = getSupportFragmentManager();
String tag = fragment.getTag(); // instance method of a to get a tag
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.frame_container, fragment, tag);
ft.addToBackStack(tag);
ft.commit();
default:
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.frame_container, fragment).commit();
// update selected item and title, then close the drawer
drawerListView.setItemChecked(position, true);
drawerListView.setSelection(position);
setTitle(navMenuTitles[position]);
drawer.closeDrawer(drawerListView);
} else {
// error in creating fragment
Log.e("MainActivity", "Error in creating fragment");
}
}
I have a fragment called home_fragment whose code behind is HomeFragment.java
When I click on this fragment first it works fine, but on clicking next from the siding menu at index 0 I get an error as:
Attempt to write to field 'int android.support.v4.app.Fragment.mNextAnim' on a null object reference
What am I doing wrong? Thanks.
This is where I'm having error:
case OP_REMOVE: {
Fragment f = op.fragment;
f.mNextAnim = exitAnim;
mManager.removeFragment(f, transition, transitionStyle);
} break;
This code is present in BackStackRecord.java

You shouldn't be calling container.removeAllViewsInLayout().
The FragmentManager will handle all the view manipulation on the container when you call FragmentTransaction.replace(), including removing the current fragment view. You are probably getting an error because the FragmentManager expects a fragment's view to be in the container, but you've removed it.
All you need is this:
private void displayView(int position) {
// update the main content by replacing fragments
Fragment fragment = null;
switch (position) {
case 0:
fragment = new HomeFragment();
break;
case 1:
// set fragment to other nav target
fragment = ...
break;
.
.
.
default:
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.frame_container, fragment).commit();
// update selected item and title, then close the drawer
drawerListView.setItemChecked(position, true);
drawerListView.setSelection(position);
setTitle(navMenuTitles[position]);
drawer.closeDrawer(drawerListView);
} else {
// error in creating fragment
Log.e("MainActivity", "Error in creating fragment");
}
}
Also I noticed you are using getFragmentManager(). Please check your class imports and make sure that you have the right call.
If HomeFragment extends android.app.Fragment, use getFragmentManager().
If HomeFragment extends android.support.v4.app.Fragment, use getSupportFragmentManager().

Related

How can i get the current Fragment ID

I did a navigation drawer, and I’ve set some items and normally when I select an item the current fragment will be changed by a new one, it's not the case for me, the first Activity still displayed even if the fragments change. This is my onNavigationDrawerItemSelectedmethod and it's clear I change the fragment every time i click on a new one.
#Override
public void onNavigationDrawerItemSelected(int position) {
// update the main content by replacing fragments
FragmentManager fragmentManager = getSupportFragmentManager();
// TODO : Added
switch(position) {
/*case 0 :
fragmentManager.beginTransaction()
.replace(R.id.container, new ProfilFrgement())
.commit();
break;*/
case 1:
fragmentManager.beginTransaction()
.replace(R.id.container, new SpotFragement())
.commit();
break;
case 2:
fragmentManager.beginTransaction()
.replace(R.id.container, new SessionsFragement())
.commit();
break;
/*case 3:
fragmentManager.beginTransaction()
.replace(R.id.container, new EventsFragment())
.commit();
break;*/
}
}
I think my problem is a change always the same container. So what I need its getting the current fragment ID
Sorry for too late but I have a solution to get fragment ID. You can use name of Fragment Class as an Identifier not the ID. Use a static String variable to store class name.
public class Activity{
...
static String currentFragment = null;
...
...
#Override
public boolean onNavigationItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.nav_one:
setFragment(new oneFragment());
break;
case R.id.nav_two:
setFragment(new twoFragment());
break;
}
return true;
}
public static void setFragment(#NonNull Fragment f) {
if(!f.getClass().getName().equals(currentFragment)){
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.container, f);
fragmentTransaction.commit();
currentFragment = f.getClass().getName();
}
...
}
What is current fragment ID here? Ur id is R.id.container which is only one rt? then what is the question about "How can i get the current Fragment ID"?
If question is to find which is the current fragment is shown to user? If yes then
Fragment ft = getSupportFragmentManager().findFragmentById(R.id.container);
if (ft instanceof SpotFragement) {
// navigation drawer item 1 and current fragment is SpotFragment.
} else if (ft instanceof SessionsFragement) {
}
Make sure that your container styling is correct.
Check following values of container once -
android:layout_width
android:layout_height

Replace a Fragment created from Navigation Drawer with another dynamically

I have a navigation drawer that works well. By well I mean I can navigate through all the fragments tied to the Navigation drawer (A,B,C,D). My issue arises here. Lets say am in Fragment A, in this fragment I have a button which on clicking should ideally replace the fragment with another one say Frag Z, and once I am in Frag Z I can return back to frag A.
To achieve this I use the below code. However the new fragment Z appears transparent on top of Fragment A. What could be the problem:
Bundle bundle = new Bundle();
bundle.putInt("int", 1);
bundle.putString("str","string" );
fragmentTransaction = getFragmentManager().beginTransaction();
FragZ fragmentz = new FragZ();
fragment.setArguments(bundle);
fragmentTransaction.replace(R.id.some_container, fragmentz);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
EDIT:
I have found a workaround to this as shown below,however it does not completely solve my problem since the newly displayed fragment is still shown with the navigation drawer capable of being toggled,but it atleast removed the overlaying of the fragments. I would still want a solution to launching an independent fragment
Bundle bundle = new Bundle();
bundle.putInt("int", 1);
bundle.putString("str","string" );
FragZ fragmentz = new FragZ();
FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
fragment.setArguments(bundle);
ft.replace(R.id.main, fragment);
ft.addToBackStack(null);
ft.commit();
Create a method in your activity to launch fragments. Whenever you want to display the fragment, just call in with a number or string to represent the fragment. You can use the same function to launch fragments from your navigation drawer.
For example:
public void displayView(int position) {
Fragment fragment = null;
currentFragmentNumber = position;
switch (position) {
case 0:
fragment = new frag1();
break;
case 1:
fragment = new frag2();
break;
case 2:
fragment = new frag3();
break;
default:
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.frame_container, fragment)
.addToBackStack("tag").commit();
} else {
// error in creating fragment
Log.e(TAG, "Error in creating fragment");
}
}
You can call this function from your activity by using:
((**ActivityName**) getActivity()).displayView(0);

how do I restore the last ListFragment from the current Fragment

My app has structure like this
MainActivity extends ActionBarActivity -- on button press -> ListFragment --on list item press--> Fragment
When in Fragment and if back key is pressed it goes to MainActivity directly . How do I make it to go to the ListFragment
Following is what I expect it to do
Fragment *----on back key pressed-->*ListFragment --on Back Key pressed ---> MainActivity extends ActionBarActivity
Following code is what I am using in mainactivity and listfragment to start any fragment
.........................................
case 5:
fragment = new HomeFragment();
break;
default:
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.frame_container, fragment).commit();
// update selected item and title, then close the drawer
mDrawerList.setItemChecked(position, true);
mDrawerList.setSelection(position);
//getSupportActionBar().setSubtitle(navMenuTitles[position]);
//setTitle(navMenuTitles[position]);
mDrawerLayout.closeDrawer(mDrawerList);
} else {
// error in creating fragment
Log.e("MainActivity", "Error in creating fragment");
}
UPDATE
Now I have added the following code to my MainActivity
#Override
public void onBackPressed() {
Fragment frag = getSupportFragmentManager().findFragmentById(R.id.frame_container);
if((frag instanceof CommonMasjidPrayerTimes)) {
finish();
}
}
And following code to my listfragment
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
// fragmentManager.beginTransaction().replace(R.id.frame_container, fragment).commit();
if (masjidNamazTimings != null) {
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.addToBackStack(null);
ft.replace(R.id.frame_container, masjidNamazTimings).commit();
}
Now when I press the backbutton on my list fragment or fragment it doesnt go back
Your code should look like this:
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.replace(R.id.frame_container, fragment).commit();
ft.addToBackStack(null);
Try this. This will work.
Isn't this missing: .addToBackStack(null)?
See here

Android Navigation Drawer Fragment State

I'm currently utilizing the Navigation Drawer for my Android APP. In my first fragment, I've a fragment that loads data using Facebook's Graph API. Thus, when my App is first loaded, it first goes to the first fragment.
Then, I use the Navigation Drawer to click on another Fragment and view it.
And then finally, I reuse the Navigation Drawer to proceed back to the first Fragment and view it.
My issue that I'm facing is, how do I proceed to utilize the Fragment that has been created once instead of re-creating it whenever the Navigation Drawer Item is selected. My code for the switching of the fragments are as shown below.
private void displayView(int position) {
// update the main content by replacing fragments
Fragment fragment = null;
switch (position) {
case 0:
fragment = new SelectionFragment();
break;
case 1:
fragment = new HomeFragment();
break;
case 2:
fragment = new PhotosFragment();
break;
case 3:
fragment = new CommunityFragment();
break;
case 4:
fragment = new PagesFragment();
break;
case 5:
fragment = new SplashFragment();
break;
default:
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.frame_container, fragment).commit();
// update selected item and title, then close the drawer
mDrawerList.setItemChecked(position, true);
mDrawerList.setSelection(position);
setTitle(navMenuTitles[position]);
mDrawerLayout.closeDrawer(mDrawerList);
} else {
// error in creating fragment
Log.e("MainActivity", "Error in creating fragment");
}
}
I noticed that there is indeed a "new" instance of the Fragment every time whenever the option is selected. How do I go about implementing the logic of creating the Fragment instance ONCE and reusing it, so that I do not have to continuously load the Fragment over and over again.
To anyone who encounters the same issue with me,I've managed to find a solution.
In the container frame,I've to define specific fragment views that I'll be utilizing as shown below.
In each Fragment view,I've to "link" it with the actual Fragment itself as shown below via the "android:name" attribute.Do take note of the the path to the Fragment,example for in my case it's com.example.confesssionsrp.SelectionFragment.
<fragment
android:id="#+id/selectionFragment"
android:name="com.example.confessionsrp.SelectionFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
In the the MainActivity(or the Activity where we're viewing the fragments),create variables for each of the Fragments as shown below.
Following that,in the Oncreate of the MainActivity(or your specific Activity),initialize the various fragments as shown below.
Proceed onto creating a new Method called "ShowFragment" as shown below.
private void showFragment(int fragmentIndex, boolean addToBackStack) {
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
for (int i = 0; i < fragments.length; i++) {
if (i == fragmentIndex) {
transaction.show(fragments[i]);
if (Session.getActiveSession().isClosed()) {
mDrawerLayout
.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
}
} else {
transaction.hide(fragments[i]);
}
}
if (addToBackStack) {
transaction.addToBackStack(null);
}
transaction.commit();
}
From then on in the switching of the fragments,manually call upon the "ShowFragment" method with the selected Fragment as shown below.
Doing all of this overall,will not reset the Fragment each time we view it,and therefore is the solution to the answer.Thank you for anyone who has helped me so far :)!
I am using the following code:
#Override
public void onNavigationDrawerItemSelected(int position) {
// update the main content by replacing fragments
FragmentManager fragmentManager = getFragmentManager();
if(position==0){// selection of tabs content
fragmentManager
.beginTransaction()
.replace(R.id.container,
SimulatorFragment.newInstance(position + 1)).commit();
}else if(position==1){
fragmentManager
.beginTransaction()
.replace(R.id.container,
HudFragment.newInstance(position + 1)).commit();
}else if(position==2){
// Display the fragment as the main content.
fragmentManager
.beginTransaction()
.replace(R.id.container,
SettingsBasicFragment.newInstance(position +1)).commit();
}else{
}
}
You can replace by a new instance the first time and store the fragment, if it is not null, then replace by the stored fragment.
The activity must implement NavigationDrawerFragment.NavigationDrawerCallbacks
The fragment constructor and newInstance methods look like this:
public final class HudFragment extends Fragment {
/**
* The fragment argument representing the section number for this
* fragment.
*/
private static final String ARG_SECTION_NUMBER = "section_number";
/**
* Returns a new instance of this fragment for the given section number.
* #param simulation
*/
public static HudFragment newInstance(int sectionNumber) {
HudFragment fragment = new HudFragment();
Bundle args = new Bundle();
args.putInt(ARG_SECTION_NUMBER, sectionNumber);
fragment.setArguments(args);
return fragment;
}
public HudFragment() {
}
To switch fragments by code I use this method inside the NavigationDrawerFragment:
/**
* Select a different section
* #param position
*/
public void select(int position){
selectItem(position);
}
private void selectItem(int position) {
mCurrentSelectedPosition = position;
if (mDrawerListView != null) {
mDrawerListView.setItemChecked(position, true);
}
if (mDrawerLayout != null) {
mDrawerLayout.closeDrawer(mFragmentContainerView);
}
if (mCallbacks != null) {
mCallbacks.onNavigationDrawerItemSelected(position);
}
}
The second option is to start with the example of navigationDrawer that Android SDK offers. I selected that template of activity when creating the project and almost all the code of my previous answer is produced automatically.
If you want to keep the fragments after device rotation or similars it is a different thing, you need then to retain the fragments. If not, you just need to save the new instance of the fragment in a variable and check if it is null to create a new one or use the old one.
In case someone want's a different approach to this: you could find the fragment on the stack:
// check if this fragment is on the backstack to avoid creating a new one
Fragment foundFragment = fragmentManager.findFragmentByTag("unique_fragment_tag");
if (foundFragment != null) {
fragmentManager.popBackStackImmediate("unique_fragment_tag", 0);
return;
}

Fragment removes when Orientation changes

I am using fragment in my application. When I change the orientation the fragment removes and my main activity gets visible from which I have added this fragment. below is the code -
Fragment fragment = null;
switch (position) {
case 0:
fragment = new ManageDataFragment();
break;
case 1:
fragment = new DownloadFragment();
break;
case 2:
fragment = new UserInfoFragment();
break;
case 3:
fragment = new AboutAppFragment();
break;
case 4:
fragment = new ShareAppFragment();
break;
case 5:
fragment = new SettingsFragment();
break;
default:
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.frame_container, fragment).commit();
// update selected item and title, then close the drawer
setTitle(menutitles[position]);
mDrawerLayout.closeDrawer(mDrawerList);
} else {
// error in creating fragment
Log.e("MainActivity", "Error in creating fragment");
}
I am using this fragment from navigationDrawer like in Gmail application.
What should I do that my fragment remains even I change the orientation of device?
Thanks in Advance
I don't think the accepted answer is the correct so I'm writing this one:
When replacing the fragment you should use the method replace with three arguments so you can find your fragment later:
fragmentManager.beginTransaction()
.replace(R.id.frame_container, fragment, TAG_FRAGMENT).commit();
Where TAG_FRAGMENT is some string tag.
Then in onCreate if the activity was restarted you can find your fragment and add it to the container:
if(savedInstanceState != null) {
fragment = getFragmentManager().findFragmentByTag(TAG_FRAGMENT);
fragmentManager.beginTransaction()
.replace(R.id.frame_container, fragment, TAG_FRAGMENT).commit();
}
I had exactly the same problem as mentioned above and I fixed it in the AndroidManifest by adding this:
<activity
...
android:configChanges="orientation|screenLayout|screenSize|layoutDirection">
Hope this helps!
Probably should save position using onSaveInstanceState() and test the bundle argument to onCreate().

Categories

Resources