Intent's delivery of complex data


Introduction to this section:

In the previous section we learned some basic uses of Intent, and learned about the seven properties of Intent, explicit Intent and Implicit Intents, and how to customize implicit Intents, and finally provide you with some commonly used system Intents! This section will explain to you the problem of Intent passing data~Okay, let’s start this section~


1. Intent passes simple data

Also Remember what we learned in Activity about how to pass simple data to each other between two Activities?

1.png

You can directly store the data by calling the putExtra() method of the Intent, and then call getXxxExtra after getting the Intent. Corresponding type of data; if multiple are passed, you can use the Bundle object as a container and first transfer the data by calling Bundle's putXxx Store it in the Bundle, then call the putExtras() method of the Intent to store the Bundle in the Intent, and then after obtaining the Intent, Call getExtras() to obtain the Bundle container, and then call its getXXX to obtain the corresponding data! In addition, data storage is somewhat similar to Map's <key, value>!


2.Intent passes the array

Hey, normal types are no problem, but what if it is an array? The solution is as follows:

Write array:

bd.putStringArray("StringArray", new String[]{"Hehe"," Haha"});
//StringArray can be replaced with other data types, such as int, float, etc...

Reading array:

String[] str = bd.getStringArray("StringArray")

3.Intent passes the collection

Well, the array is very simple Well, let's pass the collection again~ This is a little more complicated and will be handled according to the situation:


1) List<Basic data type or String>

Write collection:

##intent.putStringArrayListExtra(name, value)
intent.putIntegerArrayListExtra(name, value)

Read Collection:

intent.getStringArrayListExtra(name)
intent.getIntegerArrayListExtra(name)
##2) List< Object>

Force the list into a Serializable type, and then pass it in (Bundle can be used as a medium)

Write the collection:

putExtras(key, ( Serializable)list)
Read the collection:

(List<Object>) getIntent().getSerializable(key)

PS: The Object class needs to implement the Serializable interface


3) Map<String, Object>, or a more complex

solution is:Enclose a List in the outer layer

//Pass more complex parameters
Map<String, Object> map1 = new HashMap<String, Object>();
map1.put("key1", "value1");
map1.put("key2", "value2");
List<Map<String, Object>> list = new ArrayList<Map<String , Object>>();
list.add(map1);

Intent intent = new Intent();
intent.setClass(MainActivity.this,ComplexActivity.class);
Bundle bundle = new Bundle();

//A list must be defined to pass the ArrayList<Object> that needs to be passed in budnle. This is necessary
ArrayList bundlelist = new ArrayList() ;
bundlelist.add(list);
bundle.putParcelableArrayList("list",bundlelist);
intent.putExtras(bundle);
startActivity(intent);

4.Intent transfer object

There are two ways to transfer objects: convert the object into a Json string or serialize it through Serializable or Parcelable It is not recommended to use Android's built-in Json parser. You can use fastjson or Gson third-party library!


1) Convert the object to a Json string

Example of Gson parsing:

Model:

public class Author{
private int id;
private String name;
//...
}

public class Author{
private int id;
private String name;
//...
}

##Write data:

Book book=new Book();
book.setTitle("Java Programming Thoughts");
Author author=new Author();
author.setId(1);
author. setName("Bruce Eckel");
book.setAuthor(author);
Intent intent=new Intent(this,SecondActivity.class);
intent.putExtra("book",new Gson(). toJson(book));
startActivity(intent);

读取数据:

String bookJson=getIntent().getStringExtra("book");
Book book=new Gson().fromJson(bookJson,Book.class);
Log.d(TAG,"book title->"+book.getTitle());
Log.d(TAG,"book author name->"+book.getAuthor().getName());

2) Use Serializable, Parcelable to serialize objects


1. Serializable implementation:

①Business Bean implementation: Serializable Interface, write getter and setter methods
②Intent passes in the object instance by calling putExtra(String name, Serializable value) Of course, if there are multiple objects, we can also first Bundle.putSerializable(x,x);
③The new Activity calls the getSerializableExtra() method to obtain the object instance: eg:Product pd = (Product) getIntent().getSerializableExtra("Product");
④Call the object get method to obtain the corresponding parameters


2.Parcelable implementation:

General process:

①The business bean inherits the Parcelable interface, overrides the writeToParcel method, and serializes your object into a Parcel object;
②Rewrite the describeContents method, content interface description, return 0 by default
③Instantiate the static internal object CREATOR to implement the interface Parcelable.Creator
④In the same way, pass in the object instance through the putExtra() method of Intent , of course, if there are multiple objects, we can first Put it in Bundle Bundle.putParcelable(x,x), and then Intent.putExtras()

Some explanations:

Through writeToParcel Map your object into a Parcel object, and then map the Parcel object through createFromParcel become your object. You can also think of Parcel as a stream, and write objects into the stream through writeToParcel. Reading objects from the stream through createFromParcel, but this process requires you to implement it, so write The order and reading order must be consistent.

Code example for implementing Parcelable interface:

//Internal Description Interface,You do not need to manage  
@Override  
public int describeContents() {  
     return 0;  
}  
       
      
 
@Override  
public void writeToParcel(Parcel parcel, int flags){  
    parcel.writeString(bookName);  
    parcel.writeString(author);  
    parcel.writeInt(publishTime);  
}  
      

public static final Parcelable.Creator<Book> CREATOR = new Creator<Book>() {  
    @Override  
    public Book[] newArray(int size) {  
        return new Book[size];  
    }  
          
    @Override  
    public Book createFromParcel(Parcel source) {  
        Book mBook = new Book();    
        mBook.bookName = source.readString();   
        mBook.author = source.readString();    
        mBook.publishTime = source.readInt();   
        return mBook;  
    }  
};

Android Studio generates Parcleable plug-in:

Intellij/Andriod Studio plug-in android-parcelable-intellij-plugin As long as ALT+Insert, you can directly generate Parcleable interface code.

In addition: Parcelable objects are widely used in Android, and implementing the Parcable interface is very cumbersome. You can use Third-party open source framework: Parceler, I haven’t tried it yet because of problems with Maven.

Reference address:[Automatically generated by Android Parcelable]

3. Comparison of two serialization methods:

Comparison between the two:

  • 1) When using memory, Parcelable has higher performance than Serializable, so it is recommended to use Parcelable.
  • 2) Serializable will generate a large number of temporary variables during serialization, causing frequent GC.
  • 3) Parcelable cannot be used when data is to be stored on disk, because Parcelable cannot guarantee the integrity of the data. Continuity in the face of changes in the outside world. Although Serializable is less efficient, it is still recommended to use Serializable at this time.

5.Intent passes Bitmap

bitmap implements the Parcelable interface by default, you can pass it directly

Implementation code:

Bitmap bitmap = null;
Intent intent = new Intent();
Bundle bundle = new Bundle();
bundle.putParcelable("bitmap", bitmap);
intent.putExtra("bundle", bundle);

6. It is inconvenient to pass it back and forth, so define global data directly

If you are passing simple data and have such a demand, Activity1 -> Activity2 -> Activity3 - > Activity4, You want to pass certain data from Activity to Activity 4, how to do it? Do you want to pass it from page to page?

Obviously unscientific, right? If you want certain data to be available anywhere, you can consider using the Application global object!

The Android system creates an Application object when each program is running, and only one will be created, so Application It is a class in the singleton mode, and the life cycle of the Application object is the longest in the entire program. The period is equal to the life cycle of this program. If you want to store some more static values ​​(fixed and unchangeable, but can also be changed), if you want to use Application needs a custom class to implement the Application class and tell the system that it is our custom Application that is instantiated. Instead of the system default, this step is to add: name attribute to our application tag in AndroidManifest.xml!

Key part of the code:

1) Custom Application class:

class MyApp extends Application {
private String myState;
public String getState(){
return myState;
}
public void setState(String s){
myState = s;
}
}

2) Statement in AndroidManifest.xml:

##<application android:name=".MyApp" android:icon ="@drawable/icon"
android:label="@string/app_name">

3) Call where needed:

class Blah extends Activity {
@Override
public void onCreate(Bundle b){
...
MyApp appState = ((MyApp)getApplicationContext());
String state = appState.getState();
...
}
}

High-definition writing method

: The Application global object can be obtained at any location.


Applicaiton is a component of the system. It also has its own life cycle. We can get this in onCraete. Application object. Post the modified code!

class MyApp extends Application {
private String myState;
private static MyApp instance;
public static MyApp getInstance(){
return instance;
}
 
 
  public String getState(){
      return myState;
  }
                                                                                                                                                    use   use using use using using   using     using ’ ’ s using ’ ’s ’ s using ’ s through down through ’s using ’ s through down through ’s to ‐ ‐s-- myState = s;
}
                                                                                                                                                                                                                                                                          .

Then we can directly call: MyApp.getInstance() anywhere to get the global object of Application!


Note:

The Application object exists in memory, so it may be killed by the system, such as this Scenario:

We store the user account in the application in Activity1, and then obtain the user account in Activity2 and display it!

If we click the home button, and then after N long waits, the system will kill our app in order to reclaim memory. At this time, we re- Open this app, it's magical at this time, you return to the Activity2 page, but if you get the Application again at this time If the user account is entered, the program will report a NullPointerException and then crash~

The reason why the above crash occurs is because the Application object is newly created. You may think that the App is restarted. In fact, it is not, just create a new Application, and then start the Activity when the user left last time, thereby creating the App There is no illusion of being killed! Therefore, if it is more important data, it is recommended that you localize it. In addition, when using the data The value of the variable must be checked for non-nullity! Another point is: this is not only true for Application variables, but also for singleton objects and public static variables. This will also happen~


7. Parameter passing in singleton mode

The above Application is based on singleton. The characteristic of singleton mode is that it can ensure that the system A class has exactly one instance. This is very easy to achieve, setting parameters in A and accessing them directly in B. This is the most efficient of several methods.

Example code: (code comes from the Internet~)

①Define a singleton class:

public class XclSingleton
{
//Single mode instance
private static Create an instance
public synchronized static XclSingleton getInstance(){
if(instance == null){
instance = new XclSingleton(); stance;


Final HashMap & LT; String, Object & GT; Mmap;
Prive Xclsingleton ()
{
mmap = New HashMap & LT; Object & GT; ();
}

PUBLIC Void Put (String Key, Object Value) {
mmap.put (key, value);
}
#PUBLIC OBJECT (String Key)
{
Return mmap.get (key); ("key1", "value1");
XclSingleton.getInstance().put("key2", "value2");



Summary of this section:


Okay, that’s it for Intent complex data transmission. In addition to using Intent to transmit complex data, this section also teaches you Use Application and singleton patterns to pass parameters! I believe it will bring convenience to everyone in data transmission, thank you~