I want to create a video list using ViewPager. I must know when pager item visible, and invisible.
I use VideoListAdapter extending FragmentStatePagerAdapter for ViewPager.
I use Fragment method setUserVisibleHint to trigger video start or pause.
But there is a problem, the Fragment in the position 0 of ViewPager throw a NullPointerException. And then i print log for releated method of Fragment.
The log i come into VideoListActivity:
07-08 17:06:50.264 E/lemon: startUpdate
07-08 17:06:50.264 E/lemon: instantiateItem 0
07-08 17:06:50.264 E/lemon: getItem 0
07-08 17:06:50.264 E/lemon: setUserVisibleHint 0 isVisibleToUser false
07-08 17:06:50.264 E/lemon: instantiateItem 1
07-08 17:06:50.264 E/lemon: getItem 1
07-08 17:06:50.264 E/lemon: setUserVisibleHint 0 isVisibleToUser false
07-08 17:06:50.264 E/lemon: setPrimaryItem 0
07-08 17:06:50.264 E/lemon: setUserVisibleHint 0 isVisibleToUser true
07-08 17:06:50.264 E/lemon: finishUpdate
07-08 17:06:50.265 E/lemon: onAttach 0
07-08 17:06:50.265 E/lemon: onAttach 1
07-08 17:06:50.265 E/lemon: onCreateView 0
07-08 17:06:50.267 E/lemon: onstart 0
07-08 17:06:50.267 E/lemon: onCreateView 1
07-08 17:06:50.269 E/lemon: onstart 1
07-08 17:06:50.270 E/lemon: startUpdate
07-08 17:06:50.270 E/lemon: setPrimaryItem 0
07-08 17:06:50.270 E/lemon: finishUpdate
07-08 17:06:50.297 E/lemon: startUpdate
07-08 17:06:50.297 E/lemon: setPrimaryItem 0
07-08 17:06:50.297 E/lemon: finishUpdate
07-08 17:06:50.297 E/lemon: startUpdate
07-08 17:06:50.297 E/lemon: setPrimaryItem 0
07-08 17:06:50.297 E/lemon: finishUpdate
07-08 17:06:50.703 E/lemon: startUpdate
07-08 17:06:50.703 E/lemon: setPrimaryItem 0
07-08 17:06:50.703 E/lemon: finishUpdate
07-08 17:06:50.704 E/lemon: startUpdate
07-08 17:06:50.704 E/lemon: setPrimaryItem 0
07-08 17:06:50.704 E/lemon: finishUpdate
The log i scroll to position 1:
07-08 17:09:41.154 E/lemon: startUpdate
07-08 17:09:41.154 E/lemon: setPrimaryItem 0
07-08 17:09:41.154 E/lemon: finishUpdate
07-08 17:09:41.966 E/lemon: startUpdate
07-08 17:09:41.966 E/lemon: instantiateItem 2
07-08 17:09:41.967 E/lemon: getItem 2
07-08 17:09:41.967 E/lemon: setUserVisibleHint 0 isVisibleToUser false
07-08 17:09:41.967 E/lemon: setPrimaryItem 1
07-08 17:09:41.967 E/lemon: setUserVisibleHint 0 isVisibleToUser false
07-08 17:09:41.967 E/lemon: setUserVisibleHint 1 isVisibleToUser true
07-08 17:09:41.967 E/lemon: finishUpdate
07-08 17:09:41.968 E/lemon: onAttach 2
07-08 17:09:41.968 E/lemon: onCreateView 2
07-08 17:09:41.971 E/lemon: onstart 2
07-08 17:09:41.971 E/lemon: startUpdate
07-08 17:09:41.971 E/lemon: setPrimaryItem 1
07-08 17:09:41.971 E/lemon: finishUpdate
07-08 17:09:41.972 E/lemon: startUpdate
07-08 17:09:41.972 E/lemon: setPrimaryItem 1
07-08 17:09:41.972 E/lemon: finishUpdate
I analyse these logs, I find that fragment in positino 0 invokes setUserVisibleHint(true) first and then invokes onAttach(), but fragment in position 1 invokes onAttach() first and setUserVisibleHint(true) after.
So I write a method onTrigger() in Fragment called in both onAttach() and setUserVisibleHint(true), but fail. I then debug my code, it's show that isAdded() in onTrigger() returns false when invoke onTrigger in onAttach().
So any suggestions here to let me know when to trigger my video start. Thanks a lot.
public class FullScreenVideoFragment extends Fragment {
private FragmentFullScreenVideoBinding binding;
int colorRes;
int position;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Log.e("lemon", "onCreateView " + position);
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_full_screen_video, container, false);
setView();
return binding.getRoot();
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public void setBgAndPosition(int position, int colorRes) {
this.position = position;
this.colorRes = colorRes;
}
@Override
public void onAttach(Context context) {
Log.e("lemon", "onAttach " + position);
super.onAttach(context);
onTriger();
}
@Override
public void onDetach() {
Log.e("lemon", "onDetach " + position);
super.onDetach();
}
@Override
public void onAttachFragment(Fragment childFragment) {
Log.e("lemon", "onAttachFragment " + position);
super.onAttachFragment(childFragment);
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
Log.e("lemon", "setUserVisibleHint " + position + " isVisibleToUser " + isVisibleToUser);
super.setUserVisibleHint(isVisibleToUser);
onTriger();
}
private void setView() {
binding.getRoot().setBackgroundResource(colorRes);
binding.position.setText(String.valueOf(position));
}
private void onTriger() {
if (!isVisible()) return;
binding.position.setText(position + " start");
}
}
public class VideoListAdapter extends FragmentStatePagerAdapter {
private LinkedList<FullScreenVideoFragment> fragmentCaches;
private int[] colors = new int[]{android.graphics.Color.RED, android.graphics.Color.BLUE, android.graphics.Color.GREEN};
public VideoListAdapter(FragmentManager fm) {
super(fm);
fragmentCaches = new LinkedList<>();
}
@Override
public Fragment getItem(int position) {
Log.e("lemon", "getItem " + position);
FullScreenVideoFragment fragment = generateItem();
return fragment;
}
@Override
public int getCount() {
return 10;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
Log.e("lemon", "destroyItem " + position);
super.destroyItem(container, position, object);
}
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
Log.e("lemon", "setPrimaryItem " + position);
super.setPrimaryItem(container, position, object);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
Log.e("lemon", "instantiateItem " + position);
FullScreenVideoFragment fragment = (FullScreenVideoFragment) super.instantiateItem(container, position);
fragment.setBgAndPosition(position, colors[position % 3]);
return fragment;
}
@Override
public void startUpdate(ViewGroup container) {
Log.e("lemon", "startUpdate");
super.startUpdate(container);
}
@Override
public void finishUpdate(ViewGroup container) {
Log.e("lemon", "finishUpdate");
super.finishUpdate(container);
}
@Override
public void restoreState(Parcelable state, ClassLoader loader) {
Log.e("lemon", "restoreState");
super.restoreState(state, loader);
}
@Override
public Parcelable saveState() {
Log.e("lemon", "saveState");
return super.saveState();
}
private FullScreenVideoFragment generateItem() {
FullScreenVideoFragment neededFragment = null;
if (!fragmentCaches.isEmpty()) {
neededFragment = fragmentCaches.get(0);
fragmentCaches.remove(0);
return neededFragment;
}
neededFragment = new FullScreenVideoFragment();
return neededFragment;
}
}
The fragment xml:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data></data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/position"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textColor="@color/account_name_color"/>
</RelativeLayout>
</layout>