Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where should I call Rest API in fragment

I'm using Bottom-navigation with 3 fragments. On Home-fragment I'm requesting API to fetch data and show in recycler-view my problem is whenever I switch fragments and come again to Home-fragment it's recreating the layout and again its fetch data from API I want to load only one time when app launch

This is where I call API in the fragment

  @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.home_fragment, container, false);
       // return inflater.inflate(R.layout.home_fragment, container, false);
        sharedPrefManager = new SharedPrefManager(getActivity());
        locationTrack = new LocationTrack(getActivity());

        buildGoogleApiClient();
        fusedLocationClient = LocationServices.getFusedLocationProviderClient(getActivity());
        getUserLatLng();
        setUp(view);
        netWorkCall();
        return view;
    }

HomeActivity to load home-fragment by default

if (savedInstanceState == null) {
            Fragment fragment = null;
            fragment = new HomeFragment();

            if (fragment != null) {
                FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
                ft.add(R.id.content_frame, fragment, "home").addToBackStack("Home");
                ft.commit();
            }
        }

bottom-navigation click listener

private void displaySelectedScreen(int itemId) {

     Fragment fragment = null;

    switch (itemId) {

     case R.id.action_home:
                    fragment = new HomeFragment();
                    break;
                case R.id.action_profile:
                    if (sharedPrefManager.getAuthority()) {
                        fragment = new ProfileFragment();
                    } else {
                        SDConstant.switchActivity(this, LoginScreen.class);

                    }
                    break;
                case R.id.action_calculator:
                    if (sharedPrefManager.getAuthority()) {
                        fragment = new CalculatorFragment();
                    } else {
                        SDConstant.switchActivity(this, LoginScreen.class);
                    }
                    break;
            }
            //replacing the fragment
            if (fragment != null) {
                FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
                ft.replace(R.id.content_frame, fragment, "home").addToBackStack("Home");
                ft.commitAllowingStateLoss();
                //ft.commitNow();
            }
    }
    }

Please guide me solution How to solve this re-creation API call

like image 538
MustafaShaikh Avatar asked Oct 16 '22 03:10

MustafaShaikh


1 Answers

First off, perform this calls inside onViewCreated instead of onCreateView:

sharedPrefManager = new SharedPrefManager(getActivity());
locationTrack = new LocationTrack(getActivity());

buildGoogleApiClient();
fusedLocationClient = LocationServices.getFusedLocationProviderClient(getActivity());
getUserLatLng();
setUp(view);
netWorkCall(); //this call has to be removed as explained later

Why? Because onCreateView should just return the fragments UI. OnViewCreated is called directly afterwards and this is the place to do some stuff.

No to get to your problem. The best way for you to solve this would be using a ViewModel from the architecture components in conjunction with LiveData.

You can read more on this topic here.

Your implementation could look like this (adapted the example from the link):

public class MyViewModel extends ViewModel {
    private MutableLiveData<List<User>> users;
    public LiveData<List<User>> getUsers() {
        if (users == null) {
            users = new MutableLiveData<List<User>>();
            loadUsers();
        }
        return users;
    }

    private void loadUsers() {
        // Do an asynchronous operation to fetch users.
    }
}

In your onViewCreated you can do something lik this:

MyViewModel model = new ViewModelProvider(getViewLifecycleOwner()).get(MyViewModel.class);
model.getUsers().observe(getViewLifecycleOwner(), users -> {
    // update UI
});

Don't feel overwhelmed by this. What it does in reality is relatively simple. The ViewModel survives configuration changes. Meaning if you rotate your phone the loadUsers request won't be invoked again - same with switching between bottom navigation tabs. Of course If the fragment is destroyed, the ViewModel does also get destroyed (the function onCleared is invoekd then).

The LiveData users is just a fancy name for a simple observer. Mutable means that you can set a value, getUsers() returns a non mutable LiveData, this means you can only read its value. When you set a value to a LiveData object, it's subscriber will be notified. You can imagine it like the LiveData is an interface implmented by your Fragment which is using the ViewModel. And this interfaces function is invoked once you have fetched data. More info on dealing with LiveData is explained here you should definitely check it out.

So the ViewModel will invoke loadUsers once you start observing getUsers if the Users have not been loaded yet. If they have been loaded, the current value is returned.

Oh and to add LiveData and ViewModel -> it's explained here :)

Hope this was helpful. I know it is alot but trust me it is worth investing the time!

like image 132
Rene Ferrari Avatar answered Oct 27 '22 10:10

Rene Ferrari