I have a HomeFragment and LoginFragment in the same Activity. At first it shows the HomeFragment and then go to LoginFragment. But when I back to HomeFragment it reloads the HomeFragment.
How to make the HomeFragment not reload when I press back from LoginFragment.
Thanks in advance. Here is my code :
MainActivity.java
private void setEvent() {
img_action_back.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
closeKeyboard(getApplication(), img_action_back.getWindowToken());
onBackPressed();
}
});
}
#Override
public void onBackPressed() {
if (fragment instanceof LoginFragment)
{
LoginFragment loginFragment = (LoginFragment)fragment;
if(loginFragment.fromDrawer)
Navigator.showHomeFragment(mContext);
else
finish();
}
}
}
Navigator.java
public static void showHomeFragment(Context context) {
final FragmentTransaction transaction =
getFragmentManager(context).beginTransaction();
transaction.replace(CONTAINER_ID, new HomeFragment());
transaction.commit();
}
public static void showLoginFragment(Context context,Boolean fromDrawer,String infoRegister) {
final FragmentTransaction transaction =
getFragmentManager(context).beginTransaction();
transaction.replace(CONTAINER_ID,
LoginFragment.newInstance(fromDrawer,infoRegister),"login");
transaction.commit();
}
Your issue is that you're recreating a new HomeFragment instance when you press back. You should instead pop the FragmentManager backstack.
#Override
public void onBackPressed() {
if (fragment instanceof LoginFragment) {
LoginFragment loginFragment = (LoginFragment)fragment;
if(loginFragment.fromDrawer) {
getFragmentManager(mContext).popBackStack();
} else {
finish();
}
}
}
You also need to make sure you add the LoginFragment to the backstack.
public static void showLoginFragment(Context context,Boolean fromDrawer,String infoRegister)
{
final FragmentTransaction transaction =
getFragmentManager(context).beginTransaction();
transaction.replace(CONTAINER_ID,
LoginFragment.newInstance(fromDrawer,infoRegister),"login");
transaction.addToBackStack(null);
transaction.commit();
}
#SunnySydeUp has a nice answer. I've found some improvement scope in your code.
You need to add the Fragment in the back stack so that the super.onBackPressed call won't recreate the Fragment again like the other answer says.
But as you're really worried about recreating Fragment you might initialize them once and use the instance again during transaction.
So in the onCreate function of your Activity initialize both of them first like this.
private HomeFragment mHomeFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_layout);
mHomeFragment = new HomeFragment();
}
Now your onBackPressed may look like
#Override
public void onBackPressed() {
if (fragment instanceof LoginFragment) {
if(loginFragment.fromDrawer) {
super.onBackPressed();
} else {
finish();
}
}
}
And the Navigator.java
public static void showHomeFragment(Context context) {
final FragmentTransaction transaction =
getFragmentManager(context).beginTransaction();
transaction.replace(CONTAINER_ID, mHomeFragment);
transaction.commit();
}
public static void showLoginFragment(Context context,Boolean fromDrawer,String infoRegister) {
final FragmentTransaction transaction =
getFragmentManager(context).beginTransaction();
transaction.replace(CONTAINER_ID,
LoginFragment.newInstance(fromDrawer,infoRegister),"login");
transaction.addToBackStack(null).commit();
}
Related
I am invoking a fragment(GetStartFragment) from an activity(DiscoverActivity) and from the same fragment (GetStartFragment), I am replacing it with another fragment (SelectFragment). Now I need to remove the old fragment (GetStartFragment) when I perform onClick() method as below. I was trying to remove, but the fragment ID returns null. How to remove the old fragment from the fragment itself.
DiscoverActivity.java :
public class DiscoverActivity implements AppCompatActivity {
.....
case R.id.start:
showGetStartFragment();
return true;
.....
private void showGetStartFragment() {
lGetStartFragment = GetStartFragment.newInstance();
lGetStartFragment.show(getSupportFragmentManager(), lGetStartFragment.getTag());
}
}
**FragmentDiscover.java :**
public class GetStartFragment extends BaseBottomSheetDialogFragment {
public static GetStartFragment newInstance() {
return new GetStartFragment();
}
.....
#OnClick(R2.id.getstart_button)
void onGetStartButtonClick() {
boolean isStart = true;
/* Show Fragment 2 */
SelectFragment lSelectFragment = SelectFragment.newInstance();
SelectFragment.show(requireActivity().getSupportFragmentManager(), SelectFragment.getTag());
/*Remove previous fragment - Fragment 1*/
FragmentManager fm = requireActivity().getSupportFragmentManager();
Fragment fragment_ID = fm.findFragmentById(com.misc.exam.R.id.design_getstart);
FragmentTransaction fmt = fm.beginTransaction();
if (fragment_ID != null) {
fmt.remove(fragment_ID).commitAllowingStateLoss();
}
}
#Override
public void onDestroy() {
super.onDestroy();
FragmentManager fm = requireActivity().getSupportFragmentManager();
Fragment fragID = fm.findFragmentById(com.misc.exam.R.id.design_getting_started);
FragmentTransaction fmt = fm.beginTransaction();
if (fragID != null) {
fmt.remove(fragID).commitAllowingStateLoss();
}
}
...
}
Have you tried saving the current fragment in a separate field and replacing it?
Fragment currentFragment;
currentFragment = new NewFragment()
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,currentFragment)
each time when I open a fragment, it will be added to the stack.
So, the back button returns to me according to the stack.
I think I have to delete the stack each time I open a fragment.
if so how can I do that?
here is my code
public class MainActivity extends AppCompatActivity {
private FragmentManager fragmentManager;
FragmentTransaction transaction;
LinearLayout firstColumn,secondColumn,thirdColumn;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
fragmentManager = getSupportFragmentManager();
firstColumn = (LinearLayout) findViewById(R.id.first_column);
secondColumn = (LinearLayout) findViewById(R.id.second_column);
firstColumn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.main_container_frame_layout, new FirstFragment());
transaction.commit();
}
});
secondColumn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.main_container_frame_layout, new SecondFragment());
transaction.commit();
}
});
}
}
Thank you in advance.
getSupportFragmentManager().popBackStack() will return back according to the stack. below code will help you.
#Override
public void onBackPressed() {
if(getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack();
}else
super.onBackPressed();
}
I have 3 fragment fragmentA, fragmentB, fragmentC that are added by default on the activity on create to keep it instance after that, I have another fragment fragmentX that to be added on the fragment container with backStack on Button click, the fragmentX is shown on add but when I need to show it again its not working.
public class MainActivity extends ActivityBaseClass {
private Fragment fragmentA;
private Fragment fragmentB;
private Fragment fragmentC;
private Fragment fragmentX;
#BindView(R.id.btn_show_fragmentx)
Button mBtnShowFragmentX;
#BindView(R.id.tab_layout)
TabLayout mTab;
private FragmentTransaction transaction;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
fragmentA = FragmentA.newInstance();
fragmentB = FragmentB.newInstance();
fragmentC = FragmentC.newInstance();
transaction = getSupportFragmentManager().beginTransaction();
transaction.add(R.id.fragment_container, fragmentA, "A");
transaction.add(R.id.fragment_container, fragmentB, "B");
transaction.add(R.id.fragment_container, fragmentC, "C");
transaction.commit();
mTab.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
transaction = getSupportFragmentManager().beginTransaction();
switch (tab.getPosition()) {
case 0:
transaction.show(fragmentA);
transaction.hide(fragmentB);
transaction.hide(fragmentC);
break;
case 1:
transaction.show(fragmentB);
transaction.hide(fragmentA);
transaction.hide(fragmentC);
break;
case 2:
transaction.show(fragmentC);
transaction.hide(fragmentA);
transaction.hide(fragmentB);
break;
}
transaction.commit();
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
}
#OnClick(R.id.btn_show_fragmentx)
public void showFragmentX() {
if (fragmentX == null) {
fragmentX = FragmentX.newInstance();
transaction = getSupportFragmentManager().beginTransaction();
transaction.add(R.id.fragment_container, fragmentX, "X");
transaction.addToBackStack("X");
transaction.commit();
} else {
transaction = getSupportFragmentManager().beginTransaction();
transaction.show(fragmentX);
transaction.addToBackStack("X");
transaction.commit();
}
}
#Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragment_container);
transaction = getSupportFragmentManager().beginTransaction();
transaction.hide(fragment);
transaction.commit();
getSupportFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
}
You fragmentX is destroyed when onBackPressed is called. You need to check for the backstack's current fragment, if it is an instance of FragmentX, then hide it (and don't pop the backstack), otherwise do your code.
I am trying to retain the state of Fragment. I have MotherActivity in which I have FragmentOne,FragmentTwo,FragmentThree and inside from FragmentTwo I am calling another activity ChildActivity. Problem is that When I am pressing back button in ChildActivity it is refreshing MotherActivity and not keeping the state of my FragmentTwo instead it is showing me FragmentOne which come first time.
I only want when I am pressing BackButton from ChildActivity, on container FragmentTwo should be there:
MainAcitivity:
public class MotherActivity extends FragmentActivity {
AHBottomNavigation bottomNavigation;
Fragment selectedFragment = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bottomNavigation = (AHBottomNavigation) findViewById(R.id.navigation);
bottomNavigation.addItem(item1);
bottomNavigation.addItem(item2);
bottomNavigation.addItem(item3);
bottomNavigation.setOnTabSelectedListener(new AHBottomNavigation.OnTabSelectedListener() {
#Override
public boolean onTabSelected(int position, boolean wasSelected) {
if (position == 0) {
selectedFragment = FragmentOne.newInstance(bottomNavigation);
} else if (position == 1) {
selectedFragment = FragmentTwo.newInstance(bottomNavigation);
} else if (position == 2) {
selectedFragment = FragmentThree.newInstance(bottomNavigation);
}
android.app.FragmentManager fragmentManager = getFragmentManager();
android.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.frame_layout,selectedFragment);
fragmentTransaction.commit();
return true;
}
});
}
#Override
protected void onStart() {
super.onStart();
android.app.FragmentManager fragmentManager = getFragmentManager();
android.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.frame_layout, FragmentOne.newInstance(bottomNavigation));
fragmentTransaction.commit();
}
public void setNotification(){
bottomNavigation.setNotification("1", 1);
}
#Override
protected void onSaveInstanceState(Bundle outState) {
//No call for super().
}
#Override
public void onBackPressed() {
Intent intent = new Intent();
setResult(113, intent);
finish();
return;
}
}
FragmentTwo from where I am calling childActivity:
public class FragmentTwo extends Fragment {
public static AHBottomNavigation bottomNavigation1;
Card_detail_Adapter_Footer searchabledapter;
public static boolean showAddress = false;
Fragment selectedFragment;
public static FragmentTwo newInstance(AHBottomNavigation bottomNavigation) {
FragmentTwo fragment = new FragmentTwo();
bottomNavigation1 = bottomNavigation;
showNotificationCounter(3);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_cart, container, false);
if(showAddress == true){
showAddress = false;
// From here I am calling ChildActivity
Intent intent = new Intent(getActivity(), ChildActivity.class);
startActivity(intent);
}
return view;
}
}
In ChildActivity simply calling onBackPressed()
The problem is with the onStart() method of your MotherActivity.java because when you open another activity from FragmentTwo, your MotherActivity onStop() gets called. When you press back button from ChildActivity onStart() of MotherActivity called which is replacing FragmentTwo from FragmentOne by committing transaction.
Please have a look at https://developer.android.com/guide/components/activities/activity-lifecycle.html
Put code from onStart() method into onCreate() method and check if configuration been changed:
if (savedInstanceState == null) {
android.app.FragmentManager fragmentManager = getFragmentManager();
android.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.frame_layout, FragmentOne.newInstance(bottomNavigation));
fragmentTransaction.commit();
}
I am using tabs to switch between different lists in my app. When a user touches an item in a list, the following is the code to show and hide the detail. I am wondering how to add a back-button that goes back to the correct list it came from. I am replacing fragments so I don't know if the standard back button works in my case?
public class MainActivity extends AppCompatActivity implements
NavigationView.OnNavigationItemSelectedListener,
TabLayout.OnTabSelectedListener,
CustomerFragment.CustomerListListener,
CustomerDetailListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
actionBar.setHomeButtonEnabled(true);
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setDisplayShowHomeEnabled(true);
}
public void onShowCustomerDetail(Customer customer){
HostFragment hostFragment = (HostFragment) customPagerAdapter.getItem(viewPager.getCurrentItem());
CustomerDetailFragment fragment = CustomerDetailFragment.newInstance(customer);
hostFragment.replaceFragment(fragment, true);
}
public void onCloseCustomerDetail() {
HostFragment hostFragment = (HostFragment) customPagerAdapter.getItem(viewPager.getCurrentItem());
CustomerFragment fragment = new CustomerFragment();
hostFragment.replaceFragment(fragment, true);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// just for testing. will do switch case here
onBackPressed();
}
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() > 0) {
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
}
CustomPagerAdapter:
public class CustomPagerAdapter extends FragmentStatePagerAdapter {
private final List<String> tabTitles = new ArrayList<String>() {{
add("Messages");
add("Customers");
add("Jobs");
add("Maps");
}};
private List<Fragment> tabs = new ArrayList<>();
public CustomPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
initializeTabs();
}
private void initializeTabs() {
tabs.add(HostFragment.newInstance(new MessageFragment()));
tabs.add(HostFragment.newInstance(new CustomerFragment()));
tabs.add(HostFragment.newInstance(new JobFragment()));
tabs.add(HostFragment.newInstance(new MapFragment()));
}
#Override
public Fragment getItem(int position) {
return tabs.get(position);
}
#Override
public int getCount() {
return tabs.size();
}
#Override
public CharSequence getPageTitle(int position) {
return tabTitles.get(position);
}
}
HostFragment:
public class HostFragment extends BackStackFragment {
private Fragment fragment;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(R.layout.fragment_host, container, false);
if (fragment != null) {
replaceFragment(fragment, false);
}
return view;
}
public void replaceFragment(Fragment fragment, boolean addToBackstack) {
if (addToBackstack) {
getChildFragmentManager().beginTransaction().replace(R.id.hosted_fragment, fragment).addToBackStack(null).commit();
} else {
getChildFragmentManager().beginTransaction().replace(R.id.hosted_fragment, fragment).commit();
}
}
public static HostFragment newInstance(Fragment fragment) {
HostFragment hostFragment = new HostFragment();
hostFragment.fragment = fragment;
return hostFragment;
}
}
Because of the way I set up my fragments inside tabs using Child Fragment Manager, I had to do this in my onBackPressed to make it work:
#Override
public void onBackPressed() {
HostFragment hostFragment = (HostFragment) customPagerAdapter.getItem(viewPager.getCurrentItem());
FragmentManager fm = hostFragment.getChildFragmentManager();
if (fm.getBackStackEntryCount() > 0) {
fm.popBackStack();
} else {
super.onBackPressed();
}
}
First of all you need to add fragments in backstack while using it
see below code for creating a fragment and adding inside it to backstack
public final static String TAG_FRAGMENT = "HostFragment"; // used inside every fragment
final HostFragment fragment = new HostFragment();
final FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment, fragment, TAG_FRAGMENT);
transaction.addToBackStack(TAG_FRAGMENT);
transaction.commit();
After that inside activity onBackPressed() you need to pop fragment every backpressed that you want.
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() > 0) {
getFragmentManager().popBackStack(); // pop fragment here
} else {
super.onBackPressed(); // after nothing is there default behavior of android works.
}
}
All you need to do is add the fragment to the back stack when you create your fragment. It would look something like this:
CustomerDetailFragment fragment=CustomerDetailFragment.newInstance(customer);
getFragmentManager().beginTransaction()
.addToBackStack("Fragment Tag")
.replace(R.id.yourContainer, fragment, "Fragment Tag")
.commit();
Once you have this, you can just use the home back button to pop the fragments off the stack. If you want to use a custom button to go back, you would have to implement your own popping of the stack, which would call getFragmentManager().popBackStack();
Write a fuction onBackpress()
#Override
public void onBackPressed() {
new AlertDialog.Builder(this)
.setTitle("Exit?")
.setMessage("Do you really want to exit?")
.setNegativeButton("No")
.setPositiveButton("Yes", new OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
YourActivityname.super.onBackPressed();
}
}).create().show();
}