首页 > 其他分享 >Android开发 - Bundle传值的理解与使用

Android开发 - Bundle传值的理解与使用

时间:2024-07-23 09:08:21浏览次数:10  
标签:String people bundle Bundle key Android 传值 mParcelledData

什么是Bundle

  • Bundle经常出现在以下场合:

    Activity状态数据的保存与恢复涉及到的两个回调:
    void onSaveInstanceState (Bundle outState)
    void onCreate (Bundle savedInstanceState)
    
    Fragment的setArguments方法:void setArguments (Bundle args)
    
    消息机制中的Message的setData方法:void setData (Bundle data)
    
    ...
    
  • Bundle从字面上解释为“一捆、一批、一包”,结合上述几个应用场合,可以知道Bundle是用来传递数据的。我们经常使用BundleActivity之间传递数据,传递的数据可以是booleanbyteintlongfloatdoublestring等基本类型或它们对应的数组也可以是对象或对象数组当Bundle传递的是对象或对象数组时,必须实现Serializable 或Parcelable接口。下面分别介绍Activity之间如何传递基本类型、传递对象:

    • Bundle的两个常用方法:
      1. putXxx(String key,Xxx value):Xxx表示一系列的数据类型,比如StringintfloatParcelableSerializable等类型,以“键值对”(key-value,可以理解为一个Map<K,V>)形式保存数据
      2. getXxx(String key):根据key值获取Bundle中的value数据

Bundle源码分析

Bundle的声明

  • public final class Bundle extends BaseBundle implements Cloneable, Parcelable:可以看出以下几点:

    1. 它使用final修饰,所以不可以被继承

    2. 它实现了两个接口,cloneable(复制)和Parcelable(打包),这就意味着他必须实现以下方法:

      public Object clone()	//克隆数据
      public int describeContents()	//写入数据
      public void writeToParcel(Parcel parcel, int flags)	//将数据打包
      public void readFromParcel(Parcel parcel)	//读取数据
      public static final Parcelable.Creator<Bundle> CREATOR = new Parcelable.Creator<Bundle>()	//将打包的数据实例化
      

Bundle的内存结构

  • ArrayMap<String, Object> mMap = null;:使用的是ArrayMap,这个集合类存储的也是键值对,但是与Hashmap不同的是,hashmap采用的是“数组+链表”的方式存储,而Arraymap中使用的是两个数组进行存储,一个数组存储key,一个数组存储value,内部的增删改查都将会使用二分查找来进行,这个和SparseArray差不多,只不过sparseArraykey值只能是int类型的,而Arraymap可以是map型,所以在数据量不大的情况下可以使用这两个集合代替hashmap去优化性能

