Android Notes (4) Optimization of serializable data transfer between Activities

Pass serializable data between activities

Android application development will often deal with the serialization and transfer of data. In Android, two methods are often used to realize the serializability of data: (1) implement the java.io.Serializable interface (2) implement the android.os.Parcelable interface.
The method of defining a class as the android.os.Parcelable interface actually uses Parcel to provide a set of mechanisms to decompose a complete object, and each part of the decomposed data is Belongs to the data type supported by Intent. The decomposed serializable data can be written to a shared memory, and other processes can read the byte stream from this shared memory through Parcel and deserialize it into objects. In this way, the function of passing objects can be realized. . Because this data transfer method is more efficient, it has become the main way for Android to transfer serializable data.
Insert image description here
Now there is a simple example, which is to send different types of data objects from the main activity MainActivity to two different activities, such as sending Student type data objects to FirstActivity and Teacher type data. The object is sent to SecondActivity. The running effect is as shown in the figure below:
Insert image description here

1. Define and implement the Parcelable data class

1.Student class

data class Student(val id:String,val name:String,val gender:String,val className:String):Parcelable{
    
    
    constructor(parcel: Parcel) : this(
        parcel.readString()!!,
        parcel.readString()!!,
        parcel.readString()!!,
        parcel.readString()!!
    )

    override fun describeContents(): Int=0

    override fun writeToParcel(dest: Parcel, flags: Int) {
    
    
        dest.writeString(id)
        dest.writeString(name)
        dest.writeString(gender)
        dest.writeString(className)
    }

    companion object CREATOR : Parcelable.Creator<Student> {
    
    
        override fun createFromParcel(parcel: Parcel): Student {
    
    
            return Student(parcel)
        }

        override fun newArray(size: Int): Array<Student?> {
    
    
            return arrayOfNulls(size)
        }
    }
}

2. Combine with kotlin-parcelize plug-in to simplify the definition of data classes

The definition form of the above-mentioned serializable data class is very complex, and the definition of the data class can be simplified by combining the kotlin-parcelize plug-in. To use the kotlin-parcelize plug-in, you need to add the processing of the kotlin-parcelize plug-in in the build.gradle.kts corresponding to the module:

plugins {

id (“kotlin-parcelize”)
}

After synchronization configuration, modify the above-mentioned Student class and Teacher class to the following form:
Modify the Student class to:

@Parcelize
data class Student(val id:String,val name:String,val gender:String,val className:String):Parcelable

The Teacher class defined is as follows:

@Parcelize
data class Teacher(val id:String,val name:String,val gender:String):Parcelable

2. Define the interface combined with JetPack Compose components

1. Define MainActivity and its corresponding interface

class MainActivity : ComponentActivity() {
    
    
    override fun onCreate(savedInstanceState: Bundle?) {
    
    
        super.onCreate(savedInstanceState)
        setContent {
    
    
                    MainScreen()
        }
    }
}

@Composable
fun MainScreen(modifier: Modifier = Modifier) {
    
    
    val context = LocalContext.current
    Box(contentAlignment= Alignment.Center){
    
    
        Column(horizontalAlignment = Alignment.CenterHorizontally){
    
    
            Button(modifier = Modifier.width(200.dp),onClick={
    
    
                val intent = Intent(context,FirstActivity::class.java)
                intent.putExtra("data",
                    Student("20234454","张三","男","计算机2231班"))
                context.startActivity(intent)
            }){
    
    
                Text(text = "FirstActivity",fontSize = 18.sp)
                Icon(imageVector=Icons.Filled.ArrowForward,contentDescription = "第一个活动")
            }

            Button(modifier = Modifier.width(200.dp),onClick={
    
    
                val intent = Intent(context,SecondActivity::class.java)
                intent.putExtra("data",Teacher("20234458","李四","男"))
                context.startActivity(intent)
            }){
    
    
                Text(text = "SecondActivity",fontSize = 18.sp)
                Icon(imageVector=Icons.Filled.ArrowForward,contentDescription = "第二个活动")
            }
        }
    }
}

In MainActivity, data is sent to different activities through two buttons, and the classes of the data objects sent are different.

2. Accept the passed data in the traditional way

The traditional way is to accept data of a specified type by specifically specifying the type.
Take FirstActivity receiving data as an example:

class FirstActivity : ComponentActivity()  {
    
    
    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
    override fun onCreate(savedInstanceState: Bundle?) {
    
    
        super.onCreate(savedInstanceState)
        setContent{
    
    
            FirstScreen()
        }
    }
}

@RequiresApi(Build.VERSION_CODES.TIRAMISU)
@Composable
fun FirstScreen(){
    
    
    val context = LocalContext.current as Activity
    val receivedData = context.intent.getParcelableExtra("data",Student::class.java)
    Box(modifier= Modifier
        .fillMaxSize()
        .background(Color.Green),
        contentAlignment = Alignment.Center){
    
    
        Text( text ="第一个界面,接受数据是${receivedData}",fontSize=30.sp,color = Color.Yellow)
    }
}

Take SecondActivity as an example:

class SecondActivity : ComponentActivity()  {
    
    
    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
    override fun onCreate(savedInstanceState: Bundle?) {
    
    
        super.onCreate(savedInstanceState)
        setContent{
    
    
            SecondScreen()
        }
    }
}

@RequiresApi(Build.VERSION_CODES.TIRAMISU)
@Composable
fun SecondScreen(){
    
    
    val context = LocalContext.current as Activity
    val receivedData = context.intent.getParcelableExtra("data",Teacher::class.java)
    Box(modifier= Modifier
        .fillMaxSize()
        .background(Color.Green),
        contentAlignment = Alignment.Center){
    
    
        Text( text ="第二个界面,接受数据是${receivedData}",fontSize=30.sp,color = Color.Yellow)
    }
}

Observing the interfaces corresponding to the above two activities, we can find that they mainly process (1) different colors of the front and rear foregrounds; (2) different types of data received and transferred; (3) different content of the displayed text. Other specific operations are very similar. Therefore, consider simplifying the code and defining a common interface function.

3. Define a common interface to simplify processing

Define the general interface combination function SubScreen as follows:

@RequiresApi(Build.VERSION_CODES.TIRAMISU)
@Composable
fun <T:Parcelable> SubScreen(title:String,
                             preColor:Color,
                             backgroundColor:Color,
                             receivedDataType:Class<T>){
    
    
    val context = LocalContext.current as Activity
    val data = context.intent.getParcelableExtra("data",receivedDataType)
    Box(modifier= Modifier
        .fillMaxSize()
        .background(backgroundColor),
        contentAlignment = Alignment.Center){
    
    
        Text( text ="$title,接受数据是${data}",fontSize=30.sp,color = preColor)
    }
}

Convert the different contents of the two interfaces: (1) Different colors of the front and rear background; (2) Different data types accepted and passed; pass them in the form of parameters.
In the above code, T represents the type parameter that implements the interface Parcelable, and then specifies the type parameter that accepts data. receivedDataType is set to a universal representation: Class. After such processing, when receiving data, it is achieved that no matter what type the data object sent by the sender is, as long as it implements the android.os.Parcelable interface, it can directly accept object instances of this type.

val context = LocalContext.current as Activity
val data = context.intent.getParcelableExtra(“data”,receivedDataType)

By doing this, the code will be simpler.

4. Different activities call a common interface

Remodify FirstActivity and call the SubScreen function to define the interface. The code is as follows:

class FirstActivity : ComponentActivity()  {
    
    
    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
    override fun onCreate(savedInstanceState: Bundle?) {
    
    
        super.onCreate(savedInstanceState)
        setContent{
    
    
            SubScreen(title = "第一个界面", backgroundColor=Color.Green,
                preColor = Color.Yellow, receivedDataType = Student::class.java)
        }
    }
}

Remodify SecondActivity and call the SubScreen function to define the interface. The code is as follows:

class SecondActivity : ComponentActivity()  {
    
    
    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
    override fun onCreate(savedInstanceState: Bundle?) {
    
    
        super.onCreate(savedInstanceState)
        setContent{
    
    
            SubScreen(title = "第二个界面", backgroundColor = Color.Blue,
            preColor = Color.Yellow, receivedDataType = Teacher::class.java)
        }
    }
}

references

**Chen Yi "Android Mobile Application Development (Micro Course Edition)" [M] Beijing: Tsinghua University Press 2022

Guess you like

Origin blog.csdn.net/userhu2012/article/details/133747681