Easy Tutorial
❮ Programmer Joke 24 Java Init Object Process ❯

4.5.2 Intent and Complex Data Transfer

Category Android Basic Tutorial

Introduction to This Section:

>

In the previous section, we learned about the basic usage of Intent, understood its seven attributes, the use of explicit and implicit Intents, how to customize implicit Intents, and finally provided some commonly used system Intents! This section will discuss how to transfer data using Intent. Let's get started with this section's content.


1. Transferring Simple Data with Intent

>

Do you remember how we learned to transfer simple data between two Activities?

You can directly store data by calling the putExtra() method of Intent, and then retrieve the data by calling getXxxExtra after obtaining the Intent. For multiple data items, you can use a Bundle object as a container. Store the data in the Bundle by calling putXxx, then store the Bundle in the Intent by calling putExtras(). After obtaining the Intent, call getExtras() to retrieve the Bundle container, and then call getXXX to retrieve the corresponding data. The data storage is somewhat similar to a Map's <key, value> structure.


2. Transferring Arrays with Intent

>

Handling arrays is straightforward:

Writing Arrays:

bd.putStringArray("StringArray", new String[]{"呵呵","哈哈"});
// You can replace StringArray with other data types like int, float, etc.

Reading Arrays:

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

3. Transferring Collections with Intent

>

Transferring collections is a bit more complex and depends on the type:


1) List<Basic Data Type or String>

Writing Collections:

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

Reading Collections:

intent.getStringArrayListExtra(name);
intent.getIntegerArrayListExtra(name);

2) List<Object>

Cast the list to Serializable type and then pass it (using Bundle as a medium):

Writing Collections:

putExtras(key, (Serializable)list);

Reading Collections:

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

Note: The Object class needs to implement the Serializable interface.


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

The solution is to wrap it in a List:

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

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

// Define a list to pass the ArrayList<Object> in the bundle, which is necessary
ArrayList bundlelist = new ArrayList();
bundlelist.add(list);
bundle.putParcelableArrayList("list", bundlelist);
intent.putExtras(bundle);
startActivity(intent);

4. Transferring Objects with Intent

There are two ways to transfer objects: converting the object to a JSON string or using serialization with Serializable or Parcelable. It is not recommended to use Android's built-in JSON parser; instead, use third-party libraries like fastjson or Gson.


1) Converting Objects to JSON Strings

Example using Gson:

Model:

public class Book {
    private int id;
    private String title;
    //...
}

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

Writing 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);

Reading Data:

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) Using Serializable or Parcelable for Object Serialization


1. Serializable Implementation:

>

The business bean implements the Serializable interface and includes getter and setter methods.


2. Parcelable Implementation:

General Process:

>

The business bean inherits the Parcelable interface and overrides the writeToParcel method to serialize the object into a Parcel object.

Explanation:

>

By writing the object to a Parcel with writeToParcel, and then recreating the object from the Parcel with createFromParcel, you map the object to a Parcel and back. Think of the Parcel as a stream; write the object to the stream with writeToParcel, and read it back with createFromParcel. The process must be consistent in order and implemented by you.

Example Code 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 Plugin for Generating Parcelable Code:

Use the Intellij/Android Studio plugin android-parcelable-intellij-plugin. Simply press ALT+Insert to generate the Parcelable interface code automatically.

Additionally, Android extensively uses Parcelable objects, and implementing the Parcelable interface can be tedious. You can use third-party frameworks like Parceler, although Maven issues may prevent immediate use.

Reference: Android Parcelable Auto-Generation

Comparison of the Two Serialization Methods:


5. Transferring Bitmap with Intent

Since Bitmap implements the Parcelable interface by default, it can be directly transferred.

Example Code:

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

6. Using Global Data for Convenience

>

If you need to pass simple data through multiple activities (e.g., Activity1 -> Activity2 -> Activity3 -> Activity4), and you want to pass some data to Activity4, it would be impractical to pass it through each activity.

Instead, you can consider using the Application global object to store data that needs to be accessible from anywhere.

The Application object is created by the Android system when the program starts and is the only one created, making it a singleton. The Application object has the longest lifecycle in the program, equal to the program's lifecycle. If you need to store values that are static (or can change), and you want to access them globally, you can use the Application object. To use a custom Application class, you need to extend the Application class and inform the system to instantiate our custom Application instead of the default one. This is done by adding the name attribute to our application tag in the AndroidManifest.xml.

