70

UPDATE: Я думал, что он работает правильно. Но после некоторой проблемы с тестированием все еще существует * sniff *Когда фрагмент фрагмента с SwipeRefreshLayout во время обновления, фрагмент замерзает, но на самом деле все еще работает

Затем я сделал более простую версию, чтобы узнать, что именно происходит, и я узнаю, что освежающий фрагмент, который должен был быть отсоединен, все же остался там. Или точно, вид старого фрагмента остался там, поверх более новый фрагмент. Поскольку фон RecyclerView моего оригинального приложения не прозрачен, так получилось, что я сказал раньше.

КОНЕЦ UPDATE


У меня есть 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> 

фрагмент ContentView использовать для заполнения @id/container сконфигурирован как:

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

А вот onCreateView() из 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; 
} 

Затем в MainActivity переключить содержимое для отображения при переключении другого ContentView. Все выглядит хорошо, кроме одного: когда я переключаю ContentView фрагменты ВО ВРЕМЯ обновления в навигационном ящике, тогда содержимое зависает. Но на самом деле все работает как обычно, если вы не видите его.

+0

Нормальный, вы хотите обновить, & пока вы меняете весь список, тогда, когда обновление завершается, оно пытается перезагрузить данные, которые были изменены. Вы должны блокировать салфетки при освежении. – Sidd

+0

Ну, похоже, что это ошибка Google ... После обновления до AppCompat v21.0.2, вся боль прошла XD. Спасибо в любом случае <3 – zlm2012

ответ

102

Ну ... Через какое-то изо всех сил, я в конце концов решил эту проблему сам, в хитром пути ...

мне просто нужно, чтобы добавить их в onPause():

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

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

Хотя я добавляю этот код, но кажется, что он не работает, моя библиотека поддержки 22.0.0, действительно, я считаю, что замораживание не исчезает в моем приложении, я пытаюсь использовать setTransition(), и это может также помочь проблема, но оба этого кода и setTransition() не являются полностью истинными, если вы замените фрагмент в течение примерно одной секунды, когда макет салфетки начнет обновляться, вы также найдете содержимое замораживания, но как только за короткий промежуток времени замена фрагмента будет работать должным образом, Последнее решение состоит в том, чтобы деформировать макет салфетки в framelayout, и вам больше не нужно добавлять другой код. – cajsaiko

+0

Проблема по-прежнему сохраняется с 'support-v4: 22.1.1', у меня была эта проблема при использовании прокрутки для обновления и раздвижного меню. Я попытался setRefreshing false при вызове транзакции фрагмента, но это не помогло. Спасибо за решение. –

+0

Несмотря на то, что это может решить проблему, это замедляет все. Если я уничтожу кеш чертежа и очистку слоя анимации swipeRefreshLayout, при переключении с 1 фрагмента на другой есть задержка (отчетливо видимая для человеческого глаза). Google, вы это исправите? – Mike

3

В дополнение к @ Ответ zlm2012, я заметил, что эта проблема была воспроизведена в Support Library 21.0.0, но теперь она исправлена ​​прямо сейчас в 21.0.3

+1

Ошибка 22.2.1. – sosite

+2

Я столкнулся с этой ошибкой с 'compile 'com.android.support: appcompat-v7: 25.1.0'' – EpicPandaForce

73

Эта проблема все еще встречается в 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> 
+0

Отлично работает, спасибо! Меньше взлома, хотя, возможно, немного более неэффективна, чем самое голосованное решение? – Pin

+1

Привет @Pin, я не думаю, что это более тяжелое решение, чем другое. FrameLayout - самый легкий элемент ViewGroup, он не должен добавлять столько сложностей. –

+7

Это работает. Любая идея о том, почему? –

1

решение работает, но я думаю, что лучше всего поместить эти строки в свою собственную функцию, как:

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(); 
0

На данный момент, вы можете избежать проблем с помощью:

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

Это имеет дополнительное преимущество возобновления анимации упаковывает вы решили не переключить фрагмент (исходя из некоторых меню). Он также связан с внутренней анимацией, чтобы убедиться, что обновляющая анимация не возвращается, если обновление сети уже завершено.

1

Это работает!Просто удалите переход от вашей замены фрагмента, в моем случае я удалил вытекающий из моего кода:

.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) 
0

Прекратить SwipeRefresh всякий раз, когда пункт меню навигации кнопки. Это сработало.

private void selectItem(int position) { 

     mSwipeRefreshLayout.setRefreshing(false); 

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

Я сделал это, но я также должен был сделать то, что сказал принятый ответ, иначе я получил связку просмотров на экране, оставшихся от начала до обновления – EpicPandaForce

1

Набор clickable="true" в верхней компоновкой родителя ... Это может решить проблему.

+1

, это решение работает для события click, но для события с проводником навигатора это решение не работает. – samit