Передача даних між Activity. Серіалізація

Для передачі даних між двома Activity використовується об'єкт Intent. Через його метод putExtra() можна додати ключ і пов'язане з ним значення.

Наприклад, передача з поточної Activity в SecondActivity рядка "Hello World" з ключем "hello":

// створення об'єкта Intent для запуску SecondActivity
Intent intent = new Intent(this, SecondActivity.class);
// передача об'єкта з ключем "hello" та значенням "Hello World"
intent.putExtra("hello", "Hello World");
// запуск SecondActivity
startActivity(intent);

Для передачі даних застосовується метод putExtra(), який дозволяє передавати дані простих типів: String, int, float, double, long, short, byte, char, масиви цих типів, або об'єкти інтерфейсу Serializable.

Отримання даних в SecondActivity

Щоб отримати відправлені дані під час завантаження SecondActivity, можна скористатися методом get(), в який передається ключ об'єкта:

Bundle arguments = getIntent().getExtras();
String name = arguments.get("hello").toString();    // Hello World

Залежно від типу відправлених даних, при їх отриманні можна використовувати ряд методів об'єкта Bundle. Всі вони як параметр приймають ключ об'єкта. Основні з них:

  • get(): універсальний метод, який повертає значення типу Object. Відповідно, для отриманого значення необхідно виконати перетворення до потрібного типу.
  • getString(): повертає об'єкт типу String.
  • getInt(): повертає значення типу int.
  • getByte(): повертає значення типу byte.
  • getChar(): повертає значення типу char.
  • getShort(): повертає значення типу short.
  • getLong(): повертає значення типу long.
  • getFloat(): повертає значення типу float.
  • getDouble(): повертає значення типу double.
  • getBoolean(): повертає значення типу boolean.
  • getCharArray(): повертає масив об'єктів типу char.
  • getIntArray(): повертає масив об'єктів типу int.
  • getFloatArray(): повертає масив об'єктів типу float.
  • getSerializable(): повертає об'єкт інтерфейсу Serializable.

Нехай у нашому проекті будуть визначені дві Activity: MainActivity і SecondActivity.

У SecondActivity визначимо отримання даних:

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

        Bundle arguments = getIntent().getExtras();

        if(arguments != null) {
            String name = arguments.get("name").toString();
            String company = arguments.getString("company");
            int age = arguments.getInt("age");
            textView.setText("Name: " + name + "\nCompany: " + company +
                    "\nAge: " + age);
        }

        setContentView(textView);
    }
}

У цьому прикладі в SecondActivity ми отримуємо всі дані з об'єкта Bundle та виводимо їх у текстове поле TextView. Передбачається, що в цю Activity будуть передані три елементи: дві строки з ключами name і company, а також число з ключем age.

Тепер визначимо передачу даних у SecondActivity. Наприклад, для 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>

Тут визначено три текстові поля для введення даних і кнопка для відправки.

Тепер, коли користувач заповнить поля у MainActivity, ми можемо передати введені дані у SecondActivity, використовуючи Intent. Для цього в обробнику кнопки у MainActivity додаємо код:

public void onClick(View view) {
    EditText nameEditText = findViewById(R.id.name);
    EditText companyEditText = findViewById(R.id.company);
    EditText ageEditText = findViewById(R.id.age);

    String name = nameEditText.getText().toString();
    String company = companyEditText.getText().toString();
    int age = Integer.parseInt(ageEditText.getText().toString());

    Intent intent = new Intent(this, SecondActivity.class);
    intent.putExtra("name", name);
    intent.putExtra("company", company);
    intent.putExtra("age", age);

    startActivity(intent);
}

Тепер при натисканні на кнопку дані з MainActivity будуть передані у SecondActivity.

У класі MainActivity визначаємо наступне вміст:

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

        Intent intent = new Intent(this, SecondActivity.class);
        intent.putExtra("name", name);
        intent.putExtra("company", company);
        intent.putExtra("age", age);
        startActivity(intent);
    }
}

В обробнику натискання кнопки ми отримуємо введені в текстові поля EditText дані та передаємо їх в об'єкт Intent за допомогою методу putExtra(). Потім запускаємо SecondActivity.

У підсумку, при натисканні на кнопку, буде запущена SecondActivity, яка отримає деякі введені дані з текстових полів.

Передача складних об'єктів

У наведеному вище прикладі передавались прості дані — числа, рядки. Але також ми можемо передавати більш складні дані. Для цього використовується механізм серіалізації. Для цього натискаємо правою кнопкою миші на папку пакета, де знаходяться класи MainActivity та SecondActivity, і в контекстному меню вибираємо New -> Java Class:

Назвемо новий клас User - нехай він представлятиме користувача.

Передача складних об'єктів

Нехай клас User має наступний код:

package com.example.viewapp;

import java.io.Serializable;

public class User implements Serializable {

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

    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;
    }
}

Зверніть увагу, що цей клас реалізує інтерфейс Serializable. Тепер змінюємо код MainActivity:

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 = new User(name, company, age);

        Intent intent = new Intent(this, SecondActivity.class);
        intent.putExtra(User.class.getSimpleName(), user);
        startActivity(intent);
    }
}

Тепер замість трьох окремих даних передається один об'єкт User. У якості ключа використовується результат методу User.class.getSimpleName(), який фактично повертає назву класу.

І змінюємо клас SecondActivity:

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);
        //setContentView(R.layout.activity_second);
        TextView textView = new TextView(this);
        textView.setTextSize(26);
        textView.setPadding(16, 16, 16, 16);

        Bundle arguments = getIntent().getExtras();

        User user;
        if(arguments != null){
            user = (User) arguments.getSerializable(User.class.getSimpleName());

            textView.setText("Name: " + user.getName() + "\nCompany: " + user.getCompany() +
                    "\nAge: " + String.valueOf(user.getAge()));
        }
        setContentView(textView);
    }
}

Для отримання даних застосовується метод getSerializable(), оскільки клас User реалізує інтерфейс Serializable. Таким чином, ми можемо передавати один об'єкт замість набору окремих даних.