2017-01-31 16 views
8

在我的應用程序中,我有ViewPager內部的片段。片段包含RecyclerView和基於用戶選擇從Web API獲取的數據列表。片段,在onSaveInstanceState上保存大型數據列表(如何防止TransactionTooLargeException)

在我的片段onSaveInstanceState我清單數據保存到邦德,保持對配置變化等

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

現在我已經開始看到TransactionTooLargeException我的應用程序錯誤報告中的數據。

看來在某些情況下,我把這個列表放到Bundle中,太大了(因爲它是非常複雜的對象的集合)。

我應該如何處理這種情況?如何存儲(並恢復)我的Fragment狀態。

可以在ViewPager內的碎片上使用setRetainInstance(true)嗎?

+0

如果我做到了,我將所有的網絡運營和數據,從數據庫中檢索網絡存儲到某些服務。在這種情況下,您不需要保存它,因爲它存儲在服務中 –

+0

這聽起來像現在一點點矯枉過正。更簡單的解決方案將是從Web API再次獲取數據,但我認爲這不是很好的用戶體驗。 – devha

+0

好吧,作爲一個醜陋而快速的選擇,您可以將數據保存到共享首選項或文件中。 –

回答

5

爲了保留大量的數據,Google建議使用保留實例的Fragment來實現。想法是創建空的片段,而不用查看所有必需的字段,否則這些字段將被保存在Bundle中。 添加setRetainInstance(true);到片段的onCreate方法。並且比在Activity的onDestroy中保存Fragment中的數據並將它們加載到Create上。下面是活動的和示例:片段的

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

這確實是由谷歌推薦,但這是否在片段內工作,使用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); 
    } 

    } 

} 

然後,在你的片段,你可以投getActivity()你的活動類,並使用saveState(String, Object)getState(String)保存您的列表。


有這個其他討論可在以下位置找到:

What to do on TransactionTooLargeException

android.os.TransactionTooLargeException on Nougat(接受的答案建議setRetainInstance(true))。

0

setRetainInstance()是實現一種無副作用的最好方式。使用static將導致內存泄漏,並且沒有將onSaveInstanceState()中的狀態保存並將其取回的用處,因爲setRetainInstance()會爲您執行此操作。

因此,創建一個領域中的片段類列表,並經常檢查null或列表的size開始獲取最新數據的操作