简体   繁体   English

碎片化newInstance保存到捆绑的太多数据-android.os.TransactionTooLargeException

[英]Fragment newInstance too much data saved to bundle - android.os.TransactionTooLargeException

I have created fragment standard way (skeleton generated by Android Studio). 我创建了片段标准方式(由Android Studio生成的骨架)。 So I have newInstance static method: 所以我有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;
}

Then in, onCreate override I need to retrieve my collection, quite standard way: 然后,在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);
   }

The problem is that eventList collection is very large, so I'm getting exception: 问题在于eventList集合非常大,因此出现异常:

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

somewhere else in my app (weird, json is passed correctly, but system does not allow to pass anything more to bundle, it was not ease to track where exact problem is). 我的应用程序中的其他地方(奇怪的是,json正确传递了,但是系统不允许传递任何其他东西来捆绑,这很难跟踪确切的问题出在哪里)。

Because newInstance() method is static, I am unable to create retain fragment and pass data into it (I actually have no idea how to do that in this case). 因为newInstance()方法是静态的,所以我无法创建保留片段并将数据传递给它(在这种情况下,我实际上不知道该怎么做)。

My solution is to use WeakReference to pass data, something like that: 我的解决方案是使用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();
    }
}

Then, to store data (instead of using bundle): 然后,要存储数据(而不是使用捆绑软件):

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

And to retrieve data: 并检索数据:

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

However, this does not work on KitKat (it seems to be working fine on 5.1 and newer). 但是,这在KitKat上不起作用(在5.1及更高版本上似乎可以正常工作)。 Main trouble I am unable to debug on KitKat, because of multidex, so debug compilation won't even run on KitKat (release has minifyEnabled=true and no multi dex). 主要麻烦由于多dex,我无法在KitKat上进行调试,因此调试编译甚至无法在KitKat上运行(发行版具有minifyEnabled=true且没有多dex)。 But it seems, on KitKat, this: 但是在KitKat上似乎是这样的:

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

is always null. 始终为null。

Do you have any ideas? 你有什么想法? My current solution is to check build version and pass json to bundle on KitKat (it works on KitKat, problem is 7.0 and newer) and use WeakReference on newer Android versions. 我当前的解决方案是检查生成版本并将json传递给KitKat上的捆绑包(它适用于KitKat,问题是7.0及更高版本),并在较新的Android版本上使用WeakReference。

But I'm actually not happy with this. 但是我对此并不满意。

[edit] So my last try is to get events collection from parent activity. [edit]所以我最后的尝试是从父活动中获取事件集合。 In main activity, I have following code (one app drawer menu click): 在主要活动中,我有以下代码(单击一个应用程序抽屉菜单):

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 is private field, I have simply created getter: eventsToDraw是私有字段,我只是创建了getter:

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

Then, inside my map fragment: 然后,在我的地图片段内:

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

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

  //Draw on map stuff etc
 }

The problem is that I'm always getting mEventList null. 问题是我总是使mEventList null。 After some debugging, I noticed, that getEventsToDraw() is called to early, so it won't return my collection, it returns null, because there are no data available yet. 经过一些调试后,我注意到getEventsToDraw()被提早调用,因此它不会返回我的集合,它会返回null,因为尚无可用数据。

it works on KitKat 它适用于奇巧

No, it does not. 不,不是的。 The 1MB IPC transaction limit has existed for many years. 1MB IPC交易限制已存在多年。 However, that limit is for all simultaneous IPC transactions for your process, and so failures will be probabilistic. 但是,该限制适用于您的流程中所有同时进行的IPC事务,因此失败将很可能发生。 For example, 592196 is less than 1MB, so what crashed for you may actually make it through OK sometimes, because there happens to be little else going on with IPC at that moment in time. 例如,592196小于1MB,因此有时您崩溃的情况实际上可以通过OK进行,因为当时IPC几乎没有其他活动。

So I have newInstance static method 所以我有newInstance静态方法

Don't pass a collection of events. 不要传递事件集合。 Pass the barest minimum information necessary for the fragment to get back that collection of events. 传递该片段所需的最低限度的最少信息,以获取该事件集合。 Use a process-level POJO cache to minimize redundant I/O, but support hitting the database/network/whatever again if needed, so you handle both configuration changes (process cache is still around) and process termination (but where the user returns to your task fairly quickly, so the instance stat is still used). 使用进程级别的POJO缓存来最大程度地减少冗余I / O,但如果需要,还支持再次访问数据库/网络/其他内容,因此您既可以处理配置更改(进程缓存仍在附近)又可以处理进程终止(但用户可以返回到您的任务相当快,因此仍然使用实例状态)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 从 Fragment 移动到 Activity 导致 android.os.TransactionTooLargeException - Move from Fragment to Activity Causes android.os.TransactionTooLargeException android.os.TransactionTooLargeException:数据包大小NOUGAT错误 - android.os.TransactionTooLargeException: data parcel size NOUGAT ERROR android.os.TransactionTooLargeException检索已安装的应用程序 - android.os.TransactionTooLargeException retrieving installed applications 执行queryIntentActivities时android.os.TransactionTooLargeException - android.os.TransactionTooLargeException when executing queryIntentActivities BottomNavigationView 在每次点击选项卡时创建新片段(android.os.TransactionTooLargeException) - BottomNavigationView creates new fragment with every click on tab (android.os.TransactionTooLargeException) 由于java.lang.RuntimeException而在图库中崩溃:android.os.TransactionTooLargeException:数据包大小539544字节 - Crash in gallery due to java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 539544 bytes android.app.DialogFragment.onStart上的android.os.TransactionTooLargeException - android.os.TransactionTooLargeException at android.app.DialogFragment.onStart 在AsyncTask中使用Gson编写/读取JSON时发生android.os.TransactionTooLargeException - android.os.TransactionTooLargeException occurs when Writing/Reading JSON with Gson in AsyncTask Android片段实例化:newInstance() - Android Fragment instantiation: newInstance() Android:Firebase花费了太多时间来获取数据 - Android: Firebase taking too much time to fetch data
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM