2011-08-02 19 views
9

Projektuję aplikację, która pozwala użytkownikom przechodzić między wieloma stronami w ViewPager. Starałem się dowiedzieć, jak można usunąć instancję Fragment ze strony, gdy nie jest ona już widoczna na ekranie, umieścić ją w pamięci podręcznej (na przykład w HashMap), a następnie przywrócić ją tak, aby użytkownik odwraca się z powrotem na tę stronę, widoki i wszystkie pozostałe elementy będą w tym samym stanie, w jakim były przed usunięciem. Na przykład moja pierwsza strona to ekran logowania, który sprawia, że ​​niektóre elementy układu na tej konkretnej stronie są widoczne/niewidoczne po pomyślnym zalogowaniu. Po przewróceniu dostatecznej liczby stron i cofnięciu do pierwszej strony układ zostanie zresetowany. Staje się to większym problemem dla innej mojej strony, która zawiera ogromną, poziomą/pionową przewijaną siatkę danych, której używam wątku w tle do rysowania, gdy jest inicjowany. Używam okna dialogowego postępu, aby powiadomić użytkownika o postępie ładowania i to staje się naprawdę denerwujące za każdym razem, gdy muszę je załadować.Android: Viewpager i FragmentStatePageAdapter

Więc zrobiłem rozeznanie ...

I przejrza³e¶ kodu źródłowego FragmentStatePageAdapter aw destroyItem() callback, stan instancji Fragment usuwany jest zapisany do ArrayList. Kiedy tworzona jest nowa instancja Fragmentu w wywoływaniu instantiateItem(), jeśli instancja elementu jeszcze nie istnieje (śledzą to przez użycie ArrayList), tworzona jest nowa instancja Fragmentu i jej stan zapisany jest inicjowany odpowiednimi danymi Fragment.SavedState. Niestety, te dane nie uwzględniają stanu, w którym były Widoki, chociaż zauważyłem, że dla stron z GridView/ListView, stan Widowisk został jakoś przywrócony (gdy przewinąłem do jakiejś przypadkowej pozycji, przewróciłem kilka stron i wróciłem , nie zostanie zresetowany).

Według API

Zapisany stan nie może zawierać zależności od innych fragmentów - , która nie może użyć putFragment (Bundle, łańcuch, fragment) do przechowywania odniesienia fragment poznieważ Odniesienie to może nie być poprawne, gdy ten stan zapisany w postaci jest później używany. Podobnie cel Fragment i wynik kodu nie są zawarte w tym stanie.

Będąc noobem Androida, nie jestem pewien, czy rozumiem ostatnie stwierdzenie.

Czy jest tam jakikolwiek sposób buforowania widoku stanu? Jeśli nie, myślę, że po prostu pójdę dalej i pozostawiam w pamięci wszystkie strony fragmentów.

Odpowiedz

1

Patrząc na różne elementy dokumentacji, domyślam się, że widoki, które tworzysz, nie mają dołączonego do nich identyfikatora. Zakładając, że zapisany stan fragmentu został utworzony z Fragment.onSaveInstanceState, fragment automatycznie zapisze stan dowolnego widoku, który ma identyfikator. Prawdopodobnie masz domyślny identyfikator powiązany z twoim ListView/GridView, jeśli utworzyłeś je z pliku układu. Możesz również powiązać identyfikator z widokami, wywołując setId.

Również w przypadku niestandardowego wypełnionego fragmentu może również wystąpić konieczność zrobienia czegoś niestandardowego w onSaveInstanceState.

4

miałem ten sam problem i go rozwiązał problemu poprzez wdrożenie tych dwóch funkcji

public void onSaveInstanceState (Bundle outState) 
    public void onActivityCreated (Bundle savedInstanceState) 

na fragmentach że chciałem zaoszczędzić. W pierwszej funkcji należy zapisać w pakiecie datę, która jest potrzebna do przywrócenia widoków (w moim przypadku miałem sporo spinnera, więc użyłem tablicy int, aby zapisać swoje pozycje).Druga funkcja, która jest wywoływana podczas przywracania fragmentu, to miejsce, w którym wdrażasz proces przywracania.

Mam nadzieję, że to pomoże. Zrobiłem również adapter do dziedziczenia z FragmentStatePageAdapter, ale nie jestem pewien, czy jest to obowiązkowe.

+3

trzeba dziedziczą FragmentStatePagerAdapter, jeśli tylko używać FragmentPagerAdapter następnie onSaveInstanceState nie zostanie wywołana. – Scott

2

Notowania main.xml

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="vertical" android:layout_width="fill_parent" 
    android:layout_height="fill_parent"> 
    <TextView android:text="Page 1" android:id="@+id/textViewHeader" 
     android:layout_width="fill_parent" android:layout_height="wrap_content" 
     android:gravity="center" android:padding="10dip" android:textStyle="bold"></TextView> 
    <android.support.v4.view.ViewPager 
     android:layout_width="fill_parent" android:layout_height="fill_parent" 
     android:id="@+id/viewPager" /> 
</LinearLayout> 

Konfigurowanie ViewPager

ViewPager viewPager = (ViewPager) findViewById(R.id.viewPager); 
MyPagerAdapter adapter = new MyPagerAdapter(this); 
viewPager.setAdapter(adapter); 

PagerAdapter

@Override 
public void destroyItem(View view, int arg1, Object object) { 
     ((ViewPager) view).removeView((View)object); 
} 
@Override 
public int getCount() { 
      return views.size(); 
} 
@Override 
public Object instantiateItem(View view, int position) { 
      View view = views.get(position); 
      ((ViewPager) view).addView(view); 
      return view; 
} 
@Override 
public boolean isViewFromObject(View view, Object object) { 
      return view == object; 
} 

spojrzeć tutaj po więcej szczegółów view pager example

1

H Oto przykład tego, jak zaimplementowałem buforowanie w PagerAdapter. Po wypełnieniu pamięci podręcznej wszystkie przyszłe żądania przeglądania są obsługiwane z pamięci podręcznej, zastępowane są tylko dane.

public class TestPageAdapter extends PagerAdapter{ 

private int MAX_SIZE = 3; 
private ArrayList<SoftReference<View>> pageCache = new ArrayList<SoftReference<View>>(3); 


public TestPageAdapter(Context context){ 
    // do some initialization 
} 

@Override 
public int getCount() { 
    // number of pages 
} 

private void addToCache(View view){ 
    if (pageCache.size() < MAX_SIZE){ 
     pageCache.add(new SoftReference<View>(view)); 
    } else { 
     for(int n = (pageCache.size()-1); n >= 0; n--) { 
      SoftReference<View> cachedView = pageCache.get(n); 
      if (cachedView.get() == null){ 
       pageCache.set(n, new SoftReference<View>(view)); 
       return; 
      } 
     } 
    } 
} 

private View fetchFromCache(){ 
    for(int n = (pageCache.size()-1); n>= 0; n--) { 
     SoftReference<View> reference = pageCache.remove(n); 
     View view = reference.get(); 
     if (view != null) { 
      return view; 
     } 
    } 
    return null; 
} 

@Override 
public Object instantiateItem(View collection, int position) { 
    View view = fetchFromCache(); 
    if (view == null) { 
     // not in cache, inflate manually 
     LayoutInflater inflater = (LayoutInflater) collection.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     view = inflater.inflate(R.layout.page, null); 
    } 
    setData(view, position); 
    ((ViewPager) collection).addView(view, 0); 
    return view;   
} 

private void setData(View view, int position){ 
    // set page data (images, text ....) 
} 

public void setPrimaryItem(ViewGroup container, int position, Object object) { 
    currentItem = (View)object; 
} 

public View getCurrentItem() { 
    return currentItem; 
} 

@Override 
public boolean isViewFromObject(View view, Object object) { 
    return view == ((View) object); 
} 

@Override 
public void destroyItem(View collection, int arg1, Object view) { 
    ((ViewPager) collection).removeView((View) view); 
    addToCache((View) view); 
} 

} 
0

ja też wpadłem na ten problem, kiedy używałem PagerSlidingTabStrip i korzystania i wystąpienie FragmentPagerAdapter, przełączenie na FragmentStatePagerAdapter zdecydowanie działało.

Następnie używam onSaveInstanceState(), aby zapisać Sate

Powiązane problemy