牛轧糖中的 TransactionTooLargeException

TransactionTooLargeException in Nougat

异常

 05-12 15:42:45.791 11043-11043/ E/UncaughtException: java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 631792 bytes
                                                                       at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3776)
                                                                       at android.os.Handler.handleCallback(Handler.java:751)
                                                                       at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                       at android.os.Looper.loop(Looper.java:154)
                                                                       at android.app.ActivityThread.main(ActivityThread.java:6123)
                                                                       at java.lang.reflect.Method.invoke(Native Method)
                                                                       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
                                                                       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)
                                                                    Caused by: android.os.TransactionTooLargeException: data parcel size 631792 bytes
                                                                       at android.os.BinderProxy.transactNative(Native Method)
                                                                       at android.os.BinderProxy.transact(Binder.java:615)
                                                                       at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:3700)
                                                                       at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3768)
                                                                       at android.os.Handler.handleCallback(Handler.java:751) 
                                                                       at android.os.Handler.dispatchMessage(Handler.java:95) 
                                                                       at android.os.Looper.loop(Looper.java:154) 
                                                                       at android.app.ActivityThread.main(ActivityThread.java:6123) 
                                                                       at java.lang.reflect.Method.invoke(Native Method) 
                                                                       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867) 
                                                                       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757) 
05-12 15:42:47.247 11043-11043/ E/AndroidRuntime: FATAL EXCEPTION: main
                                                                Process: , PID: 11043
                                                                java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 631792 bytes
                                                                    at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3776)
                                                                    at android.os.Handler.handleCallback(Handler.java:751)
                                                                    at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                    at android.os.Looper.loop(Looper.java:154)
                                                                    at android.app.ActivityThread.main(ActivityThread.java:6123)
                                                                    at java.lang.reflect.Method.invoke(Native Method)
                                                                    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
                                                                    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)
                                                                 Caused by: android.os.TransactionTooLargeException: data parcel size 631792 bytes
                                                                    at android.os.BinderProxy.transactNative(Native Method)
                                                                    at android.os.BinderProxy.transact(Binder.java:615)
                                                                    at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:3700)
                                                                    at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3768)
                                                                    at android.os.Handler.handleCallback(Handler.java:751) 
                                                                    at android.os.Handler.dispatchMessage(Handler.java:95) 
                                                                    at android.os.Looper.loop(Looper.java:154) 
                                                                    at android.app.ActivityThread.main(ActivityThread.java:6123) 
                                                                    at java.lang.reflect.Method.invoke(Native Method) 
                                                                    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867) 
                                                                    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757) 

片段 OnItemClick:-

 listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position,
                                long id) {

            Bundle bundle = new Bundle();
            ProdModel mProdModel = prodList.get(position);
            bundle.putSerializable("object", mProdModel);
            Intent intent = new Intent(getActivity(), DetailActivity.class);
            intent.putExtra("bundle", bundle);
            startActivityForResult(intent, 1);

        }

    });

在DetailActivity中,

Bundle bundle = getIntent().getBundleExtra("bundle");
    if (bundle != null) {
        ProdModel model = (ProdModel) bundle.getSerializable("object");
    }

DetailActivity 清单,

  <activity
        android:name="com.mass.mysample.DetailActivity"
        android:screenOrientation="portrait" />

使用 Picasso 加载图像,

 Picasso.with(this).load(model.getImage())
             .placeholder(R.drawable.logo_without)
             .fit().into(productimage);

型号Class

