TransactionTooLargeException in Nougat
Asked Answered
D

4

6

Exception

 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) 

Fragment 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);

        }

    });

In DetailActivity,

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

DetailActivity Manifest,

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

Image Loading Using Picasso,

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

Model 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;
}

}

Data flow from TabActivity to 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.

Solutions I tried

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.,

Note:- App Crash only in NOUGAT

Finally, The fix I implemented

changing the targetSdkVersion to 23 from 25

After changing, my application not crashing in Nougat too.

All I have to Know is this proper solution or is there any workaround.

Please Guide to the proper way.

Thanks in advance.

Fragment

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 Layout

<?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>

ListView

<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>
Davilman answered 12/5, 2017 at 11:54 Comment(21)
Is it the full stacktrace ? I remember having this exception in a project, and the top stacktrace said "too large transaction" but when scrolling down, it was in fact caused by a stackOverflowException, because of a recursive call I accidentally madeJamey
Yes this is my full stacktraceDavilman
Can you post your onSaveInstanceState() implementations?Reading
@Reading sorry I don't have any onSavedState() implementations.Davilman
Can u post the DetailActivity declaration in AndroidManifest.xml ? Btw, You should have use Parcelable instead of Serializable. I think switching to Parcelable will solve the problemSynchronism
@TinTran I have updated the questionDavilman
how do u load the image in the DetailActivity ?Synchronism
@TinTran I use PicassoDavilman
Is the image url from the intent ?Synchronism
I get from model classDavilman
@TinTran Check question with Picasso loading image from modelDavilman
Let us continue this discussion in chat.Synchronism
It looks like this is happening when the Fragment in TabActivity is trying to save its state. Its state is 640KB which is too large. Can you post the relevant code from the Fragment? Also your layout files. This problem has nothing to do with "Serializable vs. Parcelable" and it has nothing to do with the ProdModel in the Bundle.Turne
@DavidWasser I'll Update data you asked now. Please Let me know when you check it.Davilman
You've not posted enough code from the Fragment. The problem is not in DetailActivity, the problem is in the Fragment in TabActivity.Turne
@DavidWasser Please Check NowDavilman
What is private ArrayList<Root_SubCatModel> subCatList;? You are calling setArguments() with a Bundle that contains this data for the Fragment. All data that you pass to setArguments() is saved automatically so that it persists across Fragment destruction and creation. I'm guessing that is where your problem is. Instead of doing this you could keep this data in the Activity and the Fragment could get the data from the Activity when it needs it.Turne
@DavidWasser I'll Check and Let you KnowDavilman
@DavidWasser I'm Sending Data coz it's a Viewpager fragment....so that data will be loaded based on catId of specific pageDavilman
@DavidWasser Thanks a lotDavilman
Possible duplicate of What to do on TransactionTooLargeExceptionGaullism
T
24

Your are passing too much data to your Fragment in setArguments(). Your Fragment will work, but when it tries to save its instance state it overflows the transaction buffer. This throws a RuntimeException if you target Android 7.0 (API 24 or higher). To preserve backwards compatibility and not break existing apps, the new behaviour is only used if you target API 24 or higher. If you target API < 24, the transaction buffer overflow exception is caught and silently ignored. This means that your data will not be persistently saved, which you may (or may not) notice.

Your code is broken. You should not pass large amounts of data to the Fragment in setArguments(). You can keep your data in your Activity. When the Fragment wants to access the data, it can always so something like this:

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

In your Activity, write a getData() method that returns a reference to whatever data the Fragment needs.

In this way, the data is held in the Activity and the Fragment can get access to it whenever it needs to.

Turne answered 8/6, 2017 at 14:23 Comment(5)
Thanks David. You save my time.Decarbonate
Instead cannot we directly access variables and methods using MyActivity.variable and MyActivity.anything() without MyActivity activity = (MyActivity)getActivity();?Reisch
@Reisch You could only do that if the variables and methods were defined as static. This is possible, but violates basic principles of object-oriented design and is not generally recommended.Turne
Beside violating the principles, how about performance issue?Reisch
@Reisch The performance difference is near zero. You probably couldn't measure it and you certainly wouldn't notice it.Turne
N
7

Android 7.0 (Nogat) includes a variety of system and API behaviour changes. Regarding TransactionTooLarge Exception :

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.

Possible Solutions : 1. Save required object in global cache and pass only the key to DetailsActivity to retrieve the object.

Nolannolana answered 5/6, 2017 at 6:20 Comment(3)
I think your solution is not best practice. we should just save the object in some database/file and pass a key to the new Activity to retrieve it later.Synchronism
Save it in DB/File only if you need it again, after app launch or app gets killed. If its only required for showing details on click of some button, save it in memory, and clear it when app goes to background.Nolannolana
I am getting this exception - android.os.TransactionTooLargeException: data parcel size 1100920 bytes My code is about to insert the contact - ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(); ContentProviderResult[] res = context.getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); How to solve itRegenaregency
K
2

Regarding the Doc This Exception throw when value are too large to fit in the transaction buffer. And might be a complicated issue, for a big project, where you can invokes several actions with sending Intent in difference places.

Your example demonstrate this issue, even with single object. And you should change your transferring behavior at all. For ex. by trimming object, to contain only important info. Intent Extra Data should have only lightweight info!


In you example you have field, which might produce this issue. Probably you are using Base64 Encoded image. Exception with message text, specific only for Android 23. Check the doc.

public String getImage() {
    return image;
}

public void setImage(String image) {
    this.image = image;
}
Karlene answered 1/6, 2017 at 13:14 Comment(0)
B
2

Read this article http://nemanjakovacevic.net/blog/english/2015/03/24/yet-another-post-on-serializable-vs-parcelable/ should help you.

My solution:

  1. Save your objects in some storage (SharedPreferences, raw JSON, SQLLite or Realm database etc.)

  2. Put to your bundle only object 'id' (simple type: int long etc.)

  3. Get 'id' from intent and find it in your storage, then retrieve the object.
Bautram answered 6/6, 2017 at 12:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.