【问题标题】:Fragment newInstance too much data saved to bundle - android.os.TransactionTooLargeExceptionFragment newInstance 太多数据保存到捆绑包 - android.os.TransactionTooLargeException
【发布时间】:2017-09-12 11:35:02
【问题描述】:

我已经创建了片段标准方式(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 我需要检索我的收藏,非常标准的方式:

 @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 被正确传递,但系统不允许传递更多内容到 bundle,很难跟踪确切的问题所在)。

因为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 并且没有 multi dex)。但在 KitKat 上,这似乎是:

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

始终为空。

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

但实际上我对此并不满意。

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

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,因为还没有可用的数据。

【问题讨论】:

    标签: java android exception transactions bundle


    【解决方案1】:

    它适用于 KitKat

    不,它没有。 1MB IPC 交易限制已存在多年。但是,该限制适用于您的进程的所有同时 IPC 事务,因此失败将是概率性的。例如,592196 小于 1MB,所以对于你来说崩溃的东西有时实际上可能会通过 OK,因为此时 IPC 恰好没有什么其他事情发生。

    所以我有 newInstance 静态方法

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

    【讨论】:

    • “不要传递事件集合” - 我需要传递事件集合,这可能很大。它们需要显示在地图上,所以我需要收集。事件非常复杂,每个事件都包含一些附加数据,应在标记单击时显示。没有办法检索项目,它们需要传递给片段。我目前的解决方案是创建 setter 并且不将任何内容传递给 bundle(配置更改已在清单中为父活动禁用)。
    • 将大量数据从活动传递到片段的有效解决方案是什么?我们不能为此使用 bundle,不推荐使用 setter。所以?我的活动包含一些从 web 服务检索到的数据(它是一个列表),我希望它们显示出来,而不需要从服务器刷新,我需要绘制当前内容。
    • @user1209216:“我需要传递可能很大的事件集合”——恕我直言,您应该将它们保存到磁盘,使用内存作为缓存。使用您的解决方案,用户可能会切换到另一个应用程序几秒钟,然后返回到您的应用程序并丢失所有这些数据,因为 Android 选择在您的应用程序不在前台时终止您的进程。
    • @user1209216:“将大量数据从活动传递到片段的有效解决方案是什么?” ——你没有。最多,您让片段向其附加的活动询问数据。
    • @user1209216:是的。让片段通过getActivity()获取托管活动并调用该方法。
    猜你喜欢
    • 2017-11-20
    • 1970-01-01
    • 2012-11-19
    • 1970-01-01
    • 2021-12-14
    • 2011-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多