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是用来传递数据的,我们暂将Bundle理解为Android中用来传递数据的一个容器。官方文档对Bundle的说明如下:
Bundle实现了Parcelable接口,所以他可以方便的在不同进程间传输,这里要注意我们传输的数据必须能够被序列化。
bundle的作用主要时用于传递数据;它所保存的数据是以key-value(键值对)的形式存在的,也就是说bundle是保存数据的容器,内部使用了ArrayMap去存储数据,也提供了很多get,put方法。
bundle传递的数据包括:string、int、boolean、byte、float、long、double等基本类型或它们对应的数组,也可以是对象或对象数组。当bundle传递的是对象或对象数组时,必须实现Serialiable或Parcelable接口。
Bundle源码分析
Bundle操作的基本数据类型如下表所示,它们都继承自BaseBundle (From class android.os.BaseBundle )
返回类型 | 函数 | 函数说明 |
---|---|---|
void | clear() | Removes all elements from the mapping of this Bundle. |
boolean | containsKey(String key) | Returns true if the given key is contained in the mapping of this Bundle. |
object | get(String key) | Returns the entry with the given key as an object. |
boolean | getBoolean(String key, boolean defaultValue) | Returns the value associated with the given key, or defaultValue if no mapping of the desired type exists for the given key. |
boolean | getBoolean(String key) | Returns the value associated with the given key, or false if no mapping of the desired type exists for the given key. |
boolean[] | getBooleanArray(String key) | Returns the value associated with the given key, or null if no mapping of the desired type exists for the given key or a null value is explicitly associated with the key. |
double | getDouble(String key, double defaultValue) | Returns the value associated with the given key, or defaultValue if no mapping of the desired type exists for the given key. |
double | getDouble(String key) | Returns the value associated with the given key, or 0.0 if no mapping of the desired type exists for the given key. |
double[] | getDoubleArray(String key) | Returns the value associated with the given key, or null if no mapping of the desired type exists for the given key or a null value is explicitly associated with the key. |
int | getInt(String key) | Returns the value associated with the given key, or 0 if no mapping of the desired type exists for the given key. |
int | getInt(String key, int defaultValue) | Returns the value associated with the given key, or defaultValue if no mapping of the desired type exists for the given key. |
int[] | getIntArray(String key) | Returns the value associated with the given key, or null if no mapping of the desired type exists for the given key or a null value is explicitly associated with the key. |
long | getLong(String key) | Returns the value associated with the given key, or 0L if no mapping of the desired type exists for the given key. |
long | getLong(String key, long defaultValue) | Returns the value associated with the given key, or defaultValue if no mapping of the desired type exists for the given key. |
long[] | getLongArray(String key) | Returns the value associated with the given key, or null if no mapping of the desired type exists for the given key or a null value is explicitly associated with the key. |
String | getString(String key) | Returns the value associated with the given key, or null if no mapping of the desired type exists for the given key or a null value is explicitly associated with the key. |
String | getString(String key, String defaultValue) | Returns the value associated with the given key, or defaultValue if no mapping of the desired type exists for the given key or if a null value is explicitly associated with the given key. |
String[] | getStringArray(String key) | Returns the value associated with the given key, or null if no mapping of the desired type exists for the given key or a null value is explicitly associated with the key. |
boolean | isEmpty() | Returns true if the mapping of this Bundle is empty, false otherwise. |
Set | keySet() | Returns a Set containing the Strings used as keys in this Bundle. |
void | putAll(PersistableBundle bundle) | Inserts all mappings from the given PersistableBundle into this BaseBundle. |
void | putBoolean(String key, boolean value) | Inserts a Boolean value into the mapping of this Bundle, replacing any existing value for the given key. |
void | putBooleanArray(String key, boolean[] value) | Inserts a boolean array value into the mapping of this Bundle, replacing any existing value for the given key. |
void | putDouble(String key, double value) | Inserts a double value into the mapping of this Bundle, replacing any existing value for the given key. |
void | putDoubleArray(String key, double[] value) | Inserts a double array value into the mapping of this Bundle, replacing any existing value for the given key. |
void | putInt(String key, int value) | Inserts an int value into the mapping of this Bundle, replacing any existing value for the given key. |
void | putIntArray(String key, int[] value) | Inserts an int array value into the mapping of this Bundle, replacing any existing value for the given key. |
void | putLong(String key, long value) | Inserts a long value into the mapping of this Bundle, replacing any existing value for the given key. |
void | putLongArray(String key, long[] value) | Inserts a long array value into the mapping of this Bundle, replacing any existing value for the given key. |
void | putString(String key, String value) | Inserts a String value into the mapping of this Bundle, replacing any existing value for the given key. |
void | putStringArray(String key, String[] value) | Inserts a String array value into the mapping of this Bundle, replacing any existing value for the given key. |
void | remove(String key) | Removes any entry with the given key from the mapping of this Bundle. |
int | size() | Returns the number of mappings contained in this Bundle. |
首先看它的声明
public final class Bundle extends BaseBundle implements Cloneable, Parcelable
第一,它使用final修饰,所以不可以被继承
第二,它实现了两个接口,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>()
再看他的内存结构:
ArrayMap<String, Object> mMap = null;
使用的是ArrayMap,这个集合类存储的也是键值对,但是与Hashmap不同的是,hashmap采用的是“数组+链表”的方式存储,而ArrayMap中使用的是两个数组进行存储,一个数组存储key,一个数组存储value,内部的增删改查都将会使用二分查找来进行,这个和SparseArray差不多,只不过SparseArray的key值只能是int型的,而Arraymap可以是map型,所以在数据量不大的情况下可以使用这两个集合代替hashmap去优化性能。
我们知道Bundle其实就是一个容器,内部使用了ArrayMap去存储数据,那么就必然会提供get,put方法,由于Bundle支持的数据类型太多,这里我们就看一个布尔类型的,其他类型的方式都差不多。
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;}
}
数据读取的逻辑很简单,就是通过key从ArrayMap里读出保存的数据,并转换成对应的类型返回,当没找到数据或发生类型转换异常时返回缺省值。
public void putBoolean(@Nullable String key, boolean value) {unparcel();mMap.put(key, value);
}
这里出现了一个unparcel()方法
/* package */
void unparcel() {synchronized (this) {final Parcel parcelledData = mParcelledData;if (parcelledData == null) {if (DEBUG) Log.d(TAG, "unparcel "+ Integer.toHexString(System.identityHashCode(this))+ ": no parcelled data");return;}if (LOG_DEFUSABLE && sShouldDefuse && (mFlags & FLAG_DEFUSABLE) == 0) {Slog.wtf(TAG, "Attempting to unparcel a Bundle while in transit; this may "+ "clobber all data inside!", new Throwable());}if (isEmptyParcel()) {if (DEBUG) Log.d(TAG, "unparcel "+ Integer.toHexString(System.identityHashCode(this)) + ": empty");if (mMap == null) {mMap = new ArrayMap<>(1);} else {mMap.erase();}mParcelledData = null;return;}int N = parcelledData.readInt();if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))+ ": reading " + N + " maps");if (N < 0) {return;}ArrayMap<String, Object> map = mMap;if (map == null) {map = new ArrayMap<>(N);} else {map.erase();map.ensureCapacity(N);}try {parcelledData.readArrayMapInternal(map, N, mClassLoader);} catch (BadParcelableException e) {if (sShouldDefuse) {Log.w(TAG, "Failed to parse Bundle, but defusing quietly", e);map.erase();} else {throw e;}} finally {mMap = map;parcelledData.recycle();mParcelledData = null;}if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))+ " final map: " + mMap);}
}
先来看下BaseBundle中mParcelledData的定义:
Parcel mParcelledData = null;
在大部分情况下mParcelledData都是null,因此unparcel()直接返回。当使用构造函数public Bundle(Bundle b)创建Bundle时,会给mParcelledData赋值;
void 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种情况:
- mParcelledData = EMPTY_PARCEL
- mParcelledData = Parcel.obtain()
- mParcelledData = null
在unparcel()方法中就对上述几种情况做了不同的处理,当mParcelledData为null时,直接返回;当mParcelledData为EMPTY_PARCEL时,会创建一个容量为1的ArrayMap对象;当mParcelledData为Parcel.obtain()时,则会将里面的数据读出,并创建一个ArrayMap,并将数据存储到ArrayMap对象里面,同时将mParcelledData回收并置为null;
Parcelable接口分析
在Android中,Parcelable接口是用于实现对象序列化和反序列化的一种机制。它允许我们将自定义的Java对象转换成一个可传输的二进制数据流,以便在不同组件之间传递数据。通常在Activity之间传递复杂的自定义对象时,使用Parcelable接口比使用Java的Serializable接口更高效。
Parcelable接口的工作原理是通过将对象的数据拆分成原始数据类型,并在写入和读取时进行序列化和反序列化。这样可以避免使用Java的反射机制,提高了性能。
要实现Parcelable接口,首先需要让自定义的Java类实现Parcelable接口,并实现以下几个方法:
- writeToParcel(Parcel parcel, int flags): 将对象的数据写入Parcel对象,以进行序列化。在这个方法中,需要将对象的各个字段写入Parcel对象。
- createFromParcel(Parcel parcel): 从Parcel对象中读取数据,以进行反序列化。在这个方法中,需要读取Parcel中的数据,并将其设置为对象的各个字段。
- newArray(int size): 创建一个指定大小的对象数组,通常用于反序列化的过程。
接着,需要在类中添加一个静态的Parcelable.Creator对象,用于创建和反序列化对象。这个对象需要实现Parcelable.Creator接口,并实现以下方法:
- createFromParcel(Parcel parcel): 根据Parcel对象创建并返回对象实例。
- newArray(int size): 创建一个指定大小的对象数组。
最后,在类中添加一个public static final的Parcelable.Creator对象,以供系统使用。
下面是一个简单的示例,演示了如何在Android中实现Parcelable接口:
import android.os.Parcel;
import android.os.Parcelable;public class Student implements Parcelable {private String name;private int age;public Student(String name, int age) {this.name = name;this.age = age;}protected Student(Parcel in) {name = in.readString();age = in.readInt();}@Overridepublic void writeToParcel(Parcel dest, int flags) {dest.writeString(name);dest.writeInt(age);}@Overridepublic int describeContents() {return 0;}public static final Creator<Student> CREATOR = new Creator<Student>() {@Overridepublic Student createFromParcel(Parcel in) {return new Student(in);}@Overridepublic Student[] newArray(int size) {return new Student[size];}};
}
在这个例子中,我们创建了一个名为Student的类,实现了Parcelable接口。在writeToParcel方法中,我们将Student对象的name和age字段写入Parcel对象。在createFromParcel方法中,我们从Parcel对象中读取name和age字段,并创建一个新的Student对象。
通过实现Parcelable接口,我们可以在不同的Android组件之间传递Student对象,而不需要进行繁琐的序列化和反序列化操作。同时,Parcelable接口也比Serializable接口更高效,适用于在性能要求较高的场景下使用。
代码举例说明
当使用Parcelable接口时,我们可以将自定义的Java类对象传递给Android组件,例如Activity之间的传递。下面是一个简单的示例,展示如何实现Parcelable接口和在Activity之间传递自定义对象:
首先,创建一个名为Student的Java类,该类包含一些基本的字段和方法:
import android.os.Parcel;
import android.os.Parcelable;public class Student implements Parcelable {private String name;private int age;public Student(String name, int age) {this.name = name;this.age = age;}protected Student(Parcel in) {name = in.readString();age = in.readInt();}public String getName() {return name;}public int getAge() {return age;}@Overridepublic void writeToParcel(Parcel dest, int flags) {dest.writeString(name);dest.writeInt(age);}@Overridepublic int describeContents() {return 0;}public static final Creator<Student> CREATOR = new Creator<Student>() {@Overridepublic Student createFromParcel(Parcel in) {return new Student(in);}@Overridepublic Student[] newArray(int size) {return new Student[size];}};
}
接下来,在发送方的Activity中,我们创建一个Student对象并使用Intent将其传递给接收方的Activity:
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;public class SenderActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_sender);// 创建一个Student对象Student student = new Student("Alice", 20);// 使用Intent传递Student对象给ReceiverActivityIntent intent = new Intent(this, ReceiverActivity.class);intent.putExtra("student", student);startActivity(intent);}
}
最后,在接收方的Activity中,我们从Intent中获取传递过来的Student对象:
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;public class ReceiverActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_receiver);// 从Intent中获取传递过来的Student对象Student student = getIntent().getParcelableExtra("student");if (student != null) {// 使用Student对象的数据String name = student.getName();int age = student.getAge();// 在这里进行相关操作,例如显示学生信息}}
}
通过实现Parcelable接口,我们可以轻松地在Activity之间传递自定义的Student对象,而不需要进行额外的序列化和反序列化操作。在接收方的Activity中,我们可以获取传递过来的Student对象,并使用其中的数据进行相应的处理。这样,我们就实现了自定义对象的传递和使用。
Bundle实战
在Activity to Activity传递数据时使用Bundle
① 当传递简单数据时
新建一个MainActivity,对应的布局文件比较简单,就是一个Button,点击这个按钮后,程序跳转到SecondActivity,并将传递的数据在SecondActivity的TextView中显示出来。这样,就使用Bundle实现了数据在Activity之间的传递。
package com.example.bundletest;import androidx.appcompat.app.AppCompatActivity;import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;public class MainActivity extends AppCompatActivity {//声明控件对象private Button mButton;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//获取控件的对象mButton = findViewById(R.id.button);//为Button绑定监听器mButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {/*** 存入数据*///实例化一个BundleBundle bundle = new Bundle();Intent intent = new Intent(MainActivity.this, SecondActivity.class);//设置数据String name = "Trump";int num = 123;//把数据放入到Bundle容器中bundle.putString("Name", name);bundle.putInt("Num", num);//把Bundle容器中的数据放到Intent中intent.putExtra("Message", bundle);//启动该Intent,实现Activity的跳转startActivity(intent);}});}
}
新建一个SecondActivity,用于显示传递的数据。对应的布局文件也很简单,就是一个TextView。
package com.example.bundletest;import androidx.appcompat.app.AppCompatActivity;import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import android.widget.TextView;public class SecondActivity extends AppCompatActivity {//声明控件对象private TextView textView;@SuppressLint("SetTextI18n")@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_second);//获取控件的对象textView = findViewById(R.id.text_view);/***读取数据*/Intent intent = getIntent();//从Intent中取出BundleBundle bundle = intent.getBundleExtra("Message");//获取数据assert bundle != null;String name = bundle.getString("Name");int num = bundle.getInt("Num");//显示数据textView.setText(name + "\n" + num);}
}
运行程序后,结果如下图所示:
点击Button,结果如下图所示:
② 当传递的参数很多,或者传递一个类的对象时
新建一个JavaBean,将这个类命名为FunPerson,并实现Serializable接口。
package com.example.bundletest;import java.io.Serializable;public class FunPerson implements Serializable {//创建实例变量private String name;private int num;public void setName(String name) {this.name = name;}public String getName() {return name;}public void setNum(int num) {this.num = num;}public int getNum() {return num;}
}
修改MainActivity中的代码:
public class MainActivity extends AppCompatActivity {//声明控件对象private Button mButton;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//获取控件的对象mButton = findViewById(R.id.button);//为Button绑定监听器mButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {/*** 存入数据*/FunPerson person = new FunPerson();//设置数据String name = "Trump is fun";int num = 12345;person.setName("name");person.setNum(num);//实例化一个BundleBundle bundle = new Bundle();//把FunPerson数据放入到Bundle容器中bundle.putSerializable("Person", person);Intent intent = new Intent(MainActivity.this, SecondActivity.class);//把Bundle容器中的数据放到Intent中intent.putExtras(bundle);//启动该Intent,实现Activity的跳转startActivity(intent);}});}
}
修改SecondActivity中的代码:
public class SecondActivity extends AppCompatActivity {//声明控件对象private TextView textView;@SuppressLint("SetTextI18n")@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_second);//获取控件的对象textView = findViewById(R.id.text_view);/***读取数据*/Intent intent = getIntent();//从Intent中取出BundleBundle bundle = intent.getExtras();//获取FunPerson里的数据数据assert bundle != null;FunPerson person = (FunPerson)bundle.getSerializable("Person");assert person != null;String name = person.getName();int num = person.getNum();//显示数据textView.setText(name + "\n" + num);}
}
看下运行后的结果:
在Activity to Fragment传递数据时使用Bundle
Activity重新创建时,会重新构建它所管理的Fragment,原先的Fragment的字段值将会全部丢失,但是通过Fragment.setArguments(Bundle bundle)方法设置的bundle会保留下来。所以尽量使用Fragment.setArguments(Bundle bundle)方式来传递参数。
有两种实现方案。
① 方法一:使用Fragment的静态方法newInstance()来传递数据
新建MainActivity:
public class MainActivity extends AppCompatActivity {private Button mButton;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mButton = findViewById(R.id.button);mButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//发送数据BlankFragment blankFragment = BlankFragment.newInstance("Message_1 To Fragment", "Message_2 To Fragment");FragmentManager fragmentManager = getSupportFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();//FrameLayout用于动态更新fragmentfragmentTransaction.replace(R.id.frame_layout, blankFragment);fragmentTransaction.commit();}});}
}
MainActivity的布局文件如下:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><Buttonandroid:id="@+id/button"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginBottom="8dp"android:layout_marginTop="8dp"android:text="SendMsg"android:textAllCaps="false"app:layout_constraintBottom_toTopOf="@+id/guide_line"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent" /><androidx.constraintlayout.widget.Guidelineandroid:id="@+id/guide_line"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal"app:layout_constraintGuide_begin="255dp" /><FrameLayoutandroid:id="@+id/frame_layout"android:layout_width="0dp"android:layout_height="0dp"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintHorizontal_bias="0.0"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="@+id/guide_line"app:layout_constraintVertical_bias="0.0" ></FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
新建一个Fragment:
public class BlankFragment extends Fragment {// TODO: Rename parameter arguments, choose names that match// the fragment initialization parameters, e.g. ARG_ITEM_NUMBERprivate static final String ARG_PARAM1 = "param1";private static final String ARG_PARAM2 = "param2";// TODO: Rename and change types of parametersprivate String mParam1;private String mParam2;public static BlankFragment newInstance(String param1, String param2) {BlankFragment fragment = new BlankFragment();Bundle args = new Bundle();args.putString(ARG_PARAM1, param1);args.putString(ARG_PARAM2, param2);fragment.setArguments(args);return fragment;}@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {// Inflate the layout for this fragmentView view = inflater.inflate(R.layout.fragment_blank, container, false);TextView textView = view.findViewById(R.id.text_view);//Fragment获取数据Bundle bundle = getArguments();String message = null;if (bundle != null) {message = bundle.getString(ARG_PARAM1);}textView.setText(message);return view;}
}
BlankFragment的布局文件比较简单,就是一个显示用的TextView。
运行程序,点击Button,结果如下图bundle4所示:
② 方法二:
修改MainActivity的代码:
public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button mButton = findViewById(R.id.button);mButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//发送数据ToFragment fragment = new ToFragment();//新建一个Bundle实例Bundle bundle = new Bundle();bundle.putString("data", "From Activity To Fragment");//将数据传递到Fragmentfragment.setArguments(bundle);FragmentManager fragmentManager = getSupportFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();//FrameLayout用于动态更新fragmentfragmentTransaction.replace(R.id.frame_layout, fragment);fragmentTransaction.commit();}});}
}
新建一个碎片ToFragment,简单起见,就不给新建的碎片弄一个布局文件,直接使用BlankFragment的布局文件,节省时间:
public class ToFragment extends Fragment {@Nullable@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {//简单起见,此处直接使用BlankFragment的布局文件View view = inflater.inflate(R.layout.fragment_blank, container, false);TextView textView = view.findViewById(R.id.text_view);//得到从Activity传来的数据Bundle bundle = this.getArguments();String message = null;if (bundle != null) {message = bundle.getString("data");}textView.setText(message);return view;}
}
运行程序后结果如下所示:
3. 在消息机制的Message中使用setData()传递数据时用到Bundle
这个栗子的思路也很简单,点击屏幕,给Activity发送一个Message,传递两个参数,并通过Toast显示出来,最后finish()掉这个Activity。
新建一个Activity:
public class MainActivity extends AppCompatActivity {final static int FLAG = 1;@SuppressLint("HandlerLeak")public Handler mHandler = new Handler() {@Overridepublic void handleMessage(@NonNull Message msg) {super.handleMessage(msg);switch (msg.what) {case FLAG://获取Message传递过来的数据String data1 = msg.getData().getString("text1");String data2 = msg.getData().getString("text2");init(data1, data2);break;default:break;}}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(new MyView(this, this));}public void init(String str1, String str2) {//将获取的数据Toast出来Toast.makeText(MainActivity.this, str1 + '\n' + str2, Toast.LENGTH_SHORT).show();finish();}
}
在建一个Java类:
@SuppressLint("ViewConstructor")
public class MyView extends View {private MainActivity activity;public MyView(Context context, MainActivity activity) {super(context);this.activity = activity;}@SuppressLint("ClickableViewAccessibility")@Overridepublic boolean onTouchEvent(MotionEvent event) {int x = (int)event.getX();int y = (int)event.getY();Rect rect = new Rect(0, 0, 320, 480);if (rect.contains(x, y)) {Message message = new Message();message.what = MainActivity.FLAG;//新建Bundle的实例Bundle bundle = new Bundle();//往Bundle中传入数据bundle.putString("text1", "Trump want to ban TimTok");bundle.putString("text2", "Make America great again");//message利用bundle传递数据message.setData(bundle);//用activity中的handler发送消息activity.mHandler.sendMessage(message);}return super.onTouchEvent(event);}
}
运行程序,得到如下结果:
点击屏幕指定区域,得到如下结果: