web-dev-qa-db-ja.com

リフレッシュ中にSwipeRefreshLayoutでフラグメントを切り替えると、フラグメントはフリーズしますが、実際にはまだ動作します

更新:私はそれが正しく働くと思った。しかし、いくつかのテストのトラブルがまだ存在する* sniff *

次に、より単純なバージョンを作成して正確に何が起こるかを確認し、デタッチするはずのリフレッシュフラグメントがまだ残っていることを知りました。または、正確には、古いフラグメントのビューがそこに残っています新しいフラグメント。私の元のアプリのRecyclerViewの背景は透明ではないので、前に言ったことが判明しました。

更新の終了


次のようなレイアウトの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を切り替えることにより、表示するコンテンツを切り替えます。 1つを除いてすべてが見栄えが良い:ナビゲーションドロワーによる更新中にContentViewフラグメントを切り替えると、コンテンツがフリーズする。しかし、実際には、あなたがそれを見ることができないことを除いて、すべてのものはいつものように機能します。

72
zlm2012

まあ...いくつかの苦労の後、私は最終的に自分でこの問題をトリッキーな方法で解決しました...

これらをonPause()に追加するだけです。

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

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

この問題は、appcompat 22.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>
75
user1354603

@ zlm2012の回答に加えて、この問題はサポートライブラリ21.0.0で再現されましたが、現在21.0.3で修正されているようです。

3
Metaphore

解決策は機能しますが、次のように、それらの行を独自の関数に入れるだけでよいと思います。

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();
1
Huan Xie

できます!フラグメント置換からトランジションを削除するだけです。私の場合、コードから次を削除しました。

.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
1
raphaelbgr

上位の親レイアウトにclickable="true"を設定します...問題を解決できる場合があります。

1

当面は、次の方法で問題を回避できます。

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");
        }
    }
}

これには、フラグメントを切り替えないことを決定した場合にアニメーションを再開するという追加の利点があります(一部のメニューから)。また、内部のアニメーションと連携して、ネットワークの更新が既に完了している場合、更新するアニメーションが戻らないようにします。

0
Saurabh

ナビゲーションメニュー項目がクリックされるたびにSwipeRefreshを終了します。出来た。

private void selectItem(int position) {

       mSwipeRefreshLayout.setRefreshing(false);

       /*
        Other part of the function
       */
}
0
Shashidhara