9

ユーザーが ViewPager で複数のページを切り替えることができるアプリを設計しています。Fragment インスタンスが画面に表示されなくなったときにページから Fragment インスタンスを削除し、それを (たとえば HashMap に) キャッシュしてから復元して、ユーザーがそのページに戻ると、ビューとその中の他のすべてが削除前と同じ状態になります。たとえば、私の最初のページは、ログインに成功したときに特定のページの特定のレイアウト要素を表示/非表示にするログイン画面です。十分な数のページをめくって最初のページに戻ると、レイアウトがリセットされます。これは、初期化時にバックグラウンドでスレッドを使用して描画するデータの巨大な水平/垂直スクロール グリッドを含む別のページでは、さらに問題になります。

というわけで色々調べてみた...

FragmentStatePageAdapter のソース コードを参照すると、destroyItem() コールバックで、削除される Fragment インスタンスの状態が ArrayList に保存されます。Fragment の新しいインスタンスが instantiateItem() コールバックで作成されているときに、アイテムのインスタンスがまだ存在しない場合 (ArrayList を使用してこれを追跡します)、新しい Fragment インスタンスが作成され、その状態が保存されます。対応する Fragment.SavedState データで初期化されます。残念ながら、このデータにはビューの状態は含まれていませんが、GridView/ListView を含むページの場合、ビューの状態が何らかの形で復元されていることに気付きました (ランダムな位置にスクロールし、いくつかのページをめくって戻ってきた場合)。 、リセットされません)。

APIによると:

保存された状態には、他のフラグメントへの依存関係を含めることはできません。つまり、 putFragment(Bundle, String, Fr​​agment) を使用してフラグメント参照を格納することはできません。これは、この保存された状態が後で使用されるときにその参照が無効になる可能性があるためです。同様に、フラグメントのターゲット コードと結果コードはこの状態には含まれません。

Android の初心者なので、最後のステートメントを理解しているかどうかはよくわかりません。

そうは言っても、ビューの状態をキャッシュする方法はありますか? そうでない場合は、すべてのフラグメント ページをメモリに残しておいてください。

4

5 に答える 5

4

私は同じ問題の問題を抱えていて、これらの2つの機能を実装することで解決しました

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

保存したいフラグメントについて。最初の関数では、ビューを復元する必要がある日付をバンドルに保存する必要があります(私の場合、スピナーがたくさんあったので、int配列を使用してそれらの位置を保存しました)。フラグメントを復元するときに呼び出される2番目の関数は、復元プロセスを実装する場所です。

これがお役に立てば幸いです。また、FragmentStatePageAdapterから継承するようにアダプターを作成しましたが、これが必須かどうかはわかりません。

于 2011-08-11T17:30:23.520 に答える
2

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>

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

詳細については、こちらをご覧くださいページャーの例を表示

于 2011-11-02T16:03:23.247 に答える
1

さまざまなドキュメントを見て、作成しているビューには ID が関連付けられていないと推測されます。フラグメントの保存された状態が Fragment.onSaveInstanceState から作成されると仮定すると、フラグメントは ID を持つビューの状態を自動的に保存します。レイアウト ファイルから作成した場合、おそらく ListView/GridView に関連付けられた既定の ID があります。setId を呼び出して、id をビューに関連付けることもできます。

また、カスタムの塗りつぶされたフラグメントの場合、onSaveInstanceState で何かカスタムを行う必要がある場合もあります。

于 2011-08-05T13:48:40.523 に答える
0

PagerAdapter でキャッシュを実装する方法の例を次に示します。キャッシュがいっぱいになると、それ以降のすべてのビュー リクエストはキャッシュから提供され、データのみが置き換えられます。

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

}
于 2012-10-03T08:58:23.690 に答える
0

PagerSlidingTabStrip を使用していて、FragmentPagerAdapter のインスタンスを使用していたときにも、この問題に遭遇しました。FragmentStatePagerAdapter への切り替えは確実に機能しました。

次に、 onSaveInstanceState() を使用して sate を保存します

于 2015-04-10T14:46:22.130 に答える