Right now I have a tablayout with a ViewPager adapter below it. I want to pause a fragment when a different tab is selected (not destroy/pop it, just pause it) and resume it when the fragment's tab is selected.
public class PagerFragment extends Fragment {
ViewPagerAdapter pagerAdapter;
ViewPager pager;
TabLayout tabLayout;
int position;
public PagerFragment() {
super();
}
public void setPosition(int position) {
this.position = position;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public void onStop() {
super.onStop();
}
@Override
public void onPause() {
super.onPause();
pagerAdapter.clear();
pagerAdapter.notifyDataSetChanged();
}
@Override
public void onStart() {
super.onStart();
}
@Override
public void onResume() {
super.onResume();
if (!isAdded()) {
pagerAdapter.instantiateItem(pager, position);
}
}
@SuppressLint("InflateParams")
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_pager, null);
pagerAdapter = new ViewPagerAdapter(getChildFragmentManager());
setPosition(position);
pagerAdapter.setDevicesList(devicesList);
pager = root.findViewById(R.id.pager);
pager.setAdapter(pagerAdapter);
tabLayout = root.findViewById(R.id.tab_layout);
for (int i = 0; i < devicesList.size(); i ) {
tabLayout.addTab(tabLayout.newTab().setText(String.valueOf(devicesList.get(i).getName())));
}
TabLayout.Tab tab = tabLayout.getTabAt(position);
if (tab != null) {
tab.select();
pager.setCurrentItem(position);
tabLayout.setupWithViewPager(pager);
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
pager.setCurrentItem(tab.getPosition());
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
int pos = tab.getPosition();
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
}
tabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(pager));
return root;
}
}
public class ViewPagerAdapter extends FragmentPagerAdapter {
ArrayList<ConnectedBluetoothDevice> devicesList;
ArrayList<DataViewFragment> dataViewFragments;
public ViewPagerAdapter(FragmentManager fm) {
super(fm);
}
/**
* Initializes the adaptor with the device list and the list of data fragments.
* @param devicesList List of devices to be displayed in their own data fragment.
*/
public void setDevicesList(ArrayList<ConnectedBluetoothDevice> devicesList) {
this.devicesList = devicesList;
dataViewFragments = new ArrayList<>();
for (int i = 0; i < devicesList.size(); i ) {
dataViewFragments.add(new DataViewFragment(devicesList.get(i)));
}
}
/**
* GetItem
* @param position position of item in the viewPager list to be returned
* @return fragment to view
*/
@NonNull
public Fragment getItem(int position) {
if (dataViewFragments != null && position < dataViewFragments.size()) {
return dataViewFragments.get(position);
} else {
return new DataViewFragment(null);
}
}
@Override
public int getCount() {
return devicesList.size();
}
/**
* Updates the tabs in tabLayout while swiping pages
* @param position of the viewPage
* @return title of the tab
*/
public CharSequence getPageTitle(int position) {
super.getPageTitle(position);
return devicesList.get(position).getName();
}
public void clear() {
dataViewFragments.clear();
}
}
Some notes:
- I'm instructed to fix this bug in ViewPager and FragmentPagerAdapter, so please don't recommend me solutions in ViewPager2 and FragmentStatePagerAdapter :)
- I heard that
setOffscreenPageLimit(0);
isn't the best practice so I want to avoid that situation (especially since I only need to pause the fragment but not destroy it)
CodePudding user response:
This depends on the version of ViewPager
you are using as it was added later.
Your are using a deprecated constructor
So as long as your using a recent version of Viewpager
you should use the non deprecated constructor:-
public FragmentPagerAdapter(
@NonNull FragmentManager fm,
@FragmentPagerAdapter.Behavior int behavior
)
This constructor with the behaviour BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
then only the current Fragment is in the RESUMED state. All other fragments are capped at STARTED
To get to the STARTED
lifecycle state from RESUMED
onPause
is called.
so change
public ViewPagerAdapter(FragmentManager fm) {
super(fm);
}
to
public ViewPagerAdapter(FragmentManager fm) {
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
}
CodePudding user response:
This method is used to for calling functions to run only when the specified tab is selected.
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
// add your tab functions here
} else {
// do nothing
}
}