片段newInstance将太多数据保存到bundle - android.os.TransactionTooLargeException

时间:2017-09-12 11:35:02

标签: java android exception transactions bundle

我创建了片段标准方式(Android Studio生成的骨架)。所以我有newInstance静态方法:

public static EventsMapFragment newInstance(List<Event> eventList, String accessToken, String tokenType, String cityId, boolean isMessage)
{
     Bundle args = new Bundle();
     args.putString("events", new Gson().toJson(eventList));
     EventsMapFragment fragment = new EventsMapFragment();

     ///...........
     fragment.setArguments(args);
     return fragment;
}

然后,onCreate覆盖我需要以非常标准的方式检索我的集合:

 @Override
 public void onCreate(Bundle savedInstanceState)
 {
    super.onCreate(savedInstanceState);
    if (getArguments() != null)
    {
        String json = getArguments().getString("events");
        Type type = new TypeToken<List<Event>>(){}.getType();
        mEventList = new Gson().fromJson(json, type);
   }

问题是eventList集合非常大,所以我得到例外:

  

java.lang.RuntimeException:android.os.TransactionTooLargeException:   数据包大小592196字节

我的应用程序中的其他地方(很奇怪,json正确传递,但系统不允许传递更多东西到捆绑,跟踪确切问题的位置并不容易)。

因为newInstance()方法是静态的,我无法创建保留片段并将数据传递给它(在这种情况下我实际上不知道如何做到这一点)。

我的解决方案是使用WeakReference传递数据,如下所示:

public class DataHolder
{
    private static final DataHolder holder = new DataHolder();
    Map<String, WeakReference<Object>> data = new HashMap<>();

    public static DataHolder getInstance() {return holder;}

    public void save(String id, Object object)
    {
        data.put(id, new WeakReference<>(object));
    }

    public Object retrieve(String id)
    {
        WeakReference<Object> objectWeakReference = data.get(id);
        return objectWeakReference.get();
    }
}

然后,存储数据(而不是使用bundle):

DataHolder.getInstance().save("eventList", eventList);

并检索数据:

mEventList = (List<Event>) DataHolder.getInstance().retrieve("eventList");

但是,这不适用于KitKat(它似乎在5.1和更新版本上正常工作)。主要问题我无法在KitKat上调试,因为multidex,所以调试编译甚至不会在KitKat上运行(发布有minifyEnabled=true而没有多指令)。但似乎在KitKat上,这个:

mEventList = (List<Event>) DataHolder.getInstance().retrieve("eventList");

始终为空。

你有什么想法吗?我目前的解决方案是检查构建版本并将Json传递给KitKat上的bundle(它适用于KitKat,问题是7.0及更新版本)并在较新的Android版本上使用WeakReference。

但我对此并不满意。

[编辑] 所以我最后的尝试是从父活动中获取事件集合。在主要活动中,我有以下代码(一个app抽屉菜单点击):

if (menuId == R.id.nav_events_map)
{
  eventsToDraw =  Lists.newArrayList(Collections2.filter(events,x->!Utils.isGeojsonEmpty(x.getGeojson())));
  //....................
  if(eventsToDraw.size() >0)
  {
    mFragment = EventsMapFragment.newInstance();
    ReplaceFragment(mFragment);
  }
  else
  {
   mFragment = NoDataFragment.newInstance(getString(R.string.message_no_events));
   ReplaceFragment(mFragment);
 }
}

eventsToDraw是私有字段,我只是创建了getter:

public List<Event> getEventsToDraw()
{
  return eventsToDraw;
}

然后,在我的地图片段中:

@Override
 public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
 {
  //Map initialization stuff
  //....................

   mEventList = ((MainActivity)getActivity()).getEventsToDraw();

  //Draw on map stuff etc
 }

问题是我总是得mEventList null。经过一些调试后,我注意到,getEventsToDraw()被提前调用,所以它不会返回我的集合,它返回null,因为还没有可用的数据。

1 个答案:

答案 0 :(得分:0)

  

适用于KitKat

不,它没有。 1MB IPC交易限制已存在多年。但是,该限制适用于您的流程的所有同时IPC事务,因此故障将是概率性的。例如,592196小于1MB,因此对你来说崩溃的事实上有时可能会通过OK,因为在那个时刻IPC几乎没有其他事情发生。

  

所以我有newInstance静态方法

不要传递一系列事件。传递片段所需的最小信息,以获取事件集合。使用进程级POJO缓存来最小化冗余I / O,但支持在需要时再次访问数据库/网络/任何内容,因此您可以处理两个配置更改(进程缓存仍然存在)和进程终止(但用户返回的位置)您的任务相当快,因此仍然使用实例统计信息。)