【安卓学习之常见问题】 界面(Activity/Fragment)之间的数据传递(Intent/Bundle)(附TransactionTooLargeException问题)

█ 【安卓学习之常见问题】 界面(Activity/Fragment)之间的数据传递(Intent/Bundle)(附TransactionTooLargeException问题)


█ 系列文章目录

提示:这里是收集了安卓学习之常见问题的相关文章


█ 文章目录


█ 读前说明

  • 本文通过学习别人写demo,学习一些课件,参考一些博客,’学习相关知识,如果涉及侵权请告知
  • 本文只简单罗列相关的代码实现过程
  • 涉及到的逻辑以及说明也只是简单介绍,主要当做笔记,了解过程而已

  

█ 我的问题:数据如何传输

⚡️ 在开发过程中进行数据传输,除了通过网络请求获取,部分数据是之间在本地之间进行传递的,经常会有点错乱,因此在此总结下。

█ 解决问题:

⚡️ 方法一,SharedPreferences
将数据通过android自带的SharedPreferences进行数据保存 (重启App数据不丢失)

        SharedPreferences.edit().putString("Token",123456).commit();// 保存
        SharedPreferences.getString("Token", "")// 获取

可以保存对象吗?当前可以,自己写比较麻烦,网上也有大神将他封装成一个库,可以直接调用使用,如果只是简单的数据信息保存,可以直接用原生的。
 
⚡️ 方法二,数据库
将数据保存到数据库中 (重启App数据不丢失)

		ArrayList<Person> items= (ArrayList<Person>) LitePal.findAll(Person.class);// 保存
		LitePal.saveAll(items);// 获取

数据库操作比较复杂,因此直接建议使用第三方库,比如’org.litepal.android:core:2.0.0’
 
⚡️ 方法三,全局对象
创建一个全局对象即可 (重启App数据丢失)

public class DataManager {
    private static volatile DataManager INSTANCE;

    List<Person> items = new ArrayList<>();

    private DataManager() {
    }

    public static DataManager getInstance() {
        if (INSTANCE == null) {
            synchronized (DataManager.class) {
                if (INSTANCE == null) {
                    INSTANCE = new DataManager();
                }
            }
        }
        return INSTANCE;
    }

    public List<Person> getItems() {
        return items;
    }

    public void setItems(List<Person> items) {
        this.items = items;
    }
 }

⚡️ 方法四,Intent/Bundle数据传递
通过Intent/Bundle数据传递到下一个界面 (重启App数据丢失),这个也是本文章主要要记录的数据。

█ 方案四详解:

⚡️ 传递的数据类型

  1. 启动Activity/Service 时通过Intent传递数据;
  2. 结束Activity/Fragment返回onActivityResult 时通过Intent传递数据;
  3. 启动Fragment 时是通过Bundle传递数据;

Intent里面也可以进行传输Bundle对象。 
 
 
⚡️ 关于Intent和Bundle 的数据封装:
(这边先定义好intent和bundle方便后面使用 )

    Person item = new Person ();
    List<Person> items = new ArrayList<>();
    
   Bundle bundle = new Bundle();
   bundle.putInt("int2",22);
   bundle.putInt("String","china22");
   bundle.putSerializable("Object2",  item);
   bundle.putSerializable("List2",   (Serializable) items);
   
	Intent intent=new Intent();
	intent.putExtra("int",11);
    intent.putExtra("String","china");
    intent.putExtra("Object",item );
    intent.putExtra("List", (Serializable) items);
    
 	intent.putExtra("bundle",bundle);

⚡️ 上述1、2情况的传递方式:(intent在前面已经定义好了)

    intent.setClass(Activity1.this,Activity2.class);
    startActivity(intent);// 情况1
    startActivityForResult(intent,requestCode);// 情况1
    
    setResult(requestCode, intent);;// 情况2
	getTargetFragment().onActivityResult(requestCode,Activity.RESULT_OK, intent);// 情况2

⚡️ 上述3情况的传递方式:(bundle在前面已经定义好 了)

 		DialogFragment fragment = new DialogFragment();
        fragment.setArguments(bundle);

⚡️ 上述1、2情况的接收:

 	intent.getIntExtra("int",11);// 针对 intent.putExtra("int",11);
    intent.getStringExtra("String","china");// 针对 intent.putExtra("String","china");
   (Person)  intent.getSerializableExtra("Object",item );// 针对 intent.putExtra("Object",item );
   (ArrayList<Person >) intent.getSerializableExtra("List", (Serializable) items);// 针对  intent.putExtra("List", (Serializable) items);

   bundle =	intent.getBundleExtra("bundle",bundle);// 针对 intent.putExtra("bundle",bundle)
	if (bundle != null) {
             ArrayList<Person> list = (ArrayList<Person>) bundle.get("List2");
             ......
   }

接下来比较有意思的是:
 我们通过intent直接获取bundle的key值,通过bundle直接获取intent的key值

 // 针对 bundle.putSerializable("Object2",  item);
 (Person)  intent.getSerializableExtra("Object2",item );
 // 针对  bundle.putSerializable("List2",   (Serializable) items);
 (ArrayList<Person >) intent.getSerializableExtra("List2", (Serializable) items);
 
  // 针对 intent.putExtra("Object",item );
  (Person)  bundle.get("Object",item );
  // 针对  intent.putExtra("List", (Serializable) items);
   (ArrayList<Person >) intent.get("List", (Serializable) items);

我们惊奇的发现竟然也可以取出这些数据!!!
也就是说:intent和bundle进行put(保存)数据的时候,是存在同一块map中,
看下源码,我们可以发现:
 
intent.getSerializableExtra(name)其实就是在调用bundle.getSerializable(name) 
因此不管用intent还是bundle都可以,只是调用的接口名称不一样而已

 public class Intent implements Parcelable, Cloneable {
    private Bundle mExtras;
    /**
     * Retrieve extended data from the intent.
     *
     * @param name The name of the desired item.
     *
     * @return the value of an item previously added with putExtra(),
     * or null if no Serializable value was found.
     *
     * @see #putExtra(String, Serializable)
     */
    public Serializable getSerializableExtra(String name) {
        return mExtras == null ? null : mExtras.getSerializable(name);
    }
  ● ● ● ● ● ●    
 }

在这里插入图片描述

█ 为什么有些是Intent 有些是Bundle ?

⚡️ 这个暂时不深入研究,至少Intent 中的数据都是存在Bundle 中的,在这里就罗列下代码记录下。
⚡️ 启动Activity/Service 时通过Intent传递数据;

    @Override
    public void startActivity(Intent intent) {
        mBase.startActivity(intent);
    }
   @Override
    public ComponentName startService(Intent service) {
        return mBase.startService(service);
    }
    /** Return the intent that started this activity. */
    public Intent getIntent() {
        return mIntent;
    }

⚡️ 结束Activity/Fragment返回onActivityResult 时通过Intent传递数据;

  protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        this.mFragments.noteStateNotSaved();
        int requestIndex = requestCode >> 16;
        if (requestIndex != 0) {
            --requestIndex;
            String who = (String)this.mPendingFragmentActivityResults.get(requestIndex);
            this.mPendingFragmentActivityResults.remove(requestIndex);
            if (who == null) {
                Log.w("FragmentActivity", "Activity result delivered for unknown Fragment.");
            } else {
                Fragment targetFragment = this.mFragments.findFragmentByWho(who);
                if (targetFragment == null) {
                    Log.w("FragmentActivity", "Activity result no fragment exists for who: " + who);
                } else {
                    targetFragment.onActivityResult(requestCode & '\uffff', resultCode, data);
                }

            }
        } else {
            PermissionCompatDelegate delegate = ActivityCompat.getPermissionCompatDelegate();
            if (delegate == null || !delegate.onActivityResult(this, requestCode, resultCode, data)) {
                super.onActivityResult(requestCode, resultCode, data);
            }
        }
    }

⚡️ 启动Fragment 时是通过Bundle传递数据;

public class TestFragment extends SupportFragment {
    Person person;
    public static TestFragment newInstance(Person person ) {
        Bundle args = new Bundle();
        args.putSerializable("person ", person );
        TestFragment fragment = new TestFragment();
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Bundle args = getArguments();
        if (args != null) {
           Object obj = args.getSerializable("person ");
            person= person instanceof Person  ? (Person) obj : null;
        }
    }
 ● ● ● ● ● ●    
 }

█ 一个小问题:putExtra和getExtra类型不同会怎么样?(2020-05-26补充)

⚡️ 如果 intent.putExtra(“test”,true);那么 intent.getIntExtra(“test”,100)等于多少?

我们都知道,intent.getBooleanExtra(“test”,false),会等于true;
而intent.getIntExtra(“test”,100)等于多少?经过测试,是等于100,即默认值。

⚡️ 为什么有这个问题?
  恰好看到一段代码,通过intent传值来判断,通知栏消息要跳转到哪个页面,因此才有此疑问,那么这样写的后果,将push永远为0,永远无法执行跳转功能,如下:

在这里插入图片描述
在这里插入图片描述

█ 第二个小问题?传递的数据太大时,怎么办?(2021-04-26补充)

⚡️ 当intent.putExtra传递的数据太大时,怎么办?
 【安卓学习之常见问题】从ANR到ConcurrentModificationException


█ 相关资料

提示:这里是参考的相关文章

  1. 2019-03-06 Android传值Intent和Bundle区别 - 限量版爱 - 博客园
  2. 2018-12-03 TransactionTooLargeException: data parcel size xxx bytes原因与解决方案_迎风致万里的博客-CSDN博客
  3. Android 开发太难了,这异常竟然捕获不到?跳转Activity时,携带数据过多

█ 免责声明

博主分享的所有文章内容,部分参考网上教程,引用大神高论,部分亲身实践,记下笔录,内容可能存在诸多不实之处,还望海涵,本内容仅供学习研究使用,切勿用于商业用途,若您是部分内容的作者,不喜欢此内容被分享出来,可联系博主说明相关情况通知删除,感谢您的理解与支持!

提示:转载请注明出处:
https://blog.csdn.net/ljb568838953/article/details/104657403

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值