Key Code Sections:

1) Custom Application Class:

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

2) Declaration in AndroidManifest.xml:

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

3) Calling in Required Places:

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

Advanced Approach:

The Application component has its own lifecycle, and we can obtain the Application object in the onCreate method. Here's 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;
    }
    public void setState(String s){
        myState = s;
    }

    @Override
    public void onCreate(){
        super.onCreate();
        instance = this;
    }
}

You can then call MyApp.getInstance() from anywhere to get the global Application object.


Important Notes:

The Application object resides in memory and can be killed by the system to reclaim memory. For example, if you store a user account in the Application object in Activity1 and retrieve it in Activity2, the app might crash if the system kills the app and a new Application object is created when the app is reopened. This can lead to a NullPointerException. It's crucial to localize important data and perform null checks when accessing variables. This issue also applies to singleton objects and public static variables.


7. Singleton Pattern for Parameter Passing

The Application example above is based on the singleton pattern, which ensures that only one instance of a class exists in the system. This allows for efficient parameter setting in one place and accessing them elsewhere.

Example Code:

① Define a Singleton Class:

public class XclSingleton  
{  
    private static XclSingleton instance = null;  

    public synchronized static XclSingleton getInstance(){  
        if(instance == null){  
            instance = new XclSingleton();  
        }     
        return instance;  
    }     

    final HashMap&lt;String, Object> mMap;  
    private XclSingleton()  
    {  
        mMap = new HashMap<String,Object>();  
    }  

    public void put(String key,Object value){  
        mMap.put(key,value);  
    }  

    public Object get(String key)  
    {  
        return mMap.get(key);  
    }  
}

② Set Parameters:

XclSingleton.getInstance().put("key1", "value1");  
XclSingleton.getInstance().put("key2", "value2");

Summary:

This section covered complex data transmission using Intent, as well as parameter passing using Application and the singleton pattern. These methods should simplify data transmission and are highly efficient. Thank you for reading.


Tutorial Links:

-1.0 Android Basic Beginner Tutorial

-1.0.1 2015 Latest Android Basic Beginner Tutorial Contents

-1.1 Background and System Architecture Analysis

-1.2 Development Environment Setup

-1.2.1 Using Eclipse + ADT + SDK to Develop Android APP

-1.2.2 Using Android Studio to Develop Android APP

-1.3 Solving SDK Update Issues

-1.4 Genymotion Emulator Installation

-1.5.1 Git Tutorial for Basic Local Repository Operations

-1.5.2 Git: Setting Up a Remote Repository on GitHub

-1.6 How to Use 9-Patch Images

-1.7 Interface Prototype Design

-1.8 Project Source Analysis (Various Files, Resource Access)

-1.9 Android App Signing and Packaging

-1.11 Decompiling APK to Retrieve Code & Resources

-2.1 Concepts of View and ViewGroup

-2.2.1 LinearLayout (Linear Layout)

-2.2.2 RelativeLayout (Relative Layout)

-2.2.3 TableLayout (Table Layout)

-2.2.4 FrameLayout (Frame Layout)

-2.2.5 GridLayout (Grid Layout)

-2.2.6 AbsoluteLayout (Absolute Layout)

-2.3.1 Detailed Explanation of TextView (Text Box)

-2.3.2 Detailed Explanation of EditText (Input Box)

-2.3.3 Button and ImageButton (Image Button)

-2.3.4 ImageView (Image View)

-2.3.5.RadioButton (Radio Button) & Checkbox (Checkbox)

-2.3.6 ToggleButton and Switch (Toggle Switch)

-2.3.7 ProgressBar (Progress Bar)

-2.3.8 SeekBar (Drag Bar)

-2.3.9 RatingBar (Star Rating Bar)

-2.4.1 ScrollView (Scroll Bar)

-2.4.2 Date & Time Components (Part 1)

-2.4.3 Date & Time Components (Part 2)

-2.4.4 Adapter Basics

-2.4.5 Simple Usage of ListView

Follow on WeChat

❮ Programmer Joke 24 Java Init Object Process ❯