public class ProdModel implements Serializable {
private String seller_id;
String name;
private String image;
private float price;
private float specialprice;
private String entity_id;
private String productNumQuantity;
private String storetitle;
private String description;
private String discount;
private String max_price;
private String store_name;
private String StoreUrl;

public String getProductNumQuantity() {
    return productNumQuantity;
}

public void setProductNumQuantity(String productNumQuantity) {
    this.productNumQuantity = productNumQuantity;
}

public String getDiscount() {
    return discount;
}

public void setDiscount(String discount) {
    this.discount = discount;
}

public String getMax_price() {
    return max_price;
}

public void setMax_price(String max_price) {
    this.max_price = max_price;
}

public String getStore_name() {
    return store_name;
}

public void setStore_name(String store_name) {
    this.store_name = store_name;
}

public String getStoreUrl() {
    return StoreUrl;
}

public void setStoreUrl(String storeUrl) {
    StoreUrl = storeUrl;
}

public String getStoretitle() {
    return storetitle;
}

public void setStoretitle(String storetitle) {
    this.storetitle = storetitle;
}

public String getSeller_id() {
    return seller_id;
}

public void setSeller_id(String seller_id) {
    this.seller_id = seller_id;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public String getImage() {
    return image;
}

public void setImage(String image) {
    this.image = image;
}

public String getEntity_id() {
    return entity_id;
}

public void setEntity_id(String entity_id) {
    this.entity_id = entity_id;
}

public String getDescription() {
    return description;
}

public void setDescription(String description) {
    this.description = description;
}

public float getPrice() {
    return price;
}

public void setPrice(float price) {
    this.price = price;
}

public float getSpecialPrice() {
    return specialprice;
}

public void setSpecialPrice(float specialprice) {
    this.specialprice = specialprice;
}

}

数据从TabActivity流向fragment,

1.I have a TabActivity with ViewPager and Fragment. 
2.In Fragment, I have a ListView.
3.The Data to fragment is passed from view pager adapter by set arguments.

我尝试过的解决方案

1.A POJO class that implements Serialization. 
2.I use Picasso to load the image from image URL. 
3.This exception is thrown when OnItemClick on ListView in fragment passes data to DetailActivity to show all passed data.
4.I get this exception after the DetailActivity load's image and other data then app suddenly crashes.
5.I pass data in Intent was all POJO Object with Id, Name, Image URL, Price etc.,

注:- 应用仅在 NOUGAT

中崩溃

最后,我实施的修复

将 targetSdkVersion 从 25 更改为 23

更改后,我的应用程序在 Nougat 中也没有崩溃。

我只需要知道这个正确的解决方案或是否有任何解决方法。

请指导正确的方法。

提前致谢。

片段

public class ProdFragment extends Fragment {
ListView listview;
SharedPreferences spref;
Boolean isInternetPresent = false;
ConnectionDetector cd;

private String toBeDisplayed,CatID;
private static final String TAG = ProdFragment.class.getSimpleName();
String totalProductCart;
private ArrayList<Root_SubCatModel> subCatList;
private ArrayList<ProdModel> prodList;
ProdAdapter adapter;

public ProdFragment() {
    // Required empty public constructor
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    spref = getActivity().getSharedPreferences(getResources().getString(R.string.myPref),
            Context.MODE_PRIVATE);
    Bundle bundle = getArguments();
    if (bundle != null) {
        int tabPosition = bundle.getInt("Tab_Position");
        toBeDisplayed = bundle.getString("Tab_ToBeDisplayed");
        CatID = bundle.getString("CategoryId");
        subCatList = (ArrayList<Root_SubCatModel>) bundle.getSerializable("Tab_Data");
    }
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    final View rootView = inflater.inflate(R.layout.prod_listview, container, false);

    cd = new ConnectionDetector(getActivity());
    listview = (ListView) rootView.findViewById(R.id.prodlist);
    if (subCatList != null) {
        adapter = new ProdAdapter(getActivity(),
                CatID,
                toBeDisplayed,
                R.layout.list_product,
                subCatList,
                (ProductCartCountListener)getActivity());
        listview.setAdapter(adapter);
        adapter.notifyDataSetChanged();

        prodList = new ArrayList<>();
        for(int i = 0; i<subCatList.size();i++){
            if (subCatList.get(i).getProd() != null) {
                if(toBeDisplayed.equals("SubCategory")){
                    if (CatID.equals(subCatList.get(i).getCategory_id())) {
                        this.prodList = subCatList.get(i).getProd();
                    }
                }else if(toBeDisplayed.equals("Products")) {
                    this.prodList = subCatList.get(i).getProd();
                }
            }
        }

    }

    listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position,
                                long id) {

            Bundle bundle = new Bundle();
            bundle.putSerializable("object", prodList.get(position));
            Intent intent = new Intent(getActivity(), DetailActivity.class);
            intent.putExtra("bundle", bundle);
            startActivityForResult(intent,1);
        }

    });

    return rootView;
}

public void showAlertDialog(Context context, String title, String message, Boolean status) {
    AlertDialog alertDialog = new AlertDialog.Builder(context).create();

    // Setting Dialog Title
    alertDialog.setTitle(title);

    // Setting Dialog Message
    alertDialog.setMessage(message);

    // Setting alert dialog icon
    //alertDialog.setIcon((status) ? R.drawable.success : R.drawable.fail);

    // Setting OK Button
    alertDialog.setButton("OK", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int which) {
        }
    });

    // Showing Alert Message
    alertDialog.show();
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == 1) {
        if (resultCode == Activity.RESULT_OK) {
            Bundle b = data.getExtras();
            if (b != null) {
                ProdModel myobj = (ProdModel) b.getSerializable("Cart_Quantity");
                if (myobj != null) {
                    if (prodList != null) {
                        for (ProdModel P : prodList) {
                            if (P.getEntity_id().equals(myobj.getEntity_id())) {
                                P.setProductNumQuantity(myobj.getProductNumQuantity());
                            }
                        }
                    }
                    Log.d(TAG,"Product_Id : " + myobj.getEntity_id()
                            + ", Product_Cart_Count : " + myobj.getProductNumQuantity());
                }
            }
        } else if (resultCode == 0) {
            Log.d(TAG,"RESULT CANCELLED");
        }
    }
    adapter.notifyDataSetChanged();
    String totalProductCart = spref.getString("Cart_Count_Tool", "0");
    Activity activity = getActivity();
    if(activity instanceof TabActivity){
        TabActivity myActivity = (TabActivity) activity;
        Toolbar toolbar = (Toolbar) myActivity.findViewById(R.id.back_toolbar);
        ImageView cart_imageview = (ImageView) toolbar.findViewById(R.id.cart_imageview);
        cart_imageview.setImageDrawable(myActivity.buildCounterDrawable(
                Integer.parseInt(totalProductCart)));
    }
    Log.d(TAG,"RESULT NOTIFIED");
}

public void refreshData(String productId, boolean isAddAsyncTaskComplete,
                        boolean isAddAsyncTaskLimitReached, boolean isDeleteAsyncTaskComplete){
    adapter.setQuantityCount(prodList, productId, isAddAsyncTaskComplete,
            isAddAsyncTaskLimitReached, isDeleteAsyncTaskComplete);

}

TabActivity 布局

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

<android.support.design.widget.AppBarLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <android.support.design.widget.TabLayout
        android:id="@+id/tabs"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/storeimage"
        android:textAlignment="center"
        android:elevation="2dp"
        android:minHeight="?attr/actionBarSize"
        app:tabMode="scrollable"
        app:tabTextColor="@color/color_dark_blue"
        app:tabSelectedTextColor="@color/color_orange"/>
</android.support.design.widget.AppBarLayout>

<android.support.v4.view.ViewPager
    android:id="@+id/viewpager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior" />
 </android.support.design.widget.CoordinatorLayout>

列表视图

<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<ListView
    android:id="@+id/prodlist"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

</FrameLayout>

关于文档 This Exception 当值太大而无法放入事务缓冲区时抛出。对于一个大项目来说,这可能是一个复杂的问题,您可以在不同的地方通过发送 Intent 来调用多个动作。

你的例子证明了这个问题,即使是单个对象。你应该完全改变你的转移行为。对于前。通过修剪对象,只包含重要信息。 意图额外数据应该只有轻量级信息!


在您的示例中,您有可能会产生此问题的字段。可能您正在使用 Base64 编码图像。消息文本异常,仅特定于 Android 23. 检查文档。

public String getImage() {
    return image;
}

public void setImage(String image) {
    this.image = image;
}

Android 7.0 (Nogat) 包括各种系统和 API 行为更改。 关于 TransactionTooLarge 异常:

In Android 7.0, many platform APIs have now started checking for large payloads being sent across Binder transactions, and the system now rethrows TransactionTooLargeExceptions as RuntimeExceptions, instead of silently logging or suppressing them. One common example is storing too much data in Activity.onSaveInstanceState(), which causes ActivityThread.StopInfo to throw a RuntimeException when your app targets Android 7.0.

可能的解决方案: 1. 将需要的对象保存在全局缓存中,只传递key给DetailsActivity获取对象。

阅读这篇文章 http://nemanjakovacevic.net/blog/english/2015/03/24/yet-another-post-on-serializable-vs-parcelable/ 应该对您有所帮助。

我的解决方案:

  1. 将您的对象保存在一些存储中(SharedPreferences、原始 JSON、SQLLite 或 Realm 数据库等)

  2. 仅将对象放入您的包中 'id'(简单类型:int long 等)

  3. 从 Intent 中获取 'id' 并在您的存储中找到它,然后检索该对象。

您向 setArguments() 中的 Fragment 传递了太多数据。您的 Fragment 可以工作,但是当它尝试保存其实例状态时,它会溢出事务缓冲区。如果您的目标是 Android 7.0(API 24 或更高),则会抛出 RuntimeException 。为保持向后兼容性且不破坏现有应用程序,仅当您以 API 24 或更高为目标时才使用新行为。如果您的目标 API < 24,事务缓冲区溢出异常将被捕获并被忽略。这意味着您的数据不会被永久保存,您可能会(或可能不会)注意到这一点。

您的代码已损坏。您不应将大量数据传递给 setArguments() 中的 Fragment。您可以将数据保存在 Activity 中。当 Fragment 想要访问数据时,它总是可以这样:

// Get the owning Activity
MyActivity activity = (MyActivity)getActivity();
// Get the data from the Activity
List<Data> data = activity.getData();

在您的 Activity 中,编写一个 getData() 方法,该方法 returns 引用 Fragment 需要的任何数据。

这样,数据保存在 Activity 中,Fragment 可以随时访问它。