android / views-widgets-samples

Multiple samples showing the best practices in views-widgets on Android.
Apache License 2.0
5.03k stars 3.01k forks source link

viewpager2 crash sometimes #103

Open taiji1 opened 4 years ago

taiji1 commented 4 years ago

When I return the activity containing viewpager2,crash sometimes

Device:OPPO R9s Plus Android 6.0.1
Color OS version:V3.0

Log: java.lang.IllegalStateException: Design assumption violated. at androidx.viewpager2.adapter.FragmentStateAdapter.placeFragmentInViewHolder(FragmentStateAdapter.java:287) at androidx.viewpager2.adapter.FragmentStateAdapter.onViewAttachedToWindow(FragmentStateAdapter.java:276) at androidx.viewpager2.adapter.FragmentStateAdapter.onViewAttachedToWindow(FragmentStateAdapter.java:67) at androidx.recyclerview.widget.RecyclerView.dispatchChildAttached(RecyclerView.java:7556) at androidx.recyclerview.widget.RecyclerView$5.addView(RecyclerView.java:860) at androidx.recyclerview.widget.ChildHelper.addView(ChildHelper.java:107) at androidx.recyclerview.widget.RecyclerView$LayoutManager.addViewInt(RecyclerView.java:8601) at androidx.recyclerview.widget.RecyclerView$LayoutManager.addView(RecyclerView.java:8559) at androidx.recyclerview.widget.RecyclerView$LayoutManager.addView(RecyclerView.java:8547) at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1641) at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1587) at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:665) at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:4134) at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:3851) at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4404) at android.view.View.layout(View.java:16673) at android.view.ViewGroup.layout(ViewGroup.java:5476) at androidx.viewpager2.widget.ViewPager2.onLayout(ViewPager2.java:527) at android.view.View.layout(View.java:16673) at android.view.ViewGroup.layout(ViewGroup.java:5476) at androidx.constraintlayout.widget.ConstraintLayout.onLayout(ConstraintLayout.java:1915) at android.view.View.layout(View.java:16673) at android.view.ViewGroup.layout(ViewGroup.java:5476) at androidx.swiperefreshlayout.widget.SwipeRefreshLayout.onLayout(SwipeRefreshLayout.java:625) at android.view.View.layout(View.java:16673) at android.view.ViewGroup.layout(ViewGroup.java:5476) at androidx.drawerlayout.widget.DrawerLayout.onLayout(DrawerLayout.java:1231) at android.view.View.layout(View.java:16673) at android.view.ViewGroup.layout(ViewGroup.java:5476) at android.widget.FrameLayout.layoutChildren(FrameLayout.java:336) at android.widget.FrameLayout.onLayout(FrameLayout.java:273) at android.view.View.layout(View.java:16673) at android.view.ViewGroup.layout(ViewGroup.java:5476) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1743) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1586) at android.widget.LinearLayout.onLayout(LinearLayout.java:1495) at android.view.View.layout(View.java:16673) at android.view.ViewGroup.layout(ViewGroup.java:5476) at android.widget.FrameLayout.layoutChildren(FrameLayout.java:336) at android.widget.FrameLayout.onLayout(FrameLayout.java:273) at android.view.View.layout(View.java:16673) at android.view.ViewGroup.layout(ViewGroup.java:5476) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1743) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1586) at android.widget.LinearLayout.onLayout(LinearLayout.java:1495) at android.view.View.layout(View.java:16673) at android.view.ViewGroup.layout(ViewGroup.java:5476) at android.widget.FrameLayout.layoutChildren(FrameLayout.java:336) at android.widget.FrameLayout.onLayout(FrameLayout.java:273) at com.android.internal.policy.PhoneWindow$DecorView.onLayout(PhoneWindow.java:2727) at android.view.View.layout(View.java:16673) at android.view.ViewGroup.layout(ViewGroup.java:5476) at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2304) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2033) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1209) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6333) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:862) at android.view.Choreographer.doCallbacks(Choreographer.java:674) at android.view.Choreographer.doFrame(Choreographer.java:610) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:848) at android.os.Handler.handleCallback(Handler.java:739) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:179) at android.app.ActivityThread.main(ActivityThread.java:5769) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:676)

waseefakhtar commented 4 years ago

I experience this in production with Xiaomi and Android 10. Any idea what the reason might be? I use ViewPager2 1.0.0.

taiji1 commented 4 years ago

I experience this in production with Xiaomi and Android 10. Any idea what the reason might be? I use ViewPager2 1.0.0.

The version I use is also 1.0.0. It may be caused by calling placefragmentinviewholder() .
mFragments get fragment by itemid = null

nb7123 commented 4 years ago

I fixed this issues: I guess when you override 'FragmentStateAdapter' s method [getItemId] but not override method [containsItem], you should also override this method [containsItem]. I found this issues caused by activity/fragment that contains the ViewPager2 paused or stoped, and when resume activity/fragment, the adapter data set changed and ViewPager rebind ViewHolder, when ViewHolder attached to window, this time trigger [gcFragments] methods, here your fragment removed from [mFragments], then cause this issues. The source code: @Override public final void onBindViewHolder(final @NonNull FragmentViewHolder holder, int position) { ... // here bound item and holder mItemIdToViewHolder.put(itemId, viewHolderId); // this might overwrite an existing entry // here put your fragment in [mfragments] ensureFragment(position); ... // gc fragments if needed gcFragments(); }

void gcFragments() {
    ...
    // Remove Fragments for items that are no longer part of the data-set
    Set<Long> toRemove = new ArraySet<>();
    for (int ix = 0; ix < mFragments.size(); ix++) {
        long itemId = mFragments.keyAt(ix);
        // here remove your fragment, then cause that issues
        if (!containsItem(itemId)) {
            toRemove.add(itemId);
            mItemIdToViewHolder.remove(itemId); // in case they're still bound
        }
    }

    ...

    for (Long itemId : toRemove) {
        removeFragment(itemId);
    }
}
houjianbo188 commented 3 years ago

I experience this in production with Xiaomi and Android 10. Any idea what the reason might be? I use ViewPager2 1.1.0-alpha01

Ronak1801 commented 3 years ago

I experience this in production with Xiaomi and Android 10. Any idea what the reason might be? I use ViewPager2 1.1.0-alpha01

hyUrbanManager commented 2 years ago

I fixed this issues: I guess when you override 'FragmentStateAdapter' s method [getItemId] but not override method [containsItem], you should also override this method [containsItem]. I found this issues caused by activity/fragment that contains the ViewPager2 paused or stoped, and when resume activity/fragment, the adapter data set changed and ViewPager rebind ViewHolder, when ViewHolder attached to window, this time trigger [gcFragments] methods, here your fragment removed from [mFragments], then cause this issues. The source code: @OverRide public final void onBindViewHolder(final @nonnull FragmentViewHolder holder, int position) { ... // here bound item and holder mItemIdToViewHolder.put(itemId, viewHolderId); // this might overwrite an existing entry // here put your fragment in [mfragments] ensureFragment(position); ... // gc fragments if needed gcFragments(); }

void gcFragments() {
    ...
    // Remove Fragments for items that are no longer part of the data-set
    Set<Long> toRemove = new ArraySet<>();
    for (int ix = 0; ix < mFragments.size(); ix++) {
        long itemId = mFragments.keyAt(ix);
      // here remove your fragment, then cause that issues
        if (!containsItem(itemId)) {
            toRemove.add(itemId);
            mItemIdToViewHolder.remove(itemId); // in case they're still bound
        }
    }

    ...

    for (Long itemId : toRemove) {
        removeFragment(itemId);
    }
}

oh my god, method [containsItem] what u say is correct. i re implement this method, this problem is never occured. u r my father.

krunalpatel3 commented 1 year ago

I experience this in production with Xiaomi and Android 10. Any idea what the reason might be? I use ViewPager2 1.0.0.

im facing this issue in Poco X2 sometimes