当在刷新期间使用 SwipeRefreshLayout 切换片段时,片段会冻结,但实际上仍然可以工作

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

然后我做了一个更简单的版本,看看到底发生了什么,我得知那个本应该被分离的令人耳目一新的片段仍然留在那里。或者确切地说,是留在那里的旧片段的视图,是较新的片段。因为我的原始应用程序的回收视图的背景是不透明的,所以它变成了我之前说的。

更新完毕


我有一个 MainActivity的布局是这样的:

<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>

我用来填充 @id/container的片段 ContentView配置为:

<android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
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>

这是 ContentViewonCreateView()

@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;
}

然后在 MainActivity中我通过切换不同的 ContentView来切换显示的内容。所有看起来都很好,除了一件事: 当我切换 ContentView片段在导航抽屉刷新期间,然后内容冻结。但事实上,除了你看不到它之外,一切都照常运转。

15231 次浏览

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

我只需要在 onPause()中添加以下内容:

@Override
public void onPause() {
super.onPause();
...


if (mSwipeRefreshLayout!=null) {
mSwipeRefreshLayout.setRefreshing(false);
mSwipeRefreshLayout.destroyDrawingCache();
mSwipeRefreshLayout.clearAnimation();
}
}

除了@zlm2012的回答之外,我注意到这个问题在 Support Library 21.0.0下重现了,但是现在似乎已经修复到了21.0.3

这个问题似乎仍然发生在 appcompat22.1.1中。在 FrameLayout 中包装 SwipeRefreshLayout 为我解决了这个问题

<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)

单击导航菜单项时终止 SwipeRefresh。 成功了。

private void selectItem(int position) {


mSwipeRefreshLayout.setRefreshing(false);


/*
Other part of the function
*/
}

设置 clickable="true"在顶部父布局... 它可以解决这个问题。