2017-01-31 9 views
8

私のアプリケーションでは、私はViewPagerの中にあるフラグメントを持っています。フラグメントにはRecyclerViewが含まれ、ユーザーの選択に基づいてWeb APIからフェッチされたデータのリストが含まれます。私の断片onSaveInstanceStateフラグメント、onSaveInstanceStateの大きなデータリストを保存する(TransactionTooLargeExceptionを防ぐ方法)

は、私は今、私は私のアプリのエラー報告に TransactionTooLargeExceptionを見始めているなど、設定の変更

public void onSaveInstanceState(Bundle savedState) { 
    super.onSaveInstanceState(savedState); 
    savedState.putParcelableArrayList(LIST_STORAGE_KEY, new ArrayList<>(mItemAdapter.getModels())); 
} 

上のデータを保持するために、ビュンデにリストデータを保存します。

ImはBundleに置くリストが大きすぎるようです(かなり複雑なオブジェクトのコレクションなので)。

このケースはどのように処理する必要がありますか?私のフラグメント状態を保存(および復元)する方法。

ViewPager内のフラグメントにsetRetainInstance(true)を使用してもよろしいですか?

+0

をフェッチする動作を開始するために、フラグメントクラスのリストのためのフィールドを作成し、常にnullまたはリストのsizeをチェックしますいくつかのサービスにネットワークを格納する。この場合は、サービスに保存されているため、保存する必要はありません。 –

+0

これは少し残酷すぎるような音です。簡単な解決策は、Web APIからデータを再度取得することですが、ユーザーエクスペリエンスはそれほど優れていないと思います。 – devha

+0

醜く高速な代替手段として、データを共有設定やファイルに保存することができます。 –

答えて

5

大量のデータを保存するには、インスタンスを保持するFragmentを使用することをおすすめします。アイデアは、Bundleに保存されていた必要なすべてのフィールドを含むビューなしで空のFragmentを作成することです。 setRetainInstanceを追加(true); FragmentのonCreateメソッドに追加します。そして、Fragment on Activity onDestroyにデータを保存し、onCreateをロードするよりも。ここで、活動の例:

public class MyActivity extends Activity { 

private DataFragment dataFragment; 

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 

    // find the retained fragment on activity restarts 
    FragmentManager fm = getFragmentManager(); 
    dataFragment = (DataFragment) fm.findFragmentByTag("data"); 

    // create the fragment and data the first time 
    if (dataFragment == null) { 
     // add the fragment 
     dataFragment = new DataFragment(); 
     fm.beginTransaction().add(dataFragment, "data").commit(); 
     // load the data from the web 
     dataFragment.setData(loadMyData()); 
    } 

    // the data is available in dataFragment.getData() 
    ... 
} 

@Override 
public void onDestroy() { 
    super.onDestroy(); 
    // store the data in the fragment 
    dataFragment.setData(collectMyLoadedData()); 
} 
} 

とフラグメントの例:

public class DataFragment extends Fragment { 

// data object we want to retain 
private MyDataObject data; 

// this method is only called once for this fragment 
@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    // retain this fragment 
    setRetainInstance(true); 
} 

public void setData(MyDataObject data) { 
    this.data = data; 
} 

public MyDataObject getData() { 
    return data; 
} 
} 
+0

これは確かにGoogle、しかし、このフラグメント内での作業は、DataFragmentをネストされたフラグメントとして使用しますか?現在のところ、私の断片は独立したコンポーネントとして動作し、断片が親タスクにそのタスクを与える状態を保存/復元することができればうれしいでしょう。 – devha

+0

私はサービスとアプリケーションの間で膨大なデータ(> 1MB)を交換していたので、空のフラグメントを作成しました。 – Shobhit

+2

@devhaこれはネストされたフラグメントとして実行できます。 'beginTransaction ...'の前にこれを追加します。 'dataFragment.setTargetFragment(this、0);' – Gary99

1

フラグメントにsetRetainInstance(true)を使用しない場合は、setRetainInstance(true)の空のフラグメントをアクティビティに追加できます。子フラグメントはsetRetainInstance(true)を使用できないので、これは便利です。

例:

public class BaseActivity extends Activity { 

    RetainedFragment retainedFragment; 

    @Override protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    retainedFragment = (RetainedFragment) getFragmentManager().findFragmentByTag("retained_fragment"); 
    if (retainedFragment == null) { 
     retainedFragment = new RetainedFragment(); 
     getFragmentManager().beginTransaction().add(retainedFragment, "retained_fragment").commit(); 
    } 
    } 

    public <T> T getState(String key) { 
    //noinspection unchecked 
    return (T) retainedFragment.map.get(key); 
    } 

    public void saveState(String key, Object value) { 
    retainedFragment.map.put(key, value); 
    } 

    public boolean has(String key) { 
    return retainedFragment.map.containsKey(key); 
    } 

    public static class RetainedFragment extends Fragment { 

    HashMap<String, Object> map = new HashMap<>(); 

    @Override public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setRetainInstance(true); 
    } 

    } 

} 

次に、あなたのフラグメントに、あなたはActivityクラスへgetActivity()をキャストし、あなたのリストを保存するsaveState(String, Object)getState(String)を使用することができます。


次の場所で見つけることができ、この上の他の議論があります。

What to do on TransactionTooLargeException

android.os.TransactionTooLargeException on Nougatは(受け入れ答えはsetRetainInstance(true)ことを示唆しています)。

0

setRetainInstance()は副作用なしにそれを達成するための最良の方法です。 staticを使用するとメモリリークが発生し、onSaveInstanceState()に状態を保存することはなく、setRetainInstance()がそれを返します。

ので、私はそれをしなかった場合、私はから取得したすべてのネットワーク・オペレーション&データを、移動したい最新のデータ

関連する問題