Wenn das Fragment während der Aktualisierung mit SwipeRefreshLayout gewechselt wird, friert das Fragment ein, funktioniert aber tatsächlich noch

73

UPDATE: Ich dachte, es hat richtig funktioniert. Aber nach einigen Tests gibt es immer noch Probleme * schnüffeln *

Dann habe ich eine einfachere Version gemacht, um zu sehen, was genau passiert, und ich erfahre, dass das erfrischende Fragment, das hätte entfernt werden sollen, immer noch dort geblieben ist. Oder genau die Ansicht des alten Fragments, das dort oben auf dem neueren Fragment verbleibt. Da der Hintergrund meiner ursprünglichen App durch RecyclerView nicht transparent ist, stellte sich heraus, was ich zuvor gesagt habe.

ENDE DES UPDATE


Ich habe ein MainActivityLayout wie dieses:

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

Das Fragment, das ContentViewich zum Füllen verwende, @id/containerist wie folgt konfiguriert:

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

Und hier ist onCreateView()vonContentView

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

Dann schalte MainActivityich in den Inhalt um, um anzuzeigen, indem ich anders wechsle ContentView. Bis auf eines sieht alles gut aus: Wenn ich ContentViewwährend der Aktualisierung durch die Navigationsschublade die Fragmente wechsle, friert der Inhalt ein. Aber eigentlich funktionieren alle Dinge wie gewohnt, außer dass Sie es nicht sehen können.

zlm2012
quelle
Normal, Sie möchten eine Aktualisierung, und während Sie die gesamte Liste ändern, wird beim Beenden der Aktualisierung versucht, geänderte Daten neu zu laden. Sie sollten das Wischen beim Aktualisieren sperren.
Sidd
Nun, es scheint, dass es Googles Schuld ist ... Nach dem Upgrade auf AppCompat v21.0.2 sind alle Schmerzen XD verschwunden.
Trotzdem

Antworten:

105

Nun ... Nach einigem Kämpfen habe ich dieses Problem schließlich auf knifflige Weise selbst gelöst ...

Ich muss nur diese hinzufügen in onPause():

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

    if (mSwipeRefreshLayout!=null) {
        mSwipeRefreshLayout.setRefreshing(false);
        mSwipeRefreshLayout.destroyDrawingCache();
        mSwipeRefreshLayout.clearAnimation();
    }
}
zlm2012
quelle
1
Obwohl ich diesen Code hinzufüge, aber es scheint nicht zu funktionieren, ist meine Support-Bibliothek 22.0.0. In der Tat finde ich, dass das Einfrieren in meiner App nicht verschwindet. Ich versuche, setTransition () zu verwenden, und dies kann auch das Problem lösen, aber beides code und setTransition () sind nicht vollständig wahr. Wenn Sie das Fragment innerhalb von etwa einer Sekunde ersetzen, wenn das Swipe-Layout aktualisiert wird, werden Sie auch Einfrierinhalte finden. Wenn das Ersetzen des Fragments jedoch nach kurzer Zeit ordnungsgemäß funktioniert, besteht meine letzte Lösung darin, zu verzerren das Swipe-Layout in einem Framelayout, und Sie müssen keinen weiteren Code mehr hinzufügen.
Cajsaiko
Das Problem besteht weiterhin support-v4:22.1.1. Ich hatte dieses Problem, als ich zum Aktualisieren und Schieben des Menüs mit dem Wischen verwendet habe. Ich habe versucht, beim Aufrufen der Fragmenttransaktion false festzulegen, aber das hat nicht funktioniert. Danke für die Lösung.
Ultimo_m
5
Einwickeln des SwipeRefreshLayout in ein FrameLayout, das in Appcompat v7: 22+ gelöst wurde
Rahul Rastogi
1
Funktioniert auch hier:com.android.support:appcompat-v7:24.2.1
Jeremy
2
Vielen Dank. Ich hatte nur setRefreshing(false)während FragmentTransaction. Nach dem Hinzufügen clearAnimation()funktioniert meine App ohne Einfrieren.
RobinBattle
76

Dieses Problem scheint in AppCompat 22.1.1 immer noch aufzutreten. Das Einwickeln des SwipeRefreshLayout in ein FrameLayout hat dies für mich gelöst

<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>
user1354603
quelle
Funktioniert super, danke! Weniger hackig, aber vielleicht etwas ineffizienter als die am häufigsten gewählte Lösung?
Pin
1
Hallo @Pin, ich denke nicht, dass es eine schwerere Lösung als die andere ist. FrameLayout ist das leichteste ViewGroup-Element, es sollte nicht so viel Komplexität hinzufügen.
andrea.rinaldi
1
Das hat bei mir in einem Fragment tatsächlich funktioniert. Beeindruckend.
EpicPandaForce
2
Vielen Dank! Es ist mein Problem zu lösen! Ich habe so viel Zeit damit verschwendet, nach dem Grund und der Lösung zu suchen. Es muss als richtige Antwort akzeptiert werden!
Trancer
3
In 25.2.0 trat immer noch ein Fehler auf und dieses Problem wurde gelöst. Ich wollte den Tisch umdrehen, bevor ich diese Lösung fand. Vielen Dank.
Lukas Novak
3

Zusätzlich zur Antwort von @ zlm2012 habe ich festgestellt, dass dieses Problem unter Support Library 21.0.0 reproduziert wurde, aber derzeit um 21.0.3 behoben zu sein scheint

Metapher
quelle
1
In 22.2.1 ist immer noch ein Fehler aufgetreten.
Sosite
3
Ich bin auf diesen Fehler compile 'com.android.support:appcompat-v7:25.1.0'
gestoßen
1

Die Lösung funktioniert, aber ich denke, es ist besser, diese Zeilen in eine eigene Funktion zu setzen, wie zum Beispiel:

public void terminateRefreshing() {
    mSwipeRefreshLayout.setRefreshing(false);
    mSwipeRefreshLayout.destroyDrawingCache();
    mSwipeRefreshLayout.clearAnimation();
}

und beim Wechseln des Fragments aufrufen.

Fragment prevFrag = fragmentManager.findFragmentById(drawerContainerId);

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

fragmentManager.beginTransaction().replace(drawerContainerId, fragment).commit();
Huan Xie
quelle
1

Es klappt! Entfernen Sie einfach den Übergang von Ihrem Fragmentersatz. In meinem Fall habe ich Folgendes aus meinem Code entfernt:

.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
raphaelbgr
quelle
1

Im clickable="true"obersten übergeordneten Layout festlegen ... Möglicherweise wird das Problem behoben.

Bishwajeet Biswas
quelle
1
Diese Lösung funktioniert für Klickereignisse, aber für Swipe-Ereignisse in Navigationsschubladen funktioniert diese Lösung nicht.
Samit
0

Vorerst können Sie das Problem vermeiden, indem Sie:

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

Dies hat den zusätzlichen Vorteil, dass die Animation fortgesetzt wird, falls Sie das Fragment nicht wechseln möchten (aus einem Menü). Es wird auch mit der internen Animation verknüpft, um sicherzustellen, dass die Aktualisierungsanimation nicht zurückgegeben wird, wenn die Netzwerkaktualisierung bereits abgeschlossen ist.

Saurabh
quelle
0

Beenden Sie SwipeRefresh, wenn Sie auf das Navigationsmenüelement klicken. Es funktionierte.

private void selectItem(int position) {

       mSwipeRefreshLayout.setRefreshing(false);

       /*
        Other part of the function
       */
}
Shashidhara
quelle
Ich tat dies, aber ich musste auch tun, was in der akzeptierten Antwort stand, sonst bekam ich eine Reihe von Ansichten auf dem Bildschirm, die vom Beginn der Aktualisierung
übrig geblieben waren