1

I have 3 bottom navigation tabs in my application :

  • Home
  • MyTour
  • Profile

In MyTour, I am using MyTourFragment which have 3 different tabs :

  • Pending(0)
  • Success(1)
  • Failed(2)

For all three tabs(Pending, Success, Failed) I am using FragmentMyTourJobList and depend on condition I am showing pending or success or failed data in all three tabs.

Problem statement :

When I click on MyTour Navigation Item, Pending Fragment instance is coming null and I am only able to see blank fragment but if i click to success or failed then I can see data. Pending tab data is only visible after coming back from other tabs but not initially.

Here is MyTourFragment code :

public class MyTourFragment {

    public MyTourFragment() {

    }

    public static MyTourFragment newInstance(MyTourFragmentListener myTourFragmentListener) {
        return new MyTourFragment(myTourFragmentListener);
    }

    private MyTourFragment(MyTourFragmentListener myTourFragmentListener) {
        this.mMyTourFragmentListener = myTourFragmentListener;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mViewModel.setNavigator(this);
        setHasOptionsMenu(true);

        //Get the Tab Id.
        Bundle bundle = this.getArguments();
        if (bundle != null) {
            mViewModel.setSelectedDateTimeMillis(bundle.getLong("todaysDateForMyTour", Calendar.getInstance().getTimeInMillis()));
            mSelectedTabId = bundle.getInt(KEY_SELECTED_TAB, 0);
        }

        mMyTourJobsListPagerAdapter = new MyTourJobsListPagerAdapter(this, mViewModel.getTourIdForSelectedDate(), this);

    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        mFragmentMyTourBinding = getViewDataBinding();

        mFragmentMyTourBinding.vpMyTour.setOffscreenPageLimit(2);
        mFragmentMyTourBinding.vpMyTour.setCurrentItem(0);
        mFragmentMyTourBinding.vpMyTour.setAdapter(mMyTourJobsListPagerAdapter);
        mFragmentMyTourBinding.tabLayoutMyTour.setupWithViewPager(mFragmentMyTourBinding.vpMyTour, true);
        mFragmentMyTourBinding.tabLayoutMyTour.addOnTabSelectedListener(this);

        setUpTabs();
    }

    private void setUpTabs() {

        //Select the current Tab.
        mFragmentMyTourBinding.vpMyTour.setCurrentItem(mSelectedTabId);

        //Refresh job list as per the selected date.
        FragmentMyTourJobsList fragmentMyTourJobsList = mMyTourJobsListPagerAdapter.getFragmentAtTab(mSelectedTabId); **// this is null first time**
        if (fragmentMyTourJobsList != null) {
            fragmentMyTourJobsList.refreshJobsList(mViewModel.getTourIdForSelectedDate());
        } 
    }
}    

Here is MyTourJobsListPagerAdapter code :

public class MyTourJobsListPagerAdapter extends FragmentStatePagerAdapter {

    private static final int MY_TOUR_JOBS_LIST_PAGES_COUNT = 3;
    private static final int POSITION_TAB_PENDING = 0;
    private static final int POSITION_TAB_SUCCESS = 1;
    private static final int POSITION_TAB_FAILED = 2;
    private HashMap<Integer, FragmentMyTourJobsList> mTabsFragments = new HashMap<Integer, FragmentMyTourJobsList>();
    private long mTourId;
    private FragmentMyTourJobsList.FragmentMyTourJobsListListener mFragmentMyTourJobsListListener;

    public MyTourJobsListPagerAdapter(Fragment fragment, long tourId, FragmentMyTourJobsList.FragmentMyTourJobsListListener fragmentMyTourJobsListListener) {
        super(fragment.getChildFragmentManager(), BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
        this.mTourId = tourId;
        this.mFragmentMyTourJobsListListener = fragmentMyTourJobsListListener;
    }

    public void setTourId(long tourId) {
        this.mTourId = tourId;
    }

    @Override
    public int getCount() {
        return MY_TOUR_JOBS_LIST_PAGES_COUNT;
    }

    @NonNull
    @Override
    public Object instantiateItem(@NonNull ViewGroup container, int position) {
        Fragment fragment = (Fragment) super.instantiateItem(container, position);
        mTabsFragments.put(position, (FragmentMyTourJobsList) fragment);
        return fragment;
    }


    @Override
    public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
        mTabsFragments.remove(position);
        super.destroyItem(container, position, object);
    }

