精华内容
下载资源
问答
  • 主要给大家介绍了关于Android Intent传递数据大小限制的相关资料,文中通过示例代码介绍的非常详细,对各位Android开发者们具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
  • Intent传递数据

    2015-06-24 15:41:39
    这是介绍了Intent怎样传递数据,传递什么类型的数据,和startactivityforResult,setResult,onactivityResult的用法,请参考:http://blog.csdn.net/forwardyzk/article/details/46620021
  • Intent传递数据并跳转页面 4.9作业登陆app 要求: 1、实现Intent调整和传递数据的功能。 2、在MainAcitvity界面输入账号和密码信息,传递到DetailActivity界面显示。 步骤: 1、新建DetialActivity.java ...
  • intent传递数据的方法

    2014-09-23 10:44:30
    intent数据从一个activity传递到另一个activity,intent如何从发送数据给另一个activity并接受传回来的值
  • 主要介绍了Android Intent传递数据底层分析详细介绍的相关资料,需要的朋友可以参考下
  • Android Studio 3.0 下使用Intent传递数据和数据回传的示例。实现了一个简单的登录界面,用户输入用户名和密码后,点击登录把用户名和密码传递到主界面,主界面显示用户名和密码,然后在主界面中购买一个物品,打开...
  • Intent传递数据的方法

    2020-08-06 16:25:30
    Intent传递数据的方法传递的数据是基本类型的传递的数据是对象 使用intent的putExtra()方法,可以将要传递的数据附加到Intent对象,然后使用Intent对象进行数据传递。Intent中重载了很多putExtra()方法,可以附加的...

    使用intent的putExtra()方法,可以将要传递的数据附加到Intent对象,然后使用Intent对象进行数据传递。Intent中重载了很多putExtra()方法,可以附加的数据类型有:所有基本类型以及Serializable、Parcelable等类型的数据。

    一、传递的数据是基本类型的

    使用putExtra()方法将数据一条一条的附加到Intent对象中
    MainActivity.java代码块:

    Intent intent = new Intent(MainActivity.this, OtherAcitivity.class);
    String name = "Jack";
    int age = 18;
    char sex = 'w';
    intent.putExtra("myName",name);
    intent.putExtra("myAge",age);
    intent.putExtra("mySex",sex);
    startActivity(intent);
    

    OtherActivity.java代码块:

    Intent intent = getIntent();
    String name = intent.getStringExtra("myName");
    int age = intent.getIntExtra("myAge",0);
    char sex = intent.getCharExtra("mySex",'w');
    
    System.out.println(name);
    System.out.println(age);
    System.out.println(sex);
    

    二、传递的数据是对象

    Android开发中,是不能将对象的引用直接传给Activities或者Fragments,需要先对象中的数据序列化转换成可以传输的二进制流后才能进行传输。这里使用Parcelable接口完成对象的序列化为例。
    首先是Person.java的代码,Person实例化的对象就是我们要传递的数据。将Person实现Parcelable接口,重写writeToParcel()、describeContents()方法。

    package cn.edu.jssvc.importexternmodule;
    import android.os.Parcel;
    import android.os.Parcelable;
    public class Person implements Parcelable {
        private String name;
        private int age;
        private char sex;
    
        public Person(String name, int age, char sex) {
            this.name = name;
            this.age = age;
            this.sex = sex;
        }
    
        protected Person(Parcel in) {
            name = in.readString();
            age = in.readInt();
            sex = (char) in.readInt();
        }
    
        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeString(name);
            dest.writeInt(age);
            dest.writeInt((int) sex);
        }
    
        @Override
        public int describeContents() {
            return 0;
        }
    
        public static final Creator<Person> CREATOR = new Creator<Person>() {
            @Override
            public Person createFromParcel(Parcel in) {
                return new Person(in);
            }
    
            @Override
            public Person[] newArray(int size) {
                return new Person[size];
            }
        };
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public char getSex() {
            return sex;
        }
    
        public void setSex(char sex) {
            this.sex = sex;
        }
    }
    
    

    MainActivity.java代码块

    Intent intent = new Intent(MainActivity.this, OtherAcitivity.class);
    Person person = new Person("Bron",25, 'w');
    Bundle bundle = new Bundle();
    bundle.putParcelable("bundle",person);
    intent.putExtra("intent",bundle);
    startActivity(intent);
    

    OtherActivity.java代码块

    Intent intent = getIntent();
    Bundle bundle = intent.getBundleExtra("intent");
    Person person = bundle.getParcelable("bundle");
    System.out.println(person.getName());
    System.out.println(person.getAge());
    System.out.println(person.getSex());
    
    展开全文
  • 我们知道可以通过 Intent 和 bundle 在 activity 或 fragment ...Activity间通过Intent传递数据的大小限制 – 具体数据博客 传 512K 以下的数据的数据可以正常传递。 传 512K~1024K 的数据会出错,闪退。 传 1024K ...

    我们知道可以通过 Intentbundleactivityfragment 间进行通信,但是 Intent 传递数据时,如果数据太大,可能会出现异常。

    1. Intent 传递不同大小数据时的问题

    • 512K 以下的数据的数据可以正常传递。
    • 512K~1024K 的数据会出错,闪退。
    • 1024K 以上的数据会报错:TransactionTooLargeException
    • 考虑到 Intent 还包括要启动的 Activity 等信息,实际可以传的数据略小于 512K

    2. 问题分析

    2.1 intent 传递数据测试

    val intent = Intent(this, MainActivity2::class.java).apply {
    	val data2 = ByteArray(1024 * 1024)
        putExtra("111", data2)
    }
    startActivity(intent)
    

    error:

    Caused by: android.os.TransactionTooLargeException: data parcel size 1049012 bytes
       at android.os.BinderProxy.transactNative(Native Method)
       at android.os.BinderProxy.transact(BinderProxy.java:511)
       at android.app.IActivityTaskManager$Stub$Proxy.startActivity(IActivityTaskManager.java:3969)
       at android.app.Instrumentation.execStartActivity(Instrumentation.java:1716)
       at android.app.Activity.startActivityForResult(Activity.java:5260) 
       at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:675) 
       at android.app.Activity.startActivityForResult(Activity.java:5218) 
       at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:662) 
       at android.app.Activity.startActivity(Activity.java:5589) 
       at android.app.Activity.startActivity(Activity.java:5557) 
    

    2.2 从 crash log 角度分析

    Intent 中传入一个 Parcelable 对象, 例如传入一个 bitmap 对象。Bitmap 实现了 Parcelable 接口,并且可以通过 getByteCount() 得知所占内存大小。测试时候报出如下信息

     V/ActivityManager: Broadcast: Intent { act=intent_bi flg=0x10 (has extras) } ordered=false userid=0 callerApp=ProcessRecord{27aeaaf5 31217:com.rustfisher.basic4/u0a113}
     E/JavaBinder: !!! FAILED BINDER TRANSACTION !!!
     W/BroadcastQueue: Failure sending broadcast Intent { act=intent_bi flg=0x10 (has extras) }
            android.os.TransactionTooLargeException
                at android.os.BinderProxy.transactNative(Native Method)
                at android.os.BinderProxy.transact(Binder.java:504)
                at android.app.ApplicationThreadProxy.scheduleRegisteredReceiver(ApplicationThreadNative.java:1170)
                at com.android.server.am.BroadcastQueue.performReceiveLocked(BroadcastQueue.java:576)
                at com.android.server.am.BroadcastQueue.deliverToRegisteredReceiverLocked(BroadcastQueue.java:848)
                at com.android.server.am.BroadcastQueue.processNextBroadcast(BroadcastQueue.java:917)
                at com.android.server.am.BroadcastQueue$BroadcastHandler.handleMessage(BroadcastQueue.java:254)
                at android.os.Handler.dispatchMessage(Handler.java:111)
                at android.os.Looper.loop(Looper.java:194)
                at android.os.HandlerThread.run(HandlerThread.java:61)
                at com.android.server.ServiceThread.run(ServiceThread.java:46)
    

    查看异常类 TransactionTooLargeException,它继承了 RemoteExceptio:

    package android.os;
    public class TransactionTooLargeException extends RemoteException {
        public TransactionTooLargeException() {
            super();
        }
    
        public TransactionTooLargeException(String msg) {
            super(msg);
        }
    }
    

    追踪到 Binder,它的 transactNative 方法会报出 RemoteException:

    public native boolean transactNative(int code, Parcel data, Parcel reply,
                int flags) throws RemoteException;
    

    由此可以看出,抛出异常与 Binder 有关。

    2.3 startActivity 流程探究

    首先, ContextActivity 都含有 startActivity, 但两者最终都调用了 Activity 中的 startActivity:

        @Override
        public void startActivity(Intent intent, @Nullable Bundle options) {
            if (options != null) {
                startActivityForResult(intent, -1, options);
            } else {
                // Note we want to go through this call for compatibility with
                // applications that may have overridden the method.
                startActivityForResult(intent, -1);
            }
        }
    

    startActivity 最终会调用自身的 startActivityForResult,省略了嵌套 activity 的代码:

    public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
                @Nullable Bundle options) {
            if (mParent == null) {
                options = transferSpringboardActivityOptions(options);
                Instrumentation.ActivityResult ar =
                    mInstrumentation.execStartActivity(
                        this, mMainThread.getApplicationThread(), mToken, this,
                        intent, requestCode, options);
                if (ar != null) {
                    mMainThread.sendActivityResult(
                        mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                        ar.getResultData());
                }
                if (requestCode >= 0) {
                    // If this start is requesting a result, we can avoid making
                    // the activity visible until the result is received.  Setting
                    // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
                    // activity hidden during this time, to avoid flickering.
                    // This can only be done when a result is requested because
                    // that guarantees we will get information back when the
                    // activity is finished, no matter what happens to it.
                    mStartedActivity = true;
                }
    
                cancelInputsAndStartExitTransition(options);
                // TODO Consider clearing/flushing other event sources and events for child windows.
            } else {
                if (options != null) {
                    mParent.startActivityFromChild(this, intent, requestCode, options);
                } else {
                    // Note we want to go through this method for compatibility with
                    // existing applications that may have overridden it.
                    mParent.startActivityFromChild(this, intent, requestCode);
                }
            }
        }
    

    然后系统会调用 Instrumentation 中的 execStartActivity 方法:

    public ActivityResult execStartActivity(
                Context who, IBinder contextThread, IBinder token, Activity target,
                Intent intent, int requestCode, Bundle options) {
            IApplicationThread whoThread = (IApplicationThread) contextThread;
            ......
            try {
                intent.migrateExtraStreamToClipData(who);
                intent.prepareToLeaveProcess(who);
                int result = ActivityTaskManager.getService().startActivity(whoThread,
                        who.getBasePackageName(), who.getAttributionTag(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()), token,
                        target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);
                checkStartActivityResult(result, intent);
            } catch (RemoteException e) {
                throw new RuntimeException("Failure from system", e);
            }
            return null;
        }
    

    接着调用了 ActivityManger.getService().startActivity, getService 返回的是系统进程中的 AMSapp 进程中的 binder 代理:

    /** @hide */
    public static IActivityTaskManager getService() {
    	return IActivityTaskManagerSingleton.get();
    }
    
    private static final Singleton<IActivityManager> IActivityManagerSingleton = new Singleton<IActivityManager>() {
    	@Override
        protected IActivityManager create() {
        	final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
            final IActivityManager am = IActivityManager.Stub.asInterface(b);
            return am;
        }
    };
    

    接下来就是 App 进程调用 AMS 进程中的方法了。简单来说,系统进程中的 AMS 集中负责管理所有进程中的 Activity

    App 进程与系统进程需要进行双向通信。比如打开一个新的 Activity,则需要调用系统进程 AMS中的方法进行实现,AMS 等实现完毕需要回调app进程中的相关方法进行具体 activity生命周期的回调。

    所以我们在 intent 中携带的数据也要从 APP 进程传输到 AMS 进程,再由 AMS 进程传输到目标Activity 所在进程。

    有同学可能由疑问了,目标 Acitivity 所在进程不就是 APP 进程吗?其实不是的,我们可以在 Manifest.xml 中设置 android:process 属性来为 Activity, Service 等指定单独的进程,所以 ActivitystartActivity 方法是原生支持跨进程通信的

    3. Binder 传输数据的 大小限制

    在这里插入图片描述
    普通的由 Zygote 孵化而来的用户进程,所映射的Binder内存大小是不到1M的,准确说是

    #define BINDER_VM_SIZE ((1*1024*1024) - (4096 *2))
    

    这个限制定义在 frameworks/native/+/4d2f4bb/libs/binder/ProcessState.cpp类中,如果传输数据超过这个大小,系统就会报错,因为Binder本身就是为了进程间频繁而灵活的通信所设计的,并不是为了拷贝大数据而使用的.

    其实在 TransactionTooLargeException 中也提到了这个

    The Binder transaction buffer has a limited fixed size, currently 1Mb, which
    is shared by all transactions in progress for the process.  Consequently this
    exception can be thrown when there are many transactions in progress even when
    most of the individual transactions are of moderate size.
    

    4. intent 传递数据大小限制问题的小结

    4.1 一句话概括这个问题

    startActivity携带的数据会经过 Binder内核再传递到目标Activity中去,因为binder映射内存的限制,所以startActivity也就会这个限制了

    4.2 分析

    Intent 携带信息的大小其实是受 Binder 限制。本文标题也可以改为 Binder传递数据大小限制。

    数据以 Parcel 对象的形式存放在 Binder传递缓存中。如果数据或返回值比传递 buffer 大,则此次传递调用失败并抛出 TransactionTooLargeException 异常。

    Binder 传递缓存有一个限定大小,通常是 1Mb。但同一个进程中所有的传输共享缓存空间。
    多个地方在进行传输时,即时它们各自传输的数据不超出大小限制,TransactionTooLargeException异常也可能会被抛出。

    在使用 Intent 传递数据时,1Mb 并不是安全上限。因为 Binder 中可能正在处理其它的传输工作。
    不同的机型和系统版本,这个上限值也可能会不同。

    在其它地方,例如 onSaveInstanceState(@NonNull Bundle outState),也可能会遇到与 Binder 有关的类似问题。

    4. 为什么 Binder 要限制传输数据的大小

    个人推测,作为一种 IPC 的方式,Binder 并不是为传输大量数据而设计。传输大量数据,可以考虑URL 之类的方法( 只传递索引,不传递具体的数据。或者其他类似的做法)。

    5. 从 Intent 传递数据的原理分析

    通过 intentbundle 的源码可以看到它们都是实现了 Parcelable ,其实就是通过序列化来实现通信的。提到 Parcelable 就不得不提 Serializable,这里引用一段网上的总结:

    介绍Parcelable不得不先提一下Serializable接口,Serializable是Java为我们提供的一个标准化的序列化接口,那什么是序列化呢? —- 简单来说就是将对象转换为可以传输的二进制流(二进制序列)的过程,这样我们就可以通过序列化,转化为可以在网络传输或者保存到本地的流(序列),从而进行传输数据 ,那反序列化就是从二进制流(序列)转化为对象的过程.

    Parcelable 是Android为我们提供的序列化的接口, Parcelable 相对于 Serializable 的使用相对复杂一些,但 Parcelable 的效率相对 Serializable 也高很多,这一直是 Google工程师引以为傲的,有时间的可以看一下 ParcelableSerializable 的效率对比 Parcelable vs Serializable 号称快10倍的效率

    Yet another post on Serializable vs Parcelable

    Parcelable 的底层使用了 Parcel 机制。传递实际上是使用了 binder 机制,binder 机制会将 Parcel序列化的数据写入到一个共享内存中,读取时也是 binder 从共享内存中读出字节流,然后 Parcel 反序列化后使用。这就是 IntentBundle 能够在 activity或者跨进程通信的原理。

    关于 ParcelableSerializable 的区别,同样引用一段网上的总结:

    ParcelableSerializable 都是实现序列化并且都可以用于 Intent 间传递数据, SerializableJava 的实现方式,可能会频繁的 IO 操作,所以消耗比较大,但是实现方式简单 ParcelableAndroid 提供的方式, 效率比较高,但是实现起来复杂一些 , 二者的选取规则是:

    • 内存序列化上选择Parcelable
    • 存储到设备或者网络传输上选择Serializable(当然Parcelable也可以但是稍显复杂)

    当我们用Intent传输过大数据时,一般logcat会报出 TransactionTooLargeException 错误,谷歌官方对这个错误的描述如下:

    The Binder transaction failed because it was too large.
    During a remote procedure call, the arguments and the return value of the call are transferred as
    Parcel objects stored in the Binder transaction buffer. If the arguments or the return value are too
    large to fit in the transaction buffer, then the call will fail and TransactionTooLargeException
    will be thrown.
    
    The Binder transaction buffer has a limited fixed size, currently 1Mb, which is shared by all
    transactions in progress for the process. Consequently this exception can be thrown when there
    are many transactions in progress even when most of the individual transactions are of moderate size.
    
    There are two possible outcomes when a remote procedure call throws TransactionTooLargeException.
    Either the client was unable to send its request to the service (most likely if the arguments were
    too large to fit in the transaction buffer), or the service was unable to send its response back to
    the client (most likely if the return value was too large to fit in the transaction buffer). It is
    not possible to tell which of these outcomes actually occurred. The client should assume that a
    partial failure occurred.
    
    The key to avoiding TransactionTooLargeException is to keep all transactions relatively small.
    Try to minimize the amount of memory needed to create a Parcel for the arguments and the return
    value of the remote procedure call. Avoid transferring huge arrays of strings or large bitmaps.
    If possible, try to break up big requests into smaller pieces.
    
    If you are implementing a service, it may help to impose size or complexity contraints on the
    queries that clients can perform. For example, if the result set could become large, then don't
    allow the client to request more than a few records at a time. Alternately, instead of returning
    all of the available data all at once, return the essential information first and make the client
    ask for additional information later as needed.
    

    简单来说,我们上面提到了 Parcel 机制使用了一个共享内存,这个共享内存就叫 Binder transaction buffer,这块内存有一个大小限制,目前是 1MB,而且共用的,当超过了这个大小就会报错。

    也就是说不仅仅是一次性传递大数据会出问题,当同时传递很多数据,尽管每个都不超过1MB,但是总大小超过 1MB也会出错

    6. 解决方法

    Activity之间传递数据的方式及常见问题总结

    • 限制传递数据量
    • 改变数据传输方式(参见Activity之间传递数据的方式)
    • 静态static
    • 单例
    • Application
    • 持久化
    • 使用容器的单例模式

    7. 参考链接


    展开全文
  • Android学习之利用Intent传递数据

    千次阅读 2020-05-31 15:42:22
    1. 利用intent在两个activity之间传递数据 2. 利用intent在两个activity之间传递数据包 很多人在刚开始进行android开发时,想要在两个activity之间传递数据,但是却并不知道如何去操作。那么通过这篇文章,我将帮助...

    你能通过这篇文章学习到什么?

    1. 利用intent在两个activity之间传递数据
    2. 利用intent在两个activity之间传递数据包

    3. 利用intent获取到返回数据

    很多人在刚开始进行android开发时,想要在两个activity之间传递数据,但是却并不知道如何去操作。那么通过这篇文章,我将帮助你把这个知识点安排的明明白白~

    一、什么是intent?

    在我看来,intent就是起到一个中间媒介的作用,可以在activity之间传递数据,也可以进行进行一些基本的action。比如startactivity()之类。如果有感兴趣的朋友,可以去网上查阅相关的资料,在这我就不赘述了~

    二、利用intent在两个activity之间传递数据

    首先我们创建两个activity,分别叫MainActivity以及OtherActivity。在MainActivity的布局文件中,添加一个button,用于页面之间的转跳,以及相关数据的传输。在OtherActivity的布局文件中,我们添加一个TextView,用于接受数据。
    (这两个Xml文件的代码较为简单,我就不贴出来了)

    下面主要说说MainActivity和OtherActivity中的代码。

    MainActivity中的代码:

    在这里插入图片描述
    这些代码,相信大家都很熟悉,应该不难。我们主要来说说putExtra();

    putExtra(“A”,B)中,AB为键值对,第一个参数为键名,第二个参数为键对应的值。顺便提一下,如果想取出Intent对象中的这些值,需要在你的另一个Activity中用getXXXXXExtra方法,注意需要使用对应类型的方法,参数为键名

    这时候我们再贴出OtherActivity的代码:
    在这里插入图片描述
    因为我们之前传入的是一个字符串,所以调用getStringExtra这个方法。

    这样我们就简单的在两个activity之间传递数据啦~

    二、 利用intent在两个activity之间传递数据包

    传递数据包,我们主要使用bundle这个类。

    首先看MainActivity中的代码:

    在这里插入图片描述
    首先我们创建一个bundle类。当传递字符串时,使用putString方法;传递整数时,用putInt方法…
    最后再用putExtras 将数据包传递到另一个activiity。

    OtherActivity中的代码:
    在这里插入图片描述
    首先我们创建一个bundle对象,接收MainActivity传递过来的数据。最后用setText方法,将其展现出来。这样一个数据包就传递完成了。

    三. 利用intent获取到返回数据

    我们继续创建两个Activity,分别叫MainActivity和OtherActivity。但是这次不同的是,我们在MainActivity的xml文件中,创建一个按钮和一个TextView,用于接收返回的数据。在OtherActivity的xml的文件中,我们创建一个EditText和一个button,用于返回数据。
    (这两个Xml文件的代码,我也不不一一展示了)

    首先看OtherActivity的代码:

    在这里插入图片描述
    都比较基础,我们主要看setResult()这个方法。

    它的第一个参数是一个返回码,主要用于设置返回状态,你也可以自行进行定义。第二个参数是一个intent对象。

    接下来我们看MainActivity的代码:
    在这里插入图片描述
    注意点:

    1. 如果我们想要得到返回的数据,就不能使用StartActivity,得使用StartActivityForResult这个方法。
    2. 还需要重写一个方法onActivityResult,用于接收数据。

    这样,我们就可以接收到OtherActivity中,输入的数据了。

    四、小结

    关于使用intent传递数据的基本用法,就如上文所说的那样,我感觉还是比较简单明了的。而且在未来的开发中,一定会经常遇到。所以大家一定要认真掌握呀~

    如果遇到什么问题,请在下方留言,我一定会尽力帮忙解决!大家共同进步呀~

    展开全文
  • intent 传递数据时的大小限制

    千次阅读 2020-04-07 17:55:27
    Activity间通过Intent传递数据的大小限制 – 具体数据博客 传 512K 以下的数据的数据可以正常传递。 传 512K~1024K 的数据会出错,闪退。 传 1024K 以上的数据会报错:TransactionTooLargeException 考虑到 Intent ...

    1. Intent 传递不同大小数据时的问题

    Activity间通过Intent传递数据的大小限制 – 具体数据博客

    传 512K 以下的数据的数据可以正常传递。
    传 512K~1024K 的数据会出错,闪退。
    传 1024K 以上的数据会报错:TransactionTooLargeException
    考虑到 Intent 还包括要启动的 Activity 等信息,实际可以传的数据略小于 512K
    2. 问题分析

    2.1 从 crash log 看起

    TransactionTooLargeException 分析:

    在 Intent 中传入一个 Parcelable 对象, 例如传入一个 bitmap 对象。Bitmap 实现了 Parcelable 接口,并且可以通过 getByteCount() 得知所占内存大小(代码在链接里可以找到)。sendBroadcast 时,报出如下信息

     V/ActivityManager: Broadcast: Intent { act=intent_bi flg=0x10 (has extras) } ordered=false userid=0 callerApp=ProcessRecord{27aeaaf5 31217:com.rustfisher.basic4/u0a113}
     E/JavaBinder: !!! FAILED BINDER TRANSACTION !!!
     W/BroadcastQueue: Failure sending broadcast Intent { act=intent_bi flg=0x10 (has extras) }
            android.os.TransactionTooLargeException
                at android.os.BinderProxy.transactNative(Native Method)
                at android.os.BinderProxy.transact(Binder.java:504)
                at android.app.ApplicationThreadProxy.scheduleRegisteredReceiver(ApplicationThreadNative.java:1170)
                at com.android.server.am.BroadcastQueue.performReceiveLocked(BroadcastQueue.java:576)
                at com.android.server.am.BroadcastQueue.deliverToRegisteredReceiverLocked(BroadcastQueue.java:848)
                at com.android.server.am.BroadcastQueue.processNextBroadcast(BroadcastQueue.java:917)
                at com.android.server.am.BroadcastQueue$BroadcastHandler.handleMessage(BroadcastQueue.java:254)
                at android.os.Handler.dispatchMessage(Handler.java:111)
                at android.os.Looper.loop(Looper.java:194)
                at android.os.HandlerThread.run(HandlerThread.java:61)
                at com.android.server.ServiceThread.run(ServiceThread.java:46)
    查看异常类 TransactionTooLargeException,它继承了 RemoteExceptio:

    package android.os;
    public class TransactionTooLargeException extends RemoteException {
        public TransactionTooLargeException() {
            super();
        }

        public TransactionTooLargeException(String msg) {
            super(msg);
        }
    }

    追踪到 Binder,它的 transactNative 方法会报出 RemoteException:

    public native boolean transactNative(int code, Parcel data, Parcel reply,
                int flags) throws RemoteException;
    1
    2
    由此可以看出,抛出异常与 Binder 有关。

    2.2 Intent 携带信息的大小受 Binder 限制

    Intent 携带信息的大小其实是受 Binder 限制。本文标题也可以改为 Binder传递数据大小限制。
    数据以 Parcel 对象的形式存放在 Binder传递缓存中。如果数据或返回值比传递 buffer 大,则此次传递调用失败并抛出 TransactionTooLargeException 异常。

    Binder 传递缓存有一个限定大小,通常是 1Mb。但同一个进程中所有的传输共享缓存空间。
    多个地方在进行传输时,即时它们各自传输的数据不超出大小限制,TransactionTooLargeException异常也可能会被抛出。

    在使用 Intent 传递数据时,1Mb 并不是安全上限。因为 Binder 中可能正在处理其它的传输工作。
    不同的机型和系统版本,这个上限值也可能会不同。

    在其它地方,例如 onSaveInstanceState(@NonNull Bundle outState),也可能会遇到与 Binder 有关的类似问题。

    2.3 为什么 Binder 要限制传输数据的大小

    个人推测,作为一种 IPC 的方式,Binder 并不是为传输大量数据而设计。传输大量数据,可以考虑URL 之类的方法( 只传递索引,不传递具体的数据。或者其他类似的做法)。

    3. 从 Intent 传递数据的原理分析

    通过 intent 的 bundle 的源码可以看到它们都是实现了 Parcelable ,其实就是通过序列化来实现通信的。提到 Parcelable 就不得不提 Serializable,这里引用一段网上的总结:

    介绍Parcelable不得不先提一下Serializable接口,Serializable是Java为我们提供的一个标准化的序列化接口,那什么是序列化呢? —- 简单来说就是将对象转换为可以传输的二进制流(二进制序列)的过程,这样我们就可以通过序列化,转化为可以在网络传输或者保存到本地的流(序列),从而进行传输数据 ,那反序列化就是从二进制流(序列)转化为对象的过程.
    Parcelable 是Android为我们提供的序列化的接口, Parcelable 相对于 Serializable 的使用相对复杂一些,但 Parcelable 的效率相对 Serializable 也高很多,这一直是 Google工程师引以为傲的,有时间的可以看一下 Parcelable 和 Serializable 的效率对比 Parcelable vs Serializable 号称快10倍的效率
    Yet another post on Serializable vs Parcelable
    Parcelable 的底层使用了 Parcel 机制。传递实际上是使用了 binder 机制,binder 机制会将 Parcel序列化的数据写入到一个共享内存中,读取时也是 binder 从共享内存中读出字节流,然后 Parcel 反序列化后使用。这就是 Intent 或 Bundle 能够在 activity或者跨进程通信的原理。

    参考“探索startActivity流程及在Activity间是如何传递Intent的
    关于 Parcelable 和 Serializable 的区别,同样引用一段网上的总结:

    Parcelable 和 Serializable 都是实现序列化并且都可以用于 Intent 间传递数据, Serializable 是 Java 的实现方式,可能会频繁的 IO 操作,所以消耗比较大,但是实现方式简单 Parcelable 是 Android 提供的方式, 效率比较高,但是实现起来复杂一些 , 二者的选取规则是:

    内存序列化上选择Parcelable
    存储到设备或者网络传输上选择Serializable(当然Parcelable也可以但是稍显复杂)
    当我们用Intent传输过大数据时,一般logcat会报出 TransactionTooLargeException 错误,谷歌官方对这个错误的描述如下:

    The Binder transaction failed because it was too large.
    During a remote procedure call, the arguments and the return value of the call are transferred as
    Parcel objects stored in the Binder transaction buffer. If the arguments or the return value are too
    large to fit in the transaction buffer, then the call will fail and TransactionTooLargeException
    will be thrown.

    The Binder transaction buffer has a limited fixed size, currently 1Mb, which is shared by all
    transactions in progress for the process. Consequently this exception can be thrown when there
    are many transactions in progress even when most of the individual transactions are of moderate size.

    There are two possible outcomes when a remote procedure call throws TransactionTooLargeException.
    Either the client was unable to send its request to the service (most likely if the arguments were
    too large to fit in the transaction buffer), or the service was unable to send its response back to
    the client (most likely if the return value was too large to fit in the transaction buffer). It is
    not possible to tell which of these outcomes actually occurred. The client should assume that a
    partial failure occurred.

    The key to avoiding TransactionTooLargeException is to keep all transactions relatively small.
    Try to minimize the amount of memory needed to create a Parcel for the arguments and the return
    value of the remote procedure call. Avoid transferring huge arrays of strings or large bitmaps.
    If possible, try to break up big requests into smaller pieces.

    If you are implementing a service, it may help to impose size or complexity contraints on the
    queries that clients can perform. For example, if the result set could become large, then don't
    allow the client to request more than a few records at a time. Alternately, instead of returning
    all of the available data all at once, return the essential information first and make the client
    ask for additional information later as needed.
    简单来说,我们上面提到了 Parcel 机制使用了一个共享内存,这个共享内存就叫 Binder transaction buffer,这块内存有一个大小限制,目前是 1MB,而且共用的,当超过了这个大小就会报错。

    也就是说不仅仅是一次性传递大数据会出问题,当同时传递很多数据,尽管每个都不超过1MB,但是总大小超过 1MB也会出错

    4. 解决方法

    Activity之间传递数据的方式及常见问题总结

    限制传递数据量
    改变数据传输方式(参见Activity之间传递数据的方式)
    静态static
    单例
    Application
    持久化
    ————————————————
    版权声明:本文为CSDN博主「怪伽先森」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/u011033906/article/details/89316543

    展开全文
  • Activity利用Intent传递数据

    千次阅读 2019-10-25 15:37:08
    一、从父Activity启动子Activity并传递数据 Intent的中文意思是“意图,目的”的意思,可以理解为不同组件之间通信的“媒介”或者“信使”。Intent由以下几个部分组成:动作(action),数据(data),分类...
  • Android Intent 传递数据大小限制

    千次阅读 2020-02-29 12:50:07
    Android Intent 传递数据大小限制 在sendBroadcast,startActivity时,我们会用到Intent。 Intent可以携带一些数据...Intent传递数据时,如果数据太大,可能会出现异常。比如App闪退,或是Intent发送不成功,logca...
  • 主要介绍了Android开发之利用Intent实现数据传递的方法,实例分析了Intent传递数据的原理与相关使用技巧,需要的朋友可以参考下
  • 参考: [007]一次Binder通信最大可以传输多大的数据? 探究intent传递大小限制 听说你Binder机制学的不错,来面试下这几个问题(一)
  • 安卓提供了Intent机制来实现应用间的通信,可以在Activity之间、Service、BroadCast中传递数据。提起Intent,我们最熟悉的可能就是在启动Activity的时候携带数据,使用非常简单: Intent intent = new Intent...
  • 其实Intent的作用不止于 活动之间的跳转, Intent还可以在启动活动的时候传递数据. 向下一个活动传递数据 在启动活动时传递数据的思路很简单, Intent 中提供了一系列 putExtra() 方法的重载, 可以把我们想要传递的...
  • Intent是Android中一个非常重要的概念,跟这个词的本意(意图,目的)一样,这个类在Android中的作用就是要调用某个组建去做某一件事,接下来详细介绍,感兴趣的朋友可以参考下
  • intent传递数据的几种常见方式

    千次阅读 2019-03-04 11:55:12
    一、通过intent.setData()来传递url Uri data = getIntent().getData(); if (data != null) { intent.setData(data); } 二、通过Intent.putExtra()方法通过键值对的形势装入数据。在新启动的activity中通过...
  • Bundl类是为字符串与某组件对象建立映射关系的组件,它与Intent配合使用,可在不同的Activity之间传送数据。常用方法如下: 1、putString:把字符串用键值对的形式放到Bundle对象中。 2、remove:移除指定key的值...
  • ​一:使用putExtra() (1)开始传递:FirstActivity.java ...二:使用bundle传递数据 (1)开始传递:FirstActivity.java (2)接收数据:SecondActivity.java (3)结果显示: 转载于:https://www....
  • Intent传递数据全解

    千次阅读 2016-03-14 16:59:44
    Intent传递简单数据可以以直接通过调用Intent的putExtra()方法存入数据,然后在获得Intent后调用getXxxExtra获得 对应类型的数据;传递多个的话,可以使用Bundle对象作为容器,通过调用Bundle的putXxx先将数据 存储...
  • intent传递数据限制

    2019-03-26 10:39:33
    https://www.jianshu.com/p/4537270be897
  • 4种最常用的Intent传递方式,这4种方式如下: 1、通过Intent传递数据 2、通过静态变量传递数据 3、通过剪切板传递数据 4、通过全局变量传递数据

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 60,290
精华内容 24,116
关键字:

intent传递数据