Parcelable

Можливість серіалізації об'єктів надається безпосередньо інфраструктурою мови Java. Однак Android також надає інтерфейс Parcelable, який по суті також дозволяє серіалізувати об'єкти, як і Serializable, але є більш оптимізованим для Android. Такі об'єкти Parcelable також можна передавати між двома Activity або використовувати іншими способами.

Наприклад, у попередній темі дані передавалися між Activity у вигляді об'єктів User, які використовували серіалізацію. Тепер нехай клас User застосовує інтерфейс Parcelable:

package com.example.viewapp;

import android.os.Parcel;
import android.os.Parcelable;

public class User implements Parcelable {

    private String name;
    private String company;
    private int age;

    public static final Creator<User> CREATOR = new Creator<User>() {
        @Override
        public User createFromParcel(Parcel source) {
            String name = source.readString();
            String company = source.readString();
            int age = source.readInt();
            return new User(name, company, age);
        }

        @Override
        public User[] newArray(int size) {
            return new User[size];
        }
    };

    public User(String name, String company, int age){
        this.name = name;
        this.company = company;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getCompany() {
        return company;
    }

    public void setCompany(String company) {
        this.company = company;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeString(company);
        dest.writeInt(age);
    }
}

Інтерфейс android.os.Parcelable передбачає реалізацію двох методів: describeContents() та writeToParcel(). Перший метод описує вміст і повертає певне числове значення. Другий метод записує в об'єкт Parcel вміст об'єкта User.

Для запису даних об'єкта в Parcel використовується ряд методів, кожен з яких призначений для певного типу даних. Основні методи:

  • writeString() — записує рядок.
  • writeInt() — записує ціле число.
  • writeFloat() — записує число з плаваючою комою (тип float).
  • writeDouble() — записує число з плаваючою комою подвійної точності (тип double).
  • writeByte() — записує байт.
  • writeLong() — записує довге ціле число.
  • writeIntArray() — записує масив цілих чисел.
  • writeValue() — записує об'єкт типу Object.
  • writeParcelable() — записує об'єкт типу Parcelable.

Крім того, об'єкт Parcelable повинен містити статичне поле CREATOR, яке представляє об'єкт Creator. Цей об'єкт реалізує два методи. Вони необхідні для створення раніше серіалізованих даних вихідних об'єктів типу User.

  • Метод newArray() створює масив об'єктів User.
  • Метод createFromParcel() створює з Parcel новий об'єкт типу User. Тобто цей метод є протилежним за дією методу writeToParcel.

Для отримання даних з Parcel застосовуються методи типу readString(), readInt(), readParcelable() та інші — для читання певних типів даних.

Важливо зазначити, що дані в методі createFromParcel() зчитуються з об'єкта Parcel саме в тому порядку, в якому вони додаються в цей об'єкт у методі writeToParcel().

Отримання об'єкта Parcelable в Android

У SecondActivity, яка є наступним екраном, ми отримаємо об'єкт User:

package com.example.viewapp;

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

public class SecondActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
         
        TextView textView = new TextView(this);
        textView.setTextSize(26);
        textView.setPadding(16, 16, 16, 16);

        // Отримуємо додаткові дані з Intent
        Bundle arguments = getIntent().getExtras();

        User user;
        if(arguments != null){
            // Читаємо об'єкт User із Parcel
            user = arguments.getParcelable(User.class.getSimpleName());

            // Виводимо інформацію про користувача
            textView.setText("Name: " + user.getName() + "\nCompany: " + user.getCompany() +
                    "\nAge: " + String.valueOf(user.getAge()));
        }
        setContentView(textView);
    }
}

Ключові моменти:

  1. Для отримання об'єкта Parcelable, переданого між Activity, використовуємо метод getParcelable(). Для цього не потрібно проводити приведення типів, оскільки Parcelable вже визначає тип даних.
  2. Якщо у Bundle є додаткові дані (це перевіряється через arguments != null), ми витягуємо об'єкт User за допомогою arguments.getParcelable(), передаючи User.class.getSimpleName() як ключ.
  3. Далі ми виводимо значення полів об'єкта User у TextView.

XML для MainActivity

У файлі activity_main.xml визначаємо простий інтерфейс для введення даних користувача:

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
 
    <TextView
        android:id="@+id/nameLabel"
        android:layout_width="0dp"
        android:layout_height="20dp"
        android:text="Name:"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>
    <EditText
        android:id="@+id/name"
        android:layout_width="0dp"
        android:layout_height="40dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/nameLabel"/>
    <TextView
        android:id="@+id/companyLabel"
        android:layout_width="0dp"
        android:layout_height="20dp"
        android:text="Company:"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/name"/>
    <EditText
        android:id="@+id/company"
        android:layout_width="0dp"
        android:layout_height="40dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/companyLabel" />
    <TextView
        android:id="@+id/ageLabel"
        android:layout_width="0dp"
        android:layout_height="20dp"
        android:text="Age:"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/company"/>
    <EditText
        android:id="@+id/age"
        android:layout_width="0dp"
        android:layout_height="40dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/ageLabel"/>
    <Button
        android:id="@+id/btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="onClick"
        android:text="Save"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/age"/>
</androidx.constraintlayout.widget.ConstraintLayout>

У цьому XML визначено кілька TextView та EditText для введення імені, компанії та віку, а також кнопку для збереження даних.


Передача даних в SecondActivity

У MainActivity ми реалізуємо передачу даних у SecondActivity:

package com.example.viewapp;

import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void onClick(View v) {
        // Отримуємо введені дані
        EditText nameText = findViewById(R.id.name);
        EditText companyText = findViewById(R.id.company);
        EditText ageText = findViewById(R.id.age);

        String name = nameText.getText().toString();
        String company = companyText.getText().toString();
        int age = Integer.parseInt(ageText.getText().toString());

        // Створюємо об'єкт User
        User user = new User(name, company, age);

        // Створюємо Intent для передачі даних у SecondActivity
        Intent intent = new Intent(this, SecondActivity.class);
        intent.putExtra(User.class.getSimpleName(), user); // Передаємо об'єкт User

        // Запускаємо SecondActivity
        startActivity(intent);
    }
}

Опис:

  1. Ми отримуємо значення з EditText за допомогою findViewById.
  2. Створюємо об'єкт User з введених даних.
  3. Використовуємо Intent для передачі об'єкта User в SecondActivity за допомогою методу putExtra().
  4. У SecondActivity об'єкт отримується через getParcelable() і виводиться на екран.

Це базова реалізація передачі даних між Activity за допомогою Parcelable.