    @Override
    public Fragment getItem(int position) {
        FragmentMyTourJobsList fragmentMyTourJobsList;
        switch (position) {
            case POSITION_TAB_SUCCESS:
                fragmentMyTourJobsList = getFragmentWithBundle(Constants.JOB_STATUS_SUCCESSFUL);
                break;
            case POSITION_TAB_FAILED:
                fragmentMyTourJobsList = getFragmentWithBundle(Constants.JOB_STATUS_FAILED);
                break;
            case POSITION_TAB_PENDING:
            default:
                fragmentMyTourJobsList = getFragmentWithBundle(Constants.JOB_STATUS_ACCEPTED);
                break;

        }
        return fragmentMyTourJobsList;
    }

    public FragmentMyTourJobsList getFragmentAtTab(int tabPosition) {
        return mTabsFragments.get(tabPosition);
    }

    private FragmentMyTourJobsList getFragmentWithBundle(String jobsStatus) {
        FragmentMyTourJobsList fragmentToLoad = FragmentMyTourJobsList.newInstance();

        Bundle bundle = new Bundle();
        bundle.putString(FragmentMyTourJobsList.KEY_ARG_JOBS_STATUS, jobsStatus);
        bundle.putLong(FragmentMyTourJobsList.KEY_ARG_TOUR_ID, mTourId);
        bundle.putSerializable(FragmentMyTourJobsList.KEY_ARG_FRAGMENT_MY_TOUR_JOBS_LIST_LISTENER, mFragmentMyTourJobsListListener);

        fragmentToLoad.setArguments(bundle);

        return fragmentToLoad;
    }
}

Everything is working but when i will go to Pending tab first time then it's not working. I am missing anything here?

Added FragmentMytourJobList

public class FragmentMyTourJobsList extends BaseFragment<FragmentMyTourJobsListBinding, MyTourJobsListViewModel> implements MyTourJobsListNavigator {

    public static FragmentMyTourJobsList newInstance() {
        return new FragmentMyTourJobsList();
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mViewModel.setNavigator(this);

        Bundle bundle = this.getArguments();
        if (bundle != null) {
            mJobsStatus = bundle.getString(KEY_ARG_JOBS_STATUS);
            mTourId = bundle.getLong(KEY_ARG_TOUR_ID, 0);
        }
    }

    @Override
    public int getBindingVariable() {
        return myTourJobsListViewModel;
    }

    @Override
    public int getLayoutId() {
        return R.layout.fragment_my_tour_jobs_list;
    }

    @Override
    public MyTourJobsListViewModel getViewModel() {
        mViewModel = ViewModelProviders.of(this, new ViewModelProviderFactory(Objects.requireNonNull(getActivity()).getApplication())).get(MyTourJobsListViewModel.class);
        return mViewModel;
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        mFragmentMyTourJobsListBinding = getViewDataBinding();

        // fetch job list  from database
        ArrayList<JobUiModel> jobList = mViewModel.fetchJobs(mTourId, mJobsStatus);
        RecyclerView.LayoutManager rvLayoutManager = new LinearLayoutManager(getActivity());
        mFragmentMyTourJobsListBinding.rvMyTourJobs.setLayoutManager(rvLayoutManager);

        // initialize adapter
        mJobsListAdapter = new MyTourJobsListAdapter(getContext(), jobList, mJobsStatus);
        mFragmentMyTourJobsListBinding.rvMyTourJobs.setAdapter(mJobsListAdapter);
        mJobsListAdapter.setClickInterface(this);

        mFragmentMyTourJobsListBinding.rvMyTourJobs.addItemDecoration(new EndOffsetItemDecoration(CommonUtils.dpToPx(56)));
    }

    void refreshJobsList(long tourId) {

        if (tourId > 0) {
            mTourId = tourId;
            mViewModel.fetchJobs(tourId, mJobsStatus);
            // fetch job list  from database
            ArrayList<JobUiModel> jobList = mViewModel.fetchJobs(mTourId, mJobsStatus);
            mJobsListAdapter.setDataset(jobList);
            mJobsListAdapter.notifyDataSetChanged();


        } else {
            mJobsListAdapter.setDataset(null);
            mJobsListAdapter.notifyDataSetChanged();

        }
    }
}
tynn
  • 38,113
  • 8
  • 108
  • 143
Sandip Armal Patil
  • 6,241
  • 21
  • 93
  • 160
  • @tynn : updated FragmentMyTourJobList – Sandip Armal Patil May 28 '20 at 13:53
  • @tynn : did you find any problem in my code? – Sandip Armal Patil May 29 '20 at 12:23
  • Hi, I checked your code and i believe that mMyTourJobsListPagerAdapter.getFragmentAtTab(mSelectedTabId); in MyTourFragment is called before instantiateItem in MyTourJobsListPagerAdapter is occured, and that is why you get null at first time. If you set Success or Failed tab as first tab, i believe you will get same result. Unfortunately debugging is needed to see when something occurs. Can you please check if this is true? It can help us in solving this problem. – Apollo Jun 03 '20 at 12:38

0 Answers0