How to Stop Fragment from Reloading When Changing Tabs? - android

I have an Activity with a BottomNavigationView, which consists of 4 Fragments, the Fragments reload whenever I change tabs, this is my Activity's code
public class MainHomeActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_home);
BottomNavigationView bottomNavigationView = findViewById(R.id.bottom_navigation);
bottomNavigationView.setOnNavigationItemSelectedListener(navigationItemSelectedListener);
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new HomeFragment()).commit();
}
private BottomNavigationView.OnNavigationItemSelectedListener navigationItemSelectedListener = new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull #NotNull MenuItem item) {
Fragment selectedFragment = null;
switch (item.getItemId()){
case R.id.nav_home:
selectedFragment = new HomeFragment();
break;
case R.id.nav_list:
selectedFragment = new UsersFragment();
break;
case R.id.nav_profile:
selectedFragment = new ProfileFragment();
break;
case R.id.nav_settings:
selectedFragment = new SettingsFragment();
break;
}
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, selectedFragment).commit();
return true;
}
};
}
In the Fragments im loading data from parse
I know that the mistake im doing is that I'm creating a new instance of the Fragment whenever I switch tabs, but I do not how to fix it or where to start from
I saw some people saying that a ViewPagerAdapter should be used in this case but i cant manage to find a place where its explained properly.
Any assistance would be very appreciated!

Here's an article which describes your case perfectly and in detail.
Basically, it creates a fragment for each tab in memory, and saves them as a local variable in the activity:
final Fragment fragment1 = new HomeFragment();
final Fragment fragment2 = new DashboardFragment();
final Fragment fragment3 = new NotificationsFragment();
final FragmentManager fm = getSupportFragmentManager();
Fragment active = fragment1;
You add all 3 fragments to the manager, but hide 2 of them, so only 1 will be visible:
fm.beginTransaction().add(R.id.main_container, fragment3, "3").hide(fragment3).commit();
fm.beginTransaction().add(R.id.main_container, fragment2, "2").hide(fragment2).commit();
fm.beginTransaction().add(R.id.main_container,fragment1, "1").commit();
You implement the OnNavigationItemSelectedListener of the BottomNavigationView, check which item was pressed, and then show that fragment while hiding the previous:
case R.id.navigation_dashboard:
fm.beginTransaction().hide(active).show(fragment2).commit();
active = fragment2;

Instead of replacing the fragment, use add/remove and create a mechanism for adding and removing fragment stack, also it is not recommended but for the sake of question you can create a singleton fragment, instead of using a new Keyword everything tab is changed, along with that you can have a look at pageOffSet
companion object{
private lateinit var INSTANCE?: HomeFragment() = null
}
fun getInstance(): HomeFragment(){
if(INSTANCE == null){
INSTANCE = HomeFragment()
}
return INSTANCE
}

As we know the ViewPager recreates the fragments when we switch the pages with our BottomNavigationView. I know how to prevent this, use one of these 2 Options:
As i can see your amount of fragments is small and fixed, add in your onCreate() of your
MainHomeActivity.java:
mViewPager = (ViewPager)findViewById(R.id.pager);
mViewPager.setOffscreenPageLimit(limit); //limit is a fixed integer
Use a FragmentPagerAdapter as part of your ViewPager. (example provided in link)
UPDATE
In #moalzoabi's case the 2nd option worked. Follow along this post.

Related

BottomNavigationView with setOnItemSelectedListener()

I am trying to build app with BottomNavigationView and I set setOnItemSelectedListener() method to bottom navigation so I can do what I want when user select one of the menu in bottom navigation.
everything is good when I don't set setOnItemSelectedListener(), but when I set setOnItemSelectedListener() method then the fragment is not updated automatically when user select the bottom navigation menu.
I consider if that do i have to handle fragment transaction manually when I set this method?
thanks ^^
Yes. You need to manually replace the fragment item on onNavigationItemSelected
Example:
private BottomNavigationView.OnNavigationItemSelectedListener navListener = new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
// By using switch we can easily get
// the selected fragment
// by using there id.
Fragment selectedFragment = null;
switch (item.getItemId()) {
case R.id.algorithm:
selectedFragment = new AlgorithmFragment();
break;
case R.id.course:
selectedFragment = new CourseFragment();
break;
case R.id.profile:
selectedFragment = new ProfileFragment();
break;
}
// It will help to replace the
// one fragment to other.
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragment_container, selectedFragment)
.commit();
return true;
}
};
You can find a good tutorial here: https://www.geeksforgeeks.org/bottomnavigationview-inandroid/

Android Bottom Navigation Bar in activities

I am developing a car rental app and right now I have 3 fragments in my app (Home - where all the cars are displayed from a recyclerview , Orders - where user's bookings are shown , Profile - user profile). I can switch beetween these 3 fragments from my bottom navigationbar.
Now I created onclick listeners for every car on home page. When I click on a car it sends me to a new activity "activity_car_detail.xml" which contains specific information about the selected car. My question is: how can I make the navigation bar to appear on this Car Detail activity? Should I use fragment instead of activity or what should I do?
This is the code for the Main Activity which contains the bottom navigation bar:
public class MainActivity extends AppCompatActivity {
public static ProgressBar progressBar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BottomNavigationView bottomNav = findViewById(R.id.bottom_navigation);
bottomNav.setOnNavigationItemSelectedListener(navListener);
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new HomeFragment()).commit();
}
private BottomNavigationView.OnNavigationItemSelectedListener navListener = new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment selectedFragment = null;
switch (item.getItemId()) {
case R.id.nav_home:
selectedFragment = new HomeFragment();
break;
case R.id.nav_orders:
selectedFragment = new OrdersFragment();
break;
case R.id.nav_profile:
selectedFragment = new ProfileFragment();
break;
}
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, selectedFragment).commit();
return true;
}
};
}
I suggest using the Navigation component instead of Fragment transactions. Also this will fix your issue and it will remove boilerplate code. Read more about it's documentation here.

recreate conditioned fragments without button

In my Application there are four ButtonNavigationView tabs with fragments, i want 2 of them to refresh every time i click on them and the other 2 to not refresh every time i click on them , how can i get that?
Home Activity
final Fragment factorsFragment = new FactorsFragment();
final Fragment newFactorFragment = new NewFactorFragment();
final Fragment productsFragment = new ProductsFragment();
final Fragment checkList = new CheckList();
final FragmentManager fm = getSupportFragmentManager();
Fragment active = newFactorFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
navigation = (BottomNavigationView) findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
fm.beginTransaction().add(R.id.fragment_container, productsFragment, "4").hide(productsFragment).commit();
fm.beginTransaction().add(R.id.fragment_container, factorsFragment, "3").hide(factorsFragment).commit();
fm.beginTransaction().add(R.id.fragment_container, checkList, "2").hide(checkList).commit();
fm.beginTransaction().add(R.id.fragment_container, newFactorFragment, "1").commit();
SQLiteStudioService.instance().start(this);
}
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_home:
fm.beginTransaction().hide(active).show(factorsFragment).commit();
active = factorsFragment;
return true;
case R.id.navigation_dashboard:
fm.beginTransaction().hide(active).show(newFactorFragment).commit();
active = newFactorFragment;
return true;
case R.id.navigation_notifications:
fm.beginTransaction().hide(active).show(productsFragment).commit();
active = productsFragment;
return true;
case R.id.navigation_checklist:
fm.beginTransaction().hide(active).show(checkList).commit();
active = checkList;
return true;
}
return false;
}
};
i want factorFragment and productFragment to refresh without adding a swiperefreshlayout or custom refresh button
my problem is all of my fragments don't refresh on tab change, because i am just making them show and hide , but i want 2 of them to refresh.
Call all the functions of your factorFragment and productFragment in onResume of the respective fragments. Changes will reflect as you are calling the methods again in onResume.
Fragment has offset. So if you are loading one fragment in activity the next few(depends on what you set or the default offset) fragments also get initialized. That's why it will be wise to recall your functions in onResume.

How to switch between fragments without actually overlapping the previous fragments

I am new to Android Developing and I am trying to create an app based on the BottomNavgiationView. One of the bottom navigation Items have an editText so when I switch to another fragment the previous fragment where I wrote something gets overlapped due to replacing.
This is my OnNavigationItemSelectedListener
private void enableNavigation(){
bottomNav.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch(item.getItemId()){
case R.id.btnHome:
HomeFragment homeFragment = new HomeFragment();
android.support.v4.app.FragmentManager manager = getSupportFragmentManager();
manager.beginTransaction().replace(R.id.container, homeFragment).commit();
return true;
case R.id.btnChats:
ChatsFragment chatsFragment = new ChatsFragment();
android.support.v4.app.FragmentManager manager1 = getSupportFragmentManager();
manager1.beginTransaction().replace(R.id.container, chatsFragment).commit();
return true;
case R.id.btnPost:
PostsFragment postsFragment = new PostsFragment();
android.support.v4.app.FragmentManager manager2 = getSupportFragmentManager();
manager2.beginTransaction().replace(R.id.container, postsFragment).commit();
return true;
case R.id.btnFavourites:;
FavouritesFragment favouritesFragment = new FavouritesFragment();
android.support.v4.app.FragmentManager manager3 = getSupportFragmentManager();
manager3.beginTransaction().replace(R.id.container, favouritesFragment).commit();
return true;
case R.id.btnProfile:
ProfileFragment profileFragment = new ProfileFragment();
android.support.v4.app.FragmentManager manager4 = getSupportFragmentManager();
manager4.beginTransaction().replace(R.id.container, profileFragment).commit();
return true;
}
return false;
}
});
Anyone having any solution please let me Know..
I assume you meant instance. Each time you switch fragment, you make a new instance and open that. So to stop doing that, you have to keep the first instance built and give that to the fragment manager when you want to switch to it.
For example, let's use your ChatFragment.
Instead of inside the switch statement, you put your ChatsFragment chatsfragmentdeclaration to the top of the Activity, so it's an instance-wide variable. Inside your switch statement, instead of building a new instance every time, you go
case R.id.btnChats:
if(chatsFragment == null) chatsFragment = new ChatsFragment();
android.support.v4.app.FragmentManager manager1 = getSupportFragmentManager();
manager1.beginTransaction().replace(R.id.container, chatsFragment).commit();
return true;
Now you only rebuild your fragment once, when it is first called. From then on, the old instance is reused.

How to remove the fragment when click on item again

Good Day,
I am facing some problem with fragments
I am displaying a fragment when user clicks on 'More', as a popup menu
but when I click the 'More' again, it would be like add one more fragment on the previous one
can someone tell me how to remove the fragment when I click on the 'More' again? Thank you!
the java code of bottom navigation menu
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BottomNavigationView bottomNavigationView = (BottomNavigationView)
findViewById(R.id.bottom_navigation);
BottomNavigationViewHelper.disableShiftMode(bottomNavigationView);
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment fragment = null;
String title = "";
switch (item.getItemId()) {
case R.id.menu:
getFragmentManager().beginTransaction().replace(R.id.fragment_container, new MenuFragment()).addToBackStack(null).commit();
title = "MENU";
getSupportActionBar().setTitle(title);
break;
case R.id.promotion:
getFragmentManager().beginTransaction().replace(R.id.fragment_container, new PromotionFragment()).addToBackStack(null).commit();
title = "PROMOTION";
getSupportActionBar().setTitle(title);
break;
case R.id.order:
getFragmentManager().beginTransaction().replace(R.id.fragment_container, new OrderFragment()).addToBackStack(null).commit();
title = "ORDER";
getSupportActionBar().setTitle(title);
break;
case R.id.location:
getFragmentManager().beginTransaction().replace(R.id.fragment_container, new LocationFragment()).addToBackStack(null).commit();
title = "LOCATION";
getSupportActionBar().setTitle(title);
break;
case R.id.more:
getFragmentManager().beginTransaction().add(R.id.fragment_container, new MoreFragment()).addToBackStack(null).commit();
break;
}
return true;
}});
}
}
Do not add your Popup Fragment to the backstack while transitioning to a new one. That is the first step you should do.
Next, rather than reopening the Popup on second "more" click, you should close it. Sounds like a better approach. But this would be probably better achieved by using Dialogs.
before calling transaction for 'more' add a tag with addToBackStack function(ex: moreFragment). check fragment manager and remove fragment like:
Fragment mFragment =getSupportFragmentManager().findFragmentByTag("moreFragment");
if(mFragment != null)
getSupportFragmentManager().beginTransaction().remove(mFragment);
But I think instead of removing old fragment just keep it and dont open new one if not null
To do this you have to keep track of fragment state. Lets assume a variable isFragmentOpen. In onClick you have to flip the variable and take your decision.
private boolean isFragmentOpen;
void onClick(View view) {
if (!isFragmentOpen) {
addFragment();
} else {
removeFragment();
}
// Flip the fragment state.
isFragmentOpen = !isFragmentOpen;
}
Please check how to add or delete fragment from official document Fragments
thanks for helping and now i already solve the problem^^
this is the code what i using
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
MoreFragment f = (MoreFragment) fm.findFragmentByTag("tag");
if(f == null) { // not added
f = new MoreFragment();
ft.add(R.id.fragment_container, f, "tag");
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
} else { // already added
ft.remove(f);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE);
}
ft.commit();
break;

Categories

Resources