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.
Related
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.
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.
I'm currently creating functionality to change Fragments using bottom navigation. But instead of destroying them and recreating them, I want to simply hide and show the fragments to preserve the member variables.
I've tried replace(), hide() and show() but haven't managed the get it right, I'm getting animation errors which I'm not able to track down.
I also can't find an example of switching fragments within an AppCompatActivity.
public class MainActivity extends AppCompatActivity {
PassengerFragment passengerFragment;
DriverFragment driverFragment;
#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 PassengerFragment()).commit();
}
// this handles the bottom navigation so when you click an item it changes fragment
private BottomNavigationView.OnNavigationItemSelectedListener navListener =
new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem menuItem) {
Fragment selectedFragment = null;
switch (menuItem.getItemId()) {
case R.id.nav_passenger:
selectedFragment = passengerFragment;
break;
case R.id.nav_driver:
if (driverFragment==null) {
selectedFragment = new DriverFragment();
}
else {
selectedFragment = driverFragment;
}
break;
}
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
selectedFragment).commit(); <---- line 54
return true;
}
};
}
ERROR
Java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Class java.lang.Object.getClass()' on a null object reference
at android.support.v4.app.BackStackRecord.doAddOp(BackStackRecord.java:396)
at android.support.v4.app.BackStackRecord.replace(BackStackRecord.java:444)
at android.support.v4.app.BackStackRecord.replace(BackStackRecord.java:434)
at je.digital.kevin_pickmeup.MainActivity$1.onNavigationItemSelected(MainActivity.java:54)
That is because you are trying do replace with Fragment which are null. You have created passengerFragment and driverFragment as fields or global variables and than you are trying to use them but in some cases especially passengerFragment is null. If you are trying to keep the data in Fragments even they are replaced you can use addToBackStack but you will need to manage not to putting too much to back stack probably by checking getSupportFragmentManager().getBackStackEntryCount() and removing if there are more than 1 using popBackStack() or save the data in Bundle on onDestroyView and restore that data in onCreateView:
just needed better if statements to handle all the cases.
private BottomNavigationView.OnNavigationItemSelectedListener navListener =
new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem menuItem) {
Fragment passengerFragment = getSupportFragmentManager().findFragmentByTag("A");
Fragment driverFragment = getSupportFragmentManager().findFragmentByTag("B");
switch (menuItem.getItemId()) {
case R.id.nav_passenger:
if(passengerFragment.isHidden()) {
getSupportFragmentManager().beginTransaction().show(passengerFragment).commit();
getSupportFragmentManager().beginTransaction().hide(driverFragment).commit();
}
break;
case R.id.nav_driver:
if(driverFragment==null) {
getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, new DriverFragment(),"B").commit();
getSupportFragmentManager().beginTransaction().hide(passengerFragment).commit();
}
else {
if(driverFragment.isHidden()) {
getSupportFragmentManager().beginTransaction().show(driverFragment).commit();
getSupportFragmentManager().beginTransaction().hide(passengerFragment).commit();
}
}
break;
}
return true;
}
};
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;
I have Base Activity including NavigationView with 2 menu items. On start it loads Home fragment having background image inside it. Each loads specific fragment. When I select Terms & Conditions menu item, it loads T&C fragment & when I press back button it simply kills it.
However, when I select About Us menu item, it loads About Us fragment but I need to press BACK button twice to kill it. I need to know why does it happen?
Part of Code in AppBaseActivity
#Override
protected void onCreate(Bundle savedInstanceState) {
fragmentManager = getSupportFragmentManager();
fragmentTransaction = fragmentManager.beginTransaction();
HomeFragment homeFragment = new HomeFragment();
fragmentTransaction.add(R.id.body_container, homeFragment, "");
fragmentTransaction.commit();
}
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
navigationView.getMenu().findItem(item.getItemId()).setChecked(true);
switch (item.getItemId()) {
case R.id.nav_terms :
fragmentTransaction = fragmentManager.beginTransaction();
TCFragment tcFragment = new TCFragment();
fragmentTransaction.replace(R.id.body_container, tcFragment, "");
fragmentTransaction.commit();
break;
case R.id.nav_about_us :
fragmentTransaction = fragmentManager.beginTransaction();
AboutUsFragment aboutUsFragment = new AboutUsFragment();
fragmentTransaction.replace(R.id.body_container, aboutUsFragment, "");
fragmentTransaction.commit();
break;
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
All fragments simply have overridden onCreateView() by inflating respected xml only. No code is written in both fragments yet.
You can stop back hardware navigation if you want.
Simply using onBackPressed() without super.onBackPressed()
#Override
public void onBackPressed() {
}
#Override
public void onBackPressed() {
super.onBackPressed();
}