Get/Put解析

  • Bundle其实就是一个容器,内部使用了Arraymap去存储数据,那么就必然会提供getput方法,由于Bundle支持的数据类型太多,这里我们就举例布尔类型的,其他类型的方式都差不多:

    getBoolean

    public boolean getBoolean(String key, boolean defaultValue) {
        unparcel();
        Object o = mMap.get(key);
        if (o == null) {
            return defaultValue;
        }
        try {
            return (Boolean) o;
        } catch (ClassCastException e) {
            typeWarning(key, o, "Boolean", defaultValue, e);
            return defaultValue;
        }
    }
    
    • 数据读取的逻辑就是通过keyArrayMap里读出保存的数据,并转换成对应的类型返回,当没找到数据或发生类型转换异常时返回缺省值(default-value类似null的空值)

    putBoolean

    public void putBoolean(@Nullable String key, boolean value) {
        unparcel();
        mMap.put(key, value);
    }
    

    unparcel()

    • 先来看下BaseBundlemParcelledData的定义:

      Parcel mParcelledData = null;
      
      • 在大部分情况下mParcelledData都是null,因此unparcel()直接返回。当使用构造函数public Bundle(Bundle b)创建Bundle时,会给mParcelledData赋值;
      oid copyInternal(BaseBundle from, boolean deep) {
          synchronized (from) {
              if (from.mParcelledData != null) {
                  if (from.isEmptyParcel()) {
                      mParcelledData = NoImagePreloadHolder.EMPTY_PARCEL;	//第一种取值
                  } else {
                      mParcelledData = Parcel.obtain();	//第二种取值
                      mParcelledData.appendFrom(from.mParcelledData, 0, from.mParcelledData.dataSize());
                      mParcelledData.setDataPosition(0);
                  }
              } else {
                  mParcelledData = null;	//第三种取值
              }
      
              if (from.mMap != null) {
                  if (!deep) {
                      mMap = new ArrayMap<>(from.mMap);
                  } else {
                      final ArrayMap<String, Object> fromMap = from.mMap;
                      final int N = fromMap.size();
                      mMap = new ArrayMap<>(N);
                      for (int i = 0; i < N; i++) {
                          mMap.append(fromMap.keyAt(i), deepCopyValue(fromMap.valueAt(i)));
                      }
                  }
              } else {
                  mMap = null;
              }
      
              mClassLoader = from.mClassLoader;
          }
      }
      
      • 从上述代码片段可以知道mParcelledData的取值有3种情况:
        1. mParcelledData = EMPTY_PARCEL
        2. mParcelledData = Parcel.obtain()
        3. mParcelledData = null

    总结

    • unparcel()方法中就对上述几种情况做了不同的处理,当mParcelledData = null时,直接返回

    • mParcelledData = EMPTY_PARCEL时,会创建一个容量为1ArrayMap对象

    • mParcelledData = Parcel.obtain()时,则会将里面的数据读出,并创建一个ArrayMap,并将数据存储到ArrayMap对象里面,同时将mParcelledData回收并置为null

Bundle的使用

各种常用类型的Put/Get方法

  • Bundle提供了,用于读写基本类型的数据。Bundle操作基本数据类型的API表格如下所示:

传递基本类型的对象

  • 数据打包

    Bundle bundle = new Bundle();
    Intent intent = new Intent(MainActivity.this,Main2Activity.class);
    //设置数据
    String name = "zhangSan";
    String num = "88888";
    //把数据保存到Bundle里  
    bundle.putString("name", name);
    bundle.putString("num", num);
    //把bundle放入intent里  
    intent.putExtra("Message", bundle);
    startActivity(intent);//开始打包
    
  • 读取数据

    Intent intent = getIntent();
    //实例化一个Bundle  
    Bundle bundle = intent.getExtras();
    String name = bundle.getString("name");
    String num = bundle.getString("num");
    

Activity通过Arguments给fragment类传值

  • Activity类动态加载fragment时可以通过fragmentsetArguments()传入值,并在fragment类中通过fragmentgetArguments()方法获得传入的值。

  • 数据打包

    Bundle bundle = new Bundle();
    fragment01 fragment01 = new fragment01();//自定义的fragment类
    //设置数据
    String name = "zhangSan";
    String num = "88888";
    //把数据保存到Bundle里  
    bundle.putString("name", name);
    bundle.putString("num", num);
    //把bundle通过Arguments放入要传值的fragment类里  
    fragment01.setArguments(bundle);
    
  • 读取数据

    String name = getArguments().getString("name");
    String num = getArguments().getString("num");
    

传递Serializable类型的对象

  • Serializable:是一个对象序列化的接口。一个类只有实现了Serializable接口,它的对象才是可序列化的。因此如果要序列化某些类的对象,这些类就必须实现Serializable接口。而实际上,Serializable是一个空接口,没有什么具体内容,它的目的只是简单的标识一个类的对象可以被序列化

  • 打包数据

    People people = new people();	//People类
    //设置数据
    String Name = "zhangSan";
    String Num = "88888";
    people.setName(Name);
    people.setNum(Num);
    //实例化一个Bundle  
    Bundle bundle = new Bundle();
    //把people数据放入到bundle中
    bundle.putSerializable("people", people);
    Intent intent = new Intent(MainActivity.this,Main2Activity.class);
    //把bundle放入intent里  
    intent.putExtras(bundle);
    startActivity(intent);//开始打包
    
  • 读取数据

    Intent intent = getIntent();
    // 实例化一个Bundle  
    Bundle bundle = intent.getExtras();
    //获取里面的people里面的数据  
    People people = (people) bundle.getSerializable("people");
    String name = people.getName();
    String num = people.getNum();
    

标签:String,people,bundle,Bundle,key,Android,传值,mParcelledData
From: https://www.cnblogs.com/ajunjava/p/18317510

相关文章

  • Android 常见面试题(一)
    Android常见面试题(一)1、java中==和equals和hashCode的区别基本数据类型的==比较的值相等.类的==比较的内存的地址,即是否是同一个对象。在不重写equals方法的情况下,equals同比较内存地址,原实现也为==,如String等重写了equals方法,会判断字符串里的值是否相等......
  • Android4.4.4双声卡同时出声
    在调试RK3288Android4.4.4,该方案默认配置上SPDIF时HDMI就没声音,但客户需求是同时要有声音的,于是驱动配置上后,呈现两个声卡状态,此时需要通过修改HAL层来处理(RK3288Android4.4.4对应的HAL层源码为hardware/rk29/audio目录),修改如下:1.修改AudioHardware.cpp文件,在AudioHardware:......
  • Android或iOS 与 REST/SOAP测试 工具推荐
    移动测试工具- 有助于自动测试Android或iOS应用程序1)AppiumAppium是用于移动应用程序自动化的开源测试工具之一。它允许用户测试各种原生、移动、web和混合应用程序。它还支持模拟器和模拟器上的自动测试。功能特点:这是一个简单的应用程序,需要很少的内存用于测试过程......
  • Android笔试面试题AI答之控件Views(3)
    答案仅供参考,来自文心一言目录1.如何在ListView间添加分割线?方法1:在XML布局文件中设置方法2:在Java代码中设置注意事项2.如何实现ListView的逐行显示?1.使用`Handler`和`postDelayed()`方法2.监听滚动事件3.自定义Adapter4.使用`RecyclerView`代替`ListVie......
  • Android 14 适配之— BluetoothAdapter、JobScheduler、 Tiles
    1. BluetoothAdapter改动:在BluetoothAdapter中必须加入 BLUETOOTH_CONNECT权限 Android14(API级别34)或更高版本为目标的App,在调用函数 BluetoothAdapter getProfileConnectionState() 时,需要 BLUETOOTH_CONNECT 权限,<uses-permissionandroid:name="android......
  • Android14 - 前台服务、图片选择器 、OpenJDK 17、其他适配
    前台服务1.指定前台服务类型   以Android14(API级别34)或更高版本为目标平台的应用,需要为应用中的每项前台服务指定服务类型,因为系统需要特定类型的前台服务满足特定用例。具体介绍如下:   在Android10在 <service> 元素内引入了 android:foregroundService......
  • android Activity生命周期
    (1)activity启动政策:activity启动行为由相应应用的 AndroidManifest.xml 文件中的启动模式、intent标志以及调用方提供的ActivityOptions定义。使用 ActivityOption#setLaunchDisplayId(int) 可将特定屏幕指定为activity启动的目标。默认情况下,activity与调用方在......
  • Frida server版本对应 Android 安卓版本
    前言全局说明Fridaserver版本对应Android安卓版本一、说明frida​的版本号需要注意一下,例如低版本的Android(如Android6),可能出现frida-server运行时宿主系统出现黑屏,死机的问题。如果遇到此问题,手机未自动重启,手动强制重启后系统即可恢复正常。下面附上一张来自网......
  • android audio 相机按键音加载与修改
    相机按键音资源,加载文件路径:frameworks/av/services/camera/libcameraservice/CameraService.cpp按键音,加载函数: voidCameraService::loadSoundLocked(sound_kindkind){   ATRACE_CALL();     LOG1("CameraService::loadSoundLockedref=%d",mSoundRe......
  • 深入分析 Android ContentProvider (一)
    文章目录深入分析AndroidContentProvider(一)1.Android中的ContentProvider设计说明1.1.ContentProvider的设计初衷1.2.ContentProvider的基本结构1.3.ContentProvider的实现示例:实现一个简单的ContentProvider1.4.ContentProvider的使用2.ContentPro......