TransactionTooLargeException when trying to send b

2019-03-03 13:24发布

问题:

I need to send binary content from my app to whatever app opens that file type in the device.

I'm following these instructions: https://developer.android.com/training/sharing/send.html#send-binary-content

Here's my code:

final FileType fileType
final File file;

final Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);

intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

intent.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(AncestryApplication.getAppContext(), AncestryApplication.getAppContext().getApplicationContext().getPackageName() + ".provider", file));

intent.setType(fileType.getMimeType());
startActivity(intent);

A few things:

  1. If I change the intent action from ACTION_VIEW to ACTION_SEND, I get the wrong possible list of apps to open my file
  2. ACTION_SEND seems to work, but only with small file sizes
  3. intent.setDataAndType() seems to work fine on devices OS M and lower. On N I get the same TransactionTooLargeException

At the end, this is what I need to accomplish:

  • I already have a file saved, and it is stored at file:///storage/emulated/0/Download/TempFile.html
  • Since the file may be too large, I need to send just the location of the file to a third party app (like adobe pdf reader) to open the file
  • No issues on M or lower, tons of issues on N

Any ideas on what I may be doing wrong? I've been trying to solve this for a few days and I've read a ton of tutorials and SO suggestions, without any final answer.

Thanks.

EDIT: here's my stacktrace:

AndroidRuntime: FATAL EXCEPTION: main
Process: com.myapp.android.apps.myapp, PID: 26785
java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 27943540 bytes
  at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3752)
  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:6077)
  at java.lang.reflect.Method.invoke(Native Method)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)

Caused by: android.os.TransactionTooLargeException: data parcel size 27943540 bytes
  at android.os.BinderProxy.transactNative(Native Method)
  at android.os.BinderProxy.transact(Binder.java:615)
  at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:3606)
  at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3744)
  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:6077) 
  at java.lang.reflect.Method.invoke(Native Method) 
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865) 
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)

EDIT 2: Added onSaveInstanceState() code from base fragment:

@Override
public void onSaveInstanceState(final Bundle outState) {
    mSaveInstanceStateCalled = true;
    outState.putBoolean(KEY_PROCESSING_SAVE, mSaveInProgress);
}

回答1:

The exception in the logcat you posted is caused by packing too much data into the Bundle processed by onSaveInstanceState.

Here is the method from the Android source where it is thrown, if the build version is N or greater:

private static class StopInfo implements Runnable {
    ActivityClientRecord activity;
    Bundle state;
    PersistableBundle persistentState;
    CharSequence description;
    @Override public void run() {
        // Tell activity manager we have been stopped.
        try {
            if (DEBUG_MEMORY_TRIM) Slog.v(TAG, "Reporting activity stopped: " + activity);
            ActivityManagerNative.getDefault().activityStopped(
                activity.token, state, persistentState, description);
        } catch (RemoteException ex) {
            if (ex instanceof TransactionTooLargeException
                    && activity.packageInfo.getTargetSdkVersion() < Build.VERSION_CODES.N) {
                Log.e(TAG, "App sent too much data in instance state, so it was ignored", ex);
                return;
            }
            throw ex.rethrowFromSystemServer(); // <<-- exception thrown here
        }
    }
}

I am posting this in the form of an answer because it's too long for a comment. It is not meant as a complete answer to the question, because there is not enough information in the question to answer it.