i have menu with two fragments. when i choose second fragment, i can move to third fragment with button.
MainActivity
drawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, toolbar, R.string.drawer_open, R.string.drawer_close);
mDrawerLayout.setDrawerListener(drawerToggle);
drawerToggle.syncState();
getSupportActionBar().setTitle("demo");
mSelectedId = savedInstanceState == null ? R.id.aboutConference : savedInstanceState.getInt("SELECTED_ID");
itemSelection(mSelectedId);
}
private void setToolbar() {
toolbar = (Toolbar) findViewById(R.id.toolbar);
if (toolbar != null) {
setSupportActionBar(toolbar);
}
}
private void initView() {
mDrawer = (NavigationView) findViewById(R.id.main_drawer);
mDrawer.setNavigationItemSelectedListener(this);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
}
private void itemSelection(int mSelectedId) {
switch (mSelectedId) {
case R.id.aboutConference:
mDrawerLayout.closeDrawer(GravityCompat.START);
fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.main_container, new FirstFragment());
fragmentTransaction.commit();
break;
case R.id.aboutDeveloper:
mDrawerLayout.closeDrawer(GravityCompat.START);
fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.main_container, new SecondFragment());
fragmentTransaction.commit();
break;
}
}
Second fragment
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view =
inflater.inflate(R.layout.second_fragment, container, false);
Button button = (Button)view.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FragmentTransaction fragmentTransaction = getActivity().getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.main_container, new ThirdFragment());
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
});
return view;
}
When i press backbutton, it's working correctly.
second fragment
But if i move to third fragment, choose first fragment in menu and press backbutton, third fragment overlaps first fragment
problem
How i can resolve this problem?
UPDATE: i don't want that i can return from first fragment to third when i press back button.
As Shaishav and vishal told you need to put colorto your parent view of the fragment.
orelse you need to Override the onBackButton pressed method and make sure the remove the previous item from stack.
To check if item is there in the stack or not try the following code
fragmentManager1.getBackStackEntryCount()
Related
I am using navigation drawer with fragments and in my Home page i am navigating like this==> maincategory===>subcategory===>subcategoryDetail
while moving from maincategory to subcategory it perfectly replaces the hamburger icon and shows back arrow icon and onback press is working perfectly
but while moving from subcategory to subcategoryDetail when i press the back arrow of subcategoryDetail onback press is working perfectly
but it replaces the back arrow of subcategory.java page with hamburger icon and i cannot go back to home page
MainActivity.java
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
Toolbar toolbar;
DrawerLayout drawer;
ActionBarDrawerToggle toggle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
displaySelectedScreen(R.id.nav_home);
}
public ActionBarDrawerToggle getToggle() {
return toggle;
}
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
int fragments = getSupportFragmentManager().getBackStackEntryCount();
if (fragments == 1) {
finish();
} else if (getFragmentManager().getBackStackEntryCount() > 1) {
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
toggle.setDrawerIndicatorEnabled(true);
}
}
}
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
displaySelectedScreen(item.getItemId());
return true;
}
private void displaySelectedScreen(int itemId) {
Bundle bundle = new Bundle();
//creating fragment object
Fragment fragment = null;
//initializing the fragment object which is selected
switch (itemId) {
case R.id.nav_home:
fragment = new HomeFragment();
break;
case R.id.nav_mens_clothing:
bundle.putString("MAINCATEGORYID", String.valueOf(1));
bundle.putString("MAINCATEGORYNAME","Carpentry");
fragment = new SubCategoryFragment();
fragment.setArguments(bundle);
break;
case R.id.nav_womens_clothing:
bundle.putString("MAINCATEGORYID", String.valueOf(2));
bundle.putString("MAINCATEGORYNAME","Electrical");
fragment = new SubCategoryFragment();
fragment.setArguments(bundle);
break;
case R.id.nav_boys_clothing:
fragment = new SubCategoryFragment();
break;
}
//replacing the fragment
if (fragment != null) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.addToBackStack(null);
ft.commit();
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
}
}
SubCategoryFragment.java
public class SubCategoryFragment extends Fragment {
protected Toolbar toolbar;
protected ActionBarDrawerToggle toggle;
View view;
public SubCategoryFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (view == null) {
view = inflater.inflate(R.layout.fragment_sub_category, container, false);
toolbar = ((MainActivity) getActivity()).findViewById(R.id.toolbar);
toggle = ((MainActivity) getActivity()).getToggle();
shimmerContainer = view.findViewById(R.id.shimmer_view_container);
recyclerView_subcategory = view.findViewById(R.id.recycler_view_category);
toggle.setDrawerIndicatorEnabled(false);
toggle.setHomeAsUpIndicator(R.drawable.back);
toggle.setToolbarNavigationClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getActivity().onBackPressed();
}
});
}
return view;
}
#Override
public void onPause() {
super.onPause();
toolbar.setTitle("Cooper");
toggle.setDrawerIndicatorEnabled(true);
}
SubCategoryDetailFragment.java
public class SubCategoryDetailFragment extends Fragment {
protected Toolbar toolbar;
protected ActionBarDrawerToggle toggle;
View view;
public SubCategoryDetailFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (view == null) {
view = inflater.inflate(R.layout.fragment_sub_category_detail, container, false);
toolbar = ((MainActivity) getActivity()).findViewById(R.id.toolbar);
toggle = ((MainActivity) getActivity()).getToggle();
toggle.setDrawerIndicatorEnabled(false);
toggle.setHomeAsUpIndicator(R.drawable.back);
toggle.setToolbarNavigationClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getActivity().onBackPressed();
}
});
}
return view;
}
#Override
public void onPause() {
super.onPause();
toolbar.setTitle("zzz");
toggle.setDrawerIndicatorEnabled(true);
}}
}
Design two different toolbars in XML and set their visibility according to fragment and activity. When Activity load set Toolbar with Navigation drawer, but when fragment load in that activity hide the current toolbar and replace with another toolbar XML with the back icon.
Do not forget to add toolbar code in onResume() method of the fragment.
Please add these two lines in onresume it will work.
toggle.setDrawerIndicatorEnabled(false);
toggle.setHomeAsUpIndicator(R.drawable.back);
I'm trying for last two days to add fragment next to my drawer activity to get navigation drawer visible across the whole application. I have tried several ways from stackoverflow and many others but still no success. and after that i have to move to 2nd fragment from 1st fragment and so on till the need for navigation drawer.
I want to replace entire view except drawer when i move from from my activity to any fragment. Each fragment have its own layout.xml like an activity(Linear/Relative layouts as parent in them).
Drawer avtivity:
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
Button btnfragOne = (Button) findViewById(R.id.btnfrag_one);
btnfragOne.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FragOne fragment = new FragOne();
getSupportFragmentManager().beginTransaction()
.replace(R.id.frag2, fragment, fragment.getClass().getSimpleName()).addToBackStack(null).commit();
}
});
}
1st Fragment class:
public class FragOne extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.frag_one, container, false);
}
// 2nd Fragment class:
public class FragTwo extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.frag_two, container, false);
}
Simply for this task you have to override onNavigationItemSelected method in your Activity, which return id of selected fragment on NavigationDrawer.
Try this,
#Override
public boolean onNavigationItemSelected(MenuItem item) {
//calling the method displayselectedscreen and passing the id of selected menu
displaySelectedFragment(item.getItemId());
return true;
}
Now displaySelectedFragment,
private void displaySelectedScreen(int itemId) {
//creating fragment object
Fragment fragment = null;
//initializing the fragment object which is selected
switch (itemId) {
case R.id.your_fragment_one_id:
fragment = new FragOne();
break;
case R.id.your_fragment_two_id:
fragment = new FragTwo();
break;
}
//replacing the fragment
if (fragment != null) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.main_layout_id_which_is_to_be_replace, fragment);
ft.commit();
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.your_drawer_layout_id);
drawer.closeDrawer(GravityCompat.START);
}
Edit -- If you want navigate from FragOne to FragTwo. Try this,
Create a method in your Activity,
public void showFragTwo(){
FragmentManager manager = getSupportFragmentManager();
FragTwo frag = new FragTwo();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.your_layout_id_which_is_to_be_replace, frag);
transaction.commit();
}
Then in your FragOne when you want to start FragTwo, call startFragTwo method from Activity as,
((YourActivity) getActivity()).showFragTwo();
In my app I have created a Navigation Drawer with six Fragments. The MainOption Fragment is not included in the Navigation item menu list. Now I want to activate Back button on mobile device to redirect to Main Fragment. For example if I have fragments A,B,C,D,E,F, and now if I click B, then if I press back button, it will back to A. In the same way if I Press back button on Fragment E it will redirect to Fragment A. Now how can I achive this logic in my code. Hence I have tried lots of code from the website, but nothis was working at all. Here is my code snepet for Navigation Drawer
private NavigationView navigationView;
private DrawerLayout drawerLayout;
private Toolbar toolbar ;
private View navigationHeader;
private ImageView imgProfile;
private TextView txtName, txtWebsite;
// flag to load home fragment when user presses back key
private boolean shouldLoadHomeFragOnBackPress = true;
private Handler mHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mHandler = new Handler();
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
navigationView = (NavigationView) findViewById(R.id.nav_view);
// Navigation view header
navigationHeader= navigationView.getHeaderView(0);
txtName = navigationHeader.findViewById(R.id.username);
txtWebsite = navigationHeader.findViewById(R.id.email);
imgProfile = navigationHeader.findViewById(R.id.profile_image);
// load nav menu header data
loadNavHeader();
//Set the Home Fragment initially
OptionMenuFragment fragment = new OptionMenuFragment();
android.support.v4.app.FragmentTransaction fragmentTransaction =
getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment, "OptionMenuFragment");
fragmentTransaction.commit();
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawerLayout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawerLayout.setDrawerListener(toggle);
toggle.syncState();
navigationView.setNavigationItemSelectedListener(this);
}
private void loadNavHeader() {
// name, website
txtName.setText("Hallo");
txtWebsite.setText("mail.com");
imgProfile.setImageResource(R.drawable.profile_image);
//ToDo: Image should be uploaded from web
}
String lastFragmentTag;
boolean showingFirstFragment = true;
public void addNewFragment(Fragment fragment, String fragmentTag) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
if (lastFragmentTag != null) {
Fragment currentFragment = fragmentManager.findFragmentByTag(lastFragmentTag);
transaction.remove(currentFragment);
} else {
Fragment currentFragment = fragmentManager.findFragmentById(R.id.fragment_container);
transaction.hide(currentFragment);
}
transaction.add(R.id.fragment_container, fragment, fragmentTag);
transaction.commit();
lastFragmentTag = fragmentTag;
showingFirstFragment = false;
}
#Override
public void onBackPressed() {
//Here we're gonna remove the last fragment added, and show OptionMenuFragment again
if (!showingFirstFragment)
{
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
Fragment firstFragment = fragmentManager.findFragmentByTag("OptionMenuFragment");
Fragment currentFragment = fragmentManager.findFragmentByTag(lastFragmentTag);
transaction.remove(currentFragment);
transaction.show(firstFragment);
transaction.commit();
showingFirstFragment = true;
} else {
super.onBackPressed();
}
}
#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.blu_home) {
Intent intent = new Intent(this, MainOptionPage.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
return true;
}
return super.onOptionsItemSelected(item);
}
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
String fragmentTag=null;
// Handle navigation view item clicks here.
Fragment fragment = null;
FragmentManager fragmentManager = getSupportFragmentManager();
switch (item.getItemId()) {
case R.id.view_profile:
fragment = new ViewProfileFragment();
fragmentTag = "ViewProfileFragment";
break;
case R.id.todo_list:
fragment =new ToDoListFragment();
fragmentTag="ToDoListFragment";
break;
case R.id.logout:
showAlertDialogLogOut();
break;
case R.id.settings:
fragment = new SettingsFragment();
fragmentTag="SettingFragment";
break;
case R.id.about:
fragment = new AboutFragment();
fragmentTag="AboutFragment";
break;
case R.id.info:
fragment=new InfoFragment();
fragmentTag="InfoFragment";
break;
}
if(fragment!=null){
fragmentManager.beginTransaction().replace(R.id.fragment_container, fragment).commit();
}
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
drawerLayout.closeDrawer(GravityCompat.START);
return true;
}
private void showAlertDialogLogOut() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Logout");
builder.setMessage("Are you sure you want to log out?");
builder.setPositiveButton("YES", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// close the dialog, go to login page
dialog.dismiss();
startActivity(new Intent(MainOptionPage.this, LoginPage.class));
}
});
builder.setNegativeButton("NO", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// Do nothing
dialog.dismiss();
}
});
AlertDialog alert = builder.create();
alert.show();
}
}
For that approach, you will want to use the add(containerViewId, fragment, tag) method instead of replace(containerViewId, fragment), since replace will call remove(Fragment) for ALL fragments previously added to the container, before adding the new fragment. Also, you will want to use addToBackStack(name).
Here's a method I created for a project, and slightly modified for you:
String lastFragmentTag;
boolean showingFirstFragment = true;
public void addNewFragment(Fragment fragment, String fragmentTag) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
if (lastFragmentTag != null) {
Fragment currentFragment = fragmentManager.findFragmentByTag(lastFragmentTag);
transaction.remove(currentFragment);
} else {
Fragment currentFragment = fragmentManager.findFragmentById(R.id.fragment_container);
transaction.hide(currentFragment);
}
transaction.add(R.id.fragment_container, fragment, fragmentTag);
transaction.commit();
lastFragmentTag = fragmentTag;
showingFirstFragment = false;
}
Then you just have to make this change inside onNavigationItemSelected:
Fragment fragment = null;
FragmentManager fragmentManager = getSupportFragmentManager();
String fragmentTag;
switch (item.getItemId()) {
case R.id.view_profile:
fragment = new ViewProfileFragment();
fragmentTag = "ViewProfileFragment";
break;
...
}
if(fragment!=null){
addNewFragment(fragment, fragmentTag);
}
Where "fragmentTag", is going to be a String variable which you change according to the fragment instantiated.
EDIT: Some more changes since the code wasn't working as intended:
#Override
public void onBackPressed() {
//Here we're gonna remove the last fragment added, and show OptionMenuFragment again
if (!showingFirstFragment)
{
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
Fragment firstFragment = fragmentManager.findFragmentByTag("OptionMenuFragment");
Fragment currentFragment = fragmentManager.findFragmentByTag(lastFragmentTag);
transaction.remove(currentFragment);
transaction.show(firstFragment);
transaction.commit();
showingFirstFragment = true;
} else {
super.onBackPressed();
}
}
And when adding OptionMenuFragment, do this instead:
fragmentTransaction.replace(R.id.fragment_container, fragment, "OptionMenuFragment");
Hello I'm trying to override back button to back to home page it gives me this error when press back from BasicInfoFragment then press back again in home fragment (MainFragment)
it gives
java.lang.NullPointerException: Attempt to invoke virtual method 'android.support.v4.app.FragmentManager android.support.v4.app.FragmentActivity.getSupportFragmentManager()' on a null object reference
then the application crushs
java.lang.NullPointerException: Attempt to invoke virtual method 'android.support.v4.app.FragmentManager android.support.v4.app.FragmentActivity.getSupportFragmentManager()' on a null object reference
at com.teqneia.blooddonation.BasicInfoFragment.doBack(BasicInfoFragment.java:245)
at com.teqneia.blooddonation.MainActivity.onBackPressed(MainActivity.java:258)
at android.app.Activity.onKeyUp(Activity.java:2530)
at android.view.KeyEvent.dispatch(KeyEvent.java:2726)
at android.app.Activity.dispatchKeyEvent(Activity.java:2798)
at android.support.v7.app.AppCompatActivity.dispatchKeyEvent(AppCompatActivity.java:543)
at android.support.v7.view.WindowCallbackWrapper.dispatchKeyEvent(WindowCallbackWrapper.java:53)
at android.support.v7.app.AppCompatDelegateImplBase$AppCompatWindowCallbackBase.dispatchKeyEvent(AppCompatDelegateImplBase.java:315)
at android.support.v7.view.WindowCallbackWrapper.dispatchKeyEvent(WindowCallbackWrapper.java:53)
at com.android.internal.policy.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:2368)
at android.view.ViewRootImpl$ViewPostImeInputStage.processKeyEvent(ViewRootImpl.java:4333)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4295)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3836)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3889)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3855)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3981)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3863)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4038)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3836)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3889)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3855)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3863)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3836)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3889)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3855)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4014)
at android.view.ViewRootImpl$ImeInputStage.onFinishedInputEvent(ViewRootImpl.java:4175)
at android.view.inputmethod.InputMethodManager$PendingEvent.run(InputMethodManager.java:2378)
at android.view.inputmethod.InputMethodManager.invokeFinishedInputEventCallback(InputMethodManager.java:1999)
at android.view.inputmethod.InputMethodManager.finishedInputEvent(InputMethodManager.java:1990)
at android.view.inputmethod.InputMethodManager$ImeInputEventSender.onInputEventFinished(InputMethodManager.java:2355)
at android.view.InputEventSender.dispatchInputEventFinished(InputEventSender.java:141)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:330)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5546)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:794)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:684)
BasicInfoFragment java
public class BasicInfoFragment extends Fragment implements MainActivity.OnBackPressedListener, View.OnClickListener {
.
.
public BasicInfoFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_basic_info, container, false);
initialize(view);
// Inflate the layout for this fragment
return view;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
((MainActivity) getActivity()).setOnBackPressedListener(this);
}
void initialize(View view) {
//VIEW OLD DATA AND ADD LISTENERS
name = (EditText) view.findViewById(R.id.name_edit);
email = (EditText) view.findViewById(R.id.email_edit);
mobile = (EditText) view.findViewById(R.id.mobile_edit);
LastDonation = (EditText) view.findViewById(R.id.date_edit);
LastDonation.setInputType(InputType.TYPE_NULL);
LastDonation.requestFocus();
LastDonation.setOnClickListener(this);
//TAKE DATA FROM SERVER
//name.setText("");
//email.setText();
//mob.setText();
//LastDonation.setText();
b = (Button) view.findViewById(R.id.save_edit);
b.setOnClickListener(this);
//get Radio Groups
radioBgGroup = (RadioGroup) view.findViewById(R.id.bg_edit);
radioRhGroup = (RadioGroup) view.findViewById(R.id.rh_edit);
if (mSharedGetter.getBloodType().equals("A")) {
}
#Override
public void doBack() {
Fragment fragment = null;
fragment = new MainFragment();
FragmentManager fm = getActivity().getSupportFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
transaction.replace(R.id.fragment_container, fragment);
transaction.commit();
}
MainActivity
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
.
.
.
.
.
.
protected OnBackPressedListener onBackPressedListener;
public interface OnBackPressedListener {
void doBack();
}
public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
this.onBackPressedListener = onBackPressedListener;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Initially Load MainFFragment xml
setContentView(R.layout.activity_main);
Fragment fragment = new MainFragment();
//Apply fragment
FragmentTransaction fragmentTransaction =
getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment);
fragmentTransaction.commit();
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
View header = navigationView.getHeaderView(0);
TVnav_name = (TextView) header.findViewById(R.id.nav_name);
navigationView.setNavigationItemSelectedListener(this);
TVnav_name.setText(mSharedGetter.getUserName());
}
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else if (onBackPressedListener != null)
onBackPressedListener.doBack();
else
super.onBackPressed();
}
#Override
protected void onDestroy() {
onBackPressedListener = null;
super.onDestroy();
}
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
Fragment fragment = null;
if (id == R.id.nav_edit_info) {
fragment = new BasicInfoFragment();
if (fragment != null) {
//Apply fragment
FragmentTransaction fragmentTransaction =
getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment);
fragmentTransaction.commit();
}
} else if (id == R.id.nav_home) {
fragment = new MainFragment();
if (fragment != null) {
//Apply fragment
FragmentTransaction fragmentTransaction =
getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment, "MY_FRAGMENT");
fragmentTransaction.commit();
}
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
}
MainFragment
public class MainFragment extends Fragment{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_main, container, false);
return view;
}
//DIALOG BUILDER
new AlertDialog.Builder(getActivity())
.setTitle("DONATION REQUEST")
.setView(dialogView)
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
})
.setPositiveButton("Request now", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
//Send the request
Dialog f = (Dialog) dialog;
}
}).show();
}
}
in doBack method getActivity() is returning null. It is also not needed as you can call getFragmentManager() from a Fragment. Here's how to do just that, with fewer lines.
#Override
public void doBack() {
Fragment fragment = new MainFragment();
getFragmentManager().beginTransaction()
.replace(R.id.fragment_container, fragment)
.commit();
}
in your BasicInfoFragment you have
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
((MainActivity) getActivity()).setOnBackPressedListener(this);
}
MainFragment should have the same line, otherwise pressing back twice as you described will invoke BasicInfoFragment doBack() twice.
Since you detach it from its activity after the first back click you get a null value from getActivity() here when the second back arrives:
FragmentManager fm = getActivity().getSupportFragmentManager();
Always call like this.
//In Activity
FragmentManager fm = getSupportFragmentManager();
//In Fragment
FragmentManager fm = getActivity().getFragmentManager();
//For Nested Fragments
FragmentManager fm = getChildFragmentManager();
I think it would be better if you describe what you are trying to solve. I believe you may be having an error in the concept of how fragments work and the management of the back stack.
I believe the problem is your back event is being triggered but this is popping the fragment out but the reference is still there.
Take a look at:
https://aarcoraci.wordpress.com/2017/02/13/android-tutorial-drawer-and-fragment-navigation-made-easyier/
I have two fragments FragmentHome and FragmentAbout, I have added NavigationDrawer to app when I click Home it opens FragmentHome and About opens FragmentAbout, when I open FragmentAbout I am also adding it to backstack. This is working fine.
Now the problem is when I click on About and press back button it goes to the FragmentHome but the NavigationDrawer still shows the About as selected item, I want to change this selected item to Home when I press back button from FragmentAbout
Home Activity:
public class ActivityHome extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {
Toolbar toolbar;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
// Toolbar
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Drawer layout
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.nav_drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.nav_drawer_open, R.string.nav_drawer_close);
assert drawer != null;
drawer.setDrawerListener(toggle);
toggle.syncState();
// Navigation view
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
assert navigationView != null;
navigationView.setNavigationItemSelectedListener(this);
// Open first menu item
navigationView.getMenu().performIdentifierAction(R.id.nav_home, 0);
// Set first item checked
navigationView.setCheckedItem(R.id.nav_home);
}
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
final MenuItem menuItem = item;
// Check if menu item is selected
if (item.isChecked())
item.setChecked(false);
else
item.setChecked(true);
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_home) {
// Open home fragment
getSupportFragmentManager().beginTransaction()
.replace(R.id.frame_layout, new FragmentHome())
.commit();
} else if (id == R.id.nav_about) {
toolbar.setTitle("About");
// Open home fragment
getSupportFragmentManager().beginTransaction()
.replace(R.id.frame_layout, new FragmentAbout())
.addToBackStack(null)
.commit();
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.nav_drawer_layout);
assert drawer != null;
drawer.closeDrawer(GravityCompat.START);
return true;
}
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.nav_drawer_layout);
assert drawer != null;
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}}
FragmentHome
public class FragmentHome extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_home, container, false);
}
#Override
public void onResume() {
super.onResume();
((AppCompatActivity)getActivity()).getSupportActionBar().setTitle(R.string.fragment_home_title);
}
}
FragmentAbout code is same as FragmentHome just layout change.
I have searched a lot on stackoverflow but didn't find any solution yet, so if someone know how to do this please tell me.
There is a OnBackStackChangedListener that you can use for this. Tried it and it works great.
public Fragment getCurrentFragment() {
return this.getSupportFragmentManager().findFragmentById(R.id.fragment_container);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
...
this.getSupportFragmentManager().addOnBackStackChangedListener(
new FragmentManager.OnBackStackChangedListener() {
public void onBackStackChanged() {
Fragment current = getCurrentFragment();
if (current instanceof MyFragmentA) {
navigationView.setCheckedItem(R.id.nav_myfragA);
} else {
navigationView.setCheckedItem(R.id.nav_myfragB);
}
}
});
...
}
This might not be a good solution, but at least it is acceptable for me. You need to store fragment's position inside stack variable (ex: List) whenever a fragment menu is clicked from nav drawer. Then override onBackPressed to remove the last value from stack, and set drawer position to the current last value of stack. Here's the example:
private List<Integer> itemPositionStacks = new ArrayList<>();
protected void onCreate(#Nullable Bundle savedInstanceState) {
itemPositionStacks.add(currentSelectedPosition);
}
public void onNavigationViewItemSelected(int itemId) {
Fragment fr = null;
switch (itemId) {
case 0:
fr = new aFragment();
break;
case 1:
fr = new bFragment();
break;
}
getSupportFragmentManager().beginTransaction()
.replace(R.id.container, fr)
.addToBackStack(null)
.commit();
Drawer.getInstance().setDrawerChecked(itemId);
itemPositionStacks.add(itemId);
}
public void onBackPressed() {
if(itemPositionStacks.size() > 1) {
itemPositionStacks.remove(itemPositionStacks.size() - 1);
Drawer.getInstance().setDrawerChecked(itemIdStacks.get(itemIdStacks.size() - 1));
}
super.onBackPressed();
}
In your onBackPressed() function ..
you must choose which item to be selected by using
drawer.setCheckedItem(R.id.nav_home);
and remove the selection of the another item
drawer.getMenu().findItem(R.id.nav_about).setChecked(false);