Android 在刷新过程中使用SwipeRefreshLayout切换片段时,片段会冻结,但实际上仍然有效

Android 在刷新过程中使用SwipeRefreshLayout切换片段时,片段会冻结,但实际上仍然有效,android,android-fragments,android-recyclerview,swiperefreshlayout,Android,Android Fragments,Android Recyclerview,Swiperefreshlayout,更新:我认为它工作正常。但经过一些测试后,问题仍然存在*嗅探* 然后我制作了一个更简单的版本,看看到底发生了什么,我知道应该分离的刷新片段仍然留在那里。或者确切地说,旧片段的视图留在那里,在新片段的上方。由于RecyclerView对我的原始应用程序的背景不透明,所以它证明了我之前所说的 更新结束 我有一个main活动,布局如下: <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.c

更新:我认为它工作正常。但经过一些测试后,问题仍然存在*嗅探*

然后我制作了一个更简单的版本,看看到底发生了什么,我知道应该分离的刷新片段仍然留在那里。或者确切地说,旧片段的视图留在那里,在新片段的上方。由于RecyclerView对我的原始应用程序的背景不透明,所以它证明了我之前所说的

更新结束


我有一个
main活动
,布局如下:

<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:id="@+id/drawer_layout"
android:layout_width="match_parent" android:layout_height="match_parent">

    <!-- As the main content view, the view below consumes the entire
         space available using match_parent in both dimensions. -->
    <FrameLayout android:id="@+id/container" android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <!-- android:layout_gravity="start" tells DrawerLayout to treat
         this as a sliding drawer on the left side for left-to-right
         languages and on the right side for right-to-left languages.
         If you're not building against API 17 or higher, use
         android:layout_gravity="left" instead. -->
    <!-- The drawer is given a fixed width in dp and extends the full height of
         the container. -->
    <fragment android:id="@+id/navigation_drawer"
        android:layout_width="@dimen/navigation_drawer_width" android:layout_height="match_parent"
        android:layout_gravity="start" tools:layout="@layout/fragment_navigation_drawer" />

</android.support.v4.widget.DrawerLayout>
下面是
ContentView

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View inflatedView = inflater.inflate(R.layout.fragment_content, container, false);

    mRecyclerView = (RecyclerView) inflatedView.findViewById(R.id.tweet_list);
    mRecyclerView.setHasFixedSize(false);

    mLinearLayoutManager = new LinearLayoutManager(getActivity().getApplicationContext());
    mRecyclerView.setLayoutManager(mLinearLayoutManager);

    mTweetList = new ArrayList<Tweet>;
    mAdapter = new TweetAdapter(mTweetList);
    mRecyclerView.setAdapter(mAdapter);
    mRecyclerView.setItemAnimator(new DefaultItemAnimator());

    mSwipeRefreshLayout = (SwipeRefreshLayout) inflatedView.findViewById(R.id.contentView);
    mSwipeRefreshLayout.setOnRefreshListener(
        ...
    );
    return inflatedView;
}
@覆盖
创建视图上的公共视图(布局、充气机、视图组容器、,
Bundle savedInstanceState){
//为该碎片膨胀布局
视图充气视图=充气器。充气(R.layout.fragment\u内容物,容器,假);
mRecyclerView=(RecyclerView)inflatedView.findviewbyd(R.id.tweet_列表);
mRecyclerView.setHasFixedSize(false);
mLinearLayoutManager=newlinearlayoutmanager(getActivity().getApplicationContext());
mRecyclerView.setLayoutManager(mLinearLayoutManager);
mTweetList=新阵列列表;
mAdapter=新的TweetAdapter(mTweetList);
mRecyclerView.setAdapter(mAdapter);
setItemAnimator(新的DefaultItemAnimator());
mSwipeRefreshLayout=(SwipeRefreshLayout)充气视图.findViewById(R.id.contentView);
mSwipeRefreshLayout.setOnRefreshListener(
...
);
返回充气视图;
}

然后在
MainActivity
中,我通过切换不同的
ContentView
来切换要显示的内容。除了一件事之外,所有这些看起来都不错:当我在导航抽屉刷新期间切换
ContentView
fragments时,内容冻结。但事实上,除了你看不见之外,所有的东西都照常工作。

好吧。。。经过一番努力,我终于自己解决了这个问题,用了一种巧妙的方式

我只需要将这些添加到
onPause()


除了@zlm2012 answer之外,我注意到这个问题在Support Library 21.0.0下被复制,但现在似乎在21.0.3上得到了修复。这个问题似乎仍然出现在appcompat 22.1.1中。将SwipeRefreshLayout包装到FrameLayout中解决了这个问题

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<android.support.v4.widget.SwipeRefreshLayout

    android:id="@+id/contentView"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/tweet_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/grey_300" />

</android.support.v4.widget.SwipeRefreshLayout>
</FrameLayout>

解决方案是可行的,但我认为最好将这些行放入它自己的函数中,例如:

public void terminateRefreshing() {
    mSwipeRefreshLayout.setRefreshing(false);
    mSwipeRefreshLayout.destroyDrawingCache();
    mSwipeRefreshLayout.clearAnimation();
}
并在切换片段时调用

Fragment prevFrag = fragmentManager.findFragmentById(drawerContainerId);

if(prevFrag instanceof SwipeRefreshFragment) {
    ((SwipeRefreshFragment)prevFrag).terminateRefreshing();
}

fragmentManager.beginTransaction().replace(drawerContainerId, fragment).commit();

目前,您可以通过以下方式避免该问题:

public class FixedRefreshLayout extends SwipeRefreshLayout {

    private static final String TAG = "RefreshTag";
    private boolean selfCancelled = false;

    public FixedRefreshLayout(Context context) {
        super(context);
    }

    public FixedRefreshLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected Parcelable onSaveInstanceState()
    {
        if(isRefreshing()) {
            clearAnimation();
            setRefreshing(false);
            selfCancelled = true;
            Log.d(TAG, "For hide refreshing");
        }
        return super.onSaveInstanceState();
    }

    @Override
    public void setRefreshing(boolean refreshing) {
        super.setRefreshing(refreshing);
        selfCancelled = false;
    }

    @Override
    public void onWindowFocusChanged(boolean hasWindowFocus) {
        super.onWindowFocusChanged(hasWindowFocus);
        if(hasWindowFocus && selfCancelled) {
            setRefreshing(true);
            Log.d(TAG, "Force show refreshing");
        }
    }
}

如果您决定不切换片段(来自某个菜单),则这具有恢复动画的附加优势。它还与内部动画相关联,以确保如果网络刷新已完成,则刷新动画不会返回。

它可以工作!只需从片段替换中删除转换,在我的例子中,我从代码中删除了以下内容:

.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)

每当单击导航菜单项时终止SwiperFresh。 成功了

private void selectItem(int position) {

       mSwipeRefreshLayout.setRefreshing(false);

       /*
        Other part of the function
       */
}

在顶部父布局中设置
clickable=“true”
。。。它可能会解决问题。

Normal,您需要刷新&当您更改整个列表时,当刷新终止时,它会尝试重新加载已更改的数据。刷新时应该锁定刷卡。看来这是谷歌的错。。。升级到AppCompat v21.0.2后,所有的痛苦都消失了。无论如何,谢谢虽然我添加了这段代码,但它似乎不起作用,我的支持库是22.0.0,事实上我发现冻结并没有在我的应用程序中消失,我尝试使用setTransition(),这也可以解决问题,但这段代码和setTransition()都不是完全正确的,如果在刷卡布局开始刷新时的大约一秒钟内替换碎片,您也会发现冻结内容,但一旦超过短时间,碎片的替换工作正常,我的最后一个解决方案是在framelayout中扭曲刷卡布局,您不需要再添加其他代码。问题仍然存在于
support-v4:22.1.1
,我在使用滑动刷新和滑动菜单时遇到此问题。在调用片段事务时,我试图设置为false,但这不起作用。感谢您提供的解决方案。将SwipeRefreshLayout包装在appcompat v7:22+中解决的框架布局中也适用于此:
com.android。支持:appcompat-v7:24.2.1
谢谢。我在FragmentTransaction期间只有
设置刷新(false)
。添加
clearAnimation()
后,我的应用程序不会冻结。效果很好,谢谢!不太老套,但可能比最受欢迎的解决方案效率稍低?嗨@Pin,我不认为这是一个比另一个更重的解决方案。。FrameLayout是最轻的ViewGroup元素,它不应该增加太多的复杂性。这在片段中对我来说确实有效。哇,谢谢!它解决了我的问题!我浪费了这么多时间寻找原因和解决办法。这是必须接受的正确答案!在25.2.0版本中,错误仍然存在,这解决了问题。我想在找到这个解决方案之前把桌子翻过来。谢谢。在22.2.1中,错误仍然存在。我在编译com.android.support:appcompat-v7:25.1.0时遇到了这个错误。我做了这件事,但我也必须按照公认的答案去做,否则我会在屏幕上看到一堆开始刷新时留下的视图。这个解决方案适用于点击事件,但对于导航抽屉滑动事件,此解决方案不起作用。
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
private void selectItem(int position) {

       mSwipeRefreshLayout.setRefreshing(false);

       /*
        Other part of the function
       */
}