I want to call web service before my Fragment1 initialize. But In MainActivity first my Fragment1 Replacing then my webservice call occurs. Now how to handle that ? I am using Retrofit for web service calling.
I can not call Webservice in Fragment 1. Because i dont want to repeat during fragment initialization.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_main);
bottomNavigationView = (BottomNavigationView findViewById(R.id.navigation);
//Here My webservice call which response value sent to Fragment 1
bottomNavigationView.setOnNavigationItemSelectedListener
(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
getSupportActionBar().setHomeButtonEnabled(false);
}
android.app.Fragment selectedFragment = null;
switch (item.getItemId()) {
case R.id.action_item1:
selectedFragment = Fragment1.newInstance();
toolbar.setTitle("1");
break;
case R.id.action_item2:
selectedFragment = Fragment2.newInstance();
toolbar.setTitle("2");
break;
default:
selectedFragment = Fragment1.newInstance();
toolbar.setTitle("1");
break;
}
android.app.FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.frame_layout, selectedFragment);
transaction.commit();
return true;
}
});
android.app.FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.frame_layout, Fragment1.newInstance());
transaction.commit();
}
}
Related
I have 3 fragments, Home, Menu and orders they can be loaded by bottomnavigtioview items and the title shown by it as well
once navigate from Home to Orders then if you want to go back to Home From Orders the title still "Orders"
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment fragment;
switch (item.getItemId()) {
case R.id.navigation_home:
toolbar.setTitle(getResources().getString(R.string.title_home));
fragment = new HomeFragment();
loadFragment(fragment);
return true;
case R.id.navigation_menu:
toolbar.setTitle(getResources().getString(R.string.fragment_title_menu));
fragment = new ProductFragment();
loadFragment(fragment);
return true;
case R.id.navigation_orders:
toolbar.setTitle(getResources().getString(R.string.title_orders));
fragment = new OrdersFragment();
loadFragment(fragment);
return true;
}
return false;
}
};
private void loadFragment(Fragment fragment) {
// load fragment
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_container, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
navigation = findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
// attaching bottom sheet behaviour - hide / show on scroll
CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) navigation.getLayoutParams();
layoutParams.setBehavior(new BottomNavigationBehavior());
toolbar.setTitle(getResources().getString(R.string.title_home));
Fragment f = HomeFragment.newInstance();
getSupportFragmentManager().beginTransaction()
.replace(R.id.frame_container, f)
.commit();
}`
I have Also Tried this but its not working
`
fragmentmanger.addOnBackStackChangedListener -> public void onBackStackChanged() {
}`
Instead of calling toolbar.setTitle in your onNavigationItemSelected method, move it to onCreateView of each fragment. When you navigate back to a Fragment, onCreateView is executed again.
It worked for me when calling it in onResume like this in each fragment:
if(getActivity()!=null) {
((MainActivity)getActivity()).setActionBarTitle
(context.getResources().getString(R.string.YOUR_TITLE));
this is the function setActionBarTitle in MainActivity
public void setActionBarTitle(String title) {
toolbar.setTitle(title);
}
I have the following bottom navbar code to switch between 3 fragments:
public class MainActivity extends AppCompatActivity {
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment fragment = null;
switch (item.getItemId()) {
case R.id.navigation_home:
fragment = new HomeFragment();
break;
case R.id.navigation_dashboard:
fragment = new DashboardFragment();
break;
case R.id.navigation_notifications:
fragment = new NotificationsFragment();
break;
}
return loadFragment(fragment);
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loadFragment(new HomeFragment());
BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
}
private boolean loadFragment(Fragment fragment) {
//switching fragment
if (fragment != null) {
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragment_container, fragment)
.commit();
return true;
}
return false;
}
}
In the fragments there are RecyclerViews with lists. Every time I switch between the tabs (between fragments), it looks like the fragment is reloaded, and the lists jump to the top. I want to prevent that reloading so that the user stays on the same place in the list he viewed before switching fragments
The problem is that you are creating a new instance every time. You can cache the instance like:
private Fragment mHomeFragment = new HomeFragment();
private Fragment mDashboardFragment = new DashboardFragment();
private Fragment mNotificationsFragment = new NotificationsFragment();
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment fragment = null;
switch (item.getItemId()) {
case R.id.navigation_home:
fragment = mHomeFragment;
break;
case R.id.navigation_dashboard:
fragment = mDashboardFragment;
break;
case R.id.navigation_notifications:
fragment = mNotificationsFragment;
break;
}
return loadFragment(fragment);
}
As we could see, you are always replace your fragment when clicks on bottom navigation, replace means previous fragment removes and state cleans. The solution is do not create your fragment each time and use attach/detach method for showing actual fragment. Here is already described about these methods.
Problem:
Each time the BottomNavigationView is clicked the fragment is re-created.
Currently in each fragment I have Recycler View that runs only once when creating the Fragment.
In this case, the RecyclerView data is loaded every time. And that's not what I'd like.
How could I work so that the Fragment remains active after it is clicked the first time. And when you go back to the Fragment already created, just display it without recreating it every time?
My attempts:
BottomNavigationView bottomNavigationView =(BottomNavigationView) findViewById(R.id.bottomNavView_Bar);
BottomNavigationViewHelper.disableShiftMode(bottomNavigationView);
final Menu menu = bottomNavigationView.getMenu();
fragmentManager = getSupportFragmentManager();
final FragmentTransaction transaction = fragmentManager.beginTransaction();
/* Fragmento Start */
transaction.replace(R.id.content_home, new MainFragment()).commit();
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Intent in;
Fragment fragment = null;
Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.content_home);
switch (item.getItemId()){
case R.id.ic_home:
if (!(currentFragment instanceof MainFragment)) {
fragment = new MainFragment();
toolbar.setTitle("Main");
item = menu.getItem(0);
item.setChecked(true);
}
break;
case R.id.ic_categorias:
if (!(currentFragment instanceof CategoriasFragment)) {
fragment = new CategoriasFragment();
toolbar.setTitle("Categorias");
item = menu.getItem(1);
item.setChecked(true);
}
break;
case R.id.ic_calendar:
if (!(currentFragment instanceof FeedUserFragment)) {
fragment = new FeedUserFragment();
item = menu.getItem(2);
toolbar.setTitle("Feed");
item.setChecked(true);
}
break;
case R.id.ic_explore:
if (!(currentFragment instanceof ExploreFragment)) {
fragment = new ExploreFragment();
item = menu.getItem(3);
toolbar.setTitle("Explorar");
item.setChecked(true);
}
break;
case R.id.ic_person:
if (!(currentFragment instanceof Opcoes)) {
fragment = new Opcoes();
toolbar.setTitle("Opções");
item = menu.getItem(4);
item.setChecked(true);
}
break;
}
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.content_home, fragment);
transaction.commit();
return false;
}
});
You are replacing your fragment every time ie after your switch block
complete.
Solution: Replace only when condition meets and use addToBackStack which helps to maintain stacks. You can read more about from this site
Try this,
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Intent in;
Fragment fragment = null;
Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.content_home);
switch (item.getItemId()){
case R.id.ic_home:
if (!(currentFragment instanceof MainFragment)) {
fragment = new MainFragment();
toolbar.setTitle("Main");
item = menu.getItem(0);
item.setChecked(true);
loadFragment(fragment,"mainMenu");
}
break;
case R.id.ic_categorias:
if (!(currentFragment instanceof CategoriasFragment)) {
fragment = new CategoriasFragment();
toolbar.setTitle("Categorias");
item = menu.getItem(1);
item.setChecked(true);
loadFragment(fragment,"categories");
}
break;
case R.id.ic_calendar:
if (!(currentFragment instanceof FeedUserFragment)) {
fragment = new FeedUserFragment();
item = menu.getItem(2);
toolbar.setTitle("Feed");
item.setChecked(true);
loadFragment(fragment,"feedUsers");
}
break;
case R.id.ic_explore:
if (!(currentFragment instanceof ExploreFragment)) {
fragment = new ExploreFragment();
item = menu.getItem(3);
toolbar.setTitle("Explorar");
item.setChecked(true);
loadFragment(fragment,"explore");
}
break;
case R.id.ic_person:
if (!(currentFragment instanceof Opcoes)) {
fragment = new Opcoes();
toolbar.setTitle("Opções");
item = menu.getItem(4);
item.setChecked(true);
loadFragment(fragment,"opcoes");
}
break;
}
return false;
}
});
/**
* Create new method which replace your old fragment
*/
public void loadFragment(Fragment fragment, String tag){
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.content_home, fragment);
transaction.addToBackStack(tag);
transaction.commit();
}
I would try transaction.add() and search for fragments in back stack with this method findFragmentByTag. https://developer.android.com/reference/android/support/v4/app/FragmentManager.html#findFragmentByTag(java.lang.String).
How can I limit a tap on a BottomNavigatioView item to just once, so that my mapfragment doesn't have to reload itself when someone spamms the item?
My current Solution is this one:
fragmentManager = getSupportFragmentManager();
bottomNavigation.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment fragment = null;
Fragment currentFragment = fragmentManager.findFragmentById(R.id.main_container);
int id = item.getItemId();
switch (id){
case R.id.World:
if (!(currentFragment instanceof MapsFragment)) {
fragment = new MapsFragment();
}
break;
case R.id.Friends:
fragment = new FriendsFragment();
break;
case R.id.Chats:
fragment = new You_Fragment();
break;
}
final FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.main_container, fragment).commit();
return true;
}
});
but it doesn't work since the fragment throws a Nullpointer.
What can i change to achieve the above?
Try this! Worked for me:
fragmentManager = getSupportFragmentManager();
bottomNavigation.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment fragment = null;
Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.main_container);
int id = item.getItemId();
switch (id){
case R.id.World:
if (currentFragment instanceof MapsFragment) {
return false;
} else {
fragment = new MapsFragment();
}
break;
case R.id.Friends:
fragment = new FriendsFragment();
break;
case R.id.Chats:
fragment = new You_Fragment();
break;
}
final FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.main_container, fragment).commit();
return true;
}
});
I have a navigation view with some items in it, and when one item is pressed it will go to that fragment. For example, if you press the "Home" item, on the drawer, it will bring up the home fragment.
navigationView = (NavigationView)findViewById(R.id.navigation_view);
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.home_id:
HomeFragment homeFragment = (HomeFragment) fragmentManager.findFragmentByTag("Home");
if (homeFragment == null)
homeFragment = new HomeFragment();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.Main, homeFragment, "Home");
fragmentTransaction.commit();
getSupportActionBar().setTitle("Home");
item.setChecked(true);
drawerLayout.closeDrawers();
break;
case R.id.chat_id:
ChatFragment chatFragment = (ChatFragment) fragmentManager.findFragmentByTag("Chat");
if (chatFragment == null)
chatFragment = new ChatFragment();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.Main, chatFragment, "Chat");
fragmentTransaction.commit();
getSupportActionBar().setTitle("Chat");
item.setChecked(true);
drawerLayout.closeDrawers();
break;
}
}
}
So what I think is happening is that when I am using the replace() method, it is destroying the chat fragment. What if I have data on the chat fragment, and I want to make sure the data does not go away when I change fragments.
In the ChatFragment class I have put this override method:
#Override
public void onSaveInstanceState(Bundle outState)
{
Log.d("CHATFRAG", "onSaveInstanceState: been called ");
super.onSaveInstanceState(outState);
outState.putString("textView",textView.getText().toString());
//Save the fragment's state here
}
Now when I switch between fragments in my app, this method does not get called, which means the fragment is being destroyed.
Is there an alternative way where I can swap the current fragment that is on screen, with the desired fragment(without destroying both)?
I will be having more fragments (up to ten), is there an optimised solution that will not require duplicate code?
you are replacing fragment with other, so first one will get distroyed. If you dont want it to destroy you need to add it instead of replace
fragmentTransaction.add(R.id.Main, homeFragment, "Home");
You can create your fragments in advance, for instance in your activity's onCreate() method:
private HomeFragment homeFragment;
private ChatFragment chatFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_activity);
homeFragment = new HomeFragment();
chatFragment = new ChatFragment();
}
Then in your navigation code:
#Override
public boolean onNavigationItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.home_id:
if (homeFragment == null)
homeFragment = new HomeFragment();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.Main, homeFragment, "Home");
fragmentTransaction.commit();
getSupportActionBar().setTitle("Home");
item.setChecked(true);
drawerLayout.closeDrawers();
break;
case R.id.chat_id:
if (chatFragment == null)
chatFragment = new ChatFragment();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.Main, chatFragment, "Chat");
fragmentTransaction.commit();
getSupportActionBar().setTitle("Chat");
item.setChecked(true);
drawerLayout.closeDrawers();
break;
}
}
Although I think Ravi Rupareliya's answer is the best choice (using .add), I'll share another way I think might work.
You can add two FrameLayout on top of each other, .add a Fragment into both, and then alternate their visibility.