Получение результата из Activity

Последнее обновление: 16.10.2021

В прошлой теме было рассмотрено как вызывать новую Activity и передавать ей некоторые данные. Но мы можем не только передавать данные запускаемой activity, но и ожидать от нее некоторого результата работы.

К примеру, пусть у нас в проекте будут две activity: MainActivity и SecondActivity. А для каждой activity есть свой файл интерфейса: activity_main.xml и activity_second.xml соответственно.

startActivityForResult в Android и Java

В прошлой теме мы вызывали новую activity с помощью метода startActivity(). Для получения же результата работы запускаемой activity необходимо использовать Activity Result API.

Activity Result API предоставляет компоненты для регистрации, запуска и обработки результата другой Activity. Одним из преимуществ применения Activity Result API является то, что он отвязывает результат Activity от самой Activity. Это позволяет получить и обработать результат, даже если Activity, которая возвращает результат, в силу ограничений памяти или в силу других причин завершила свою работу. Вкратце рассмотрим основные моменты применения Activity Result API.

Регистрация функции для получения результата

Для регистрации функции, которая будет обрабатывать результат, Activity Result API предоставляет метод registerForActivityResult(). Этот метод в качестве параметров принимает объекты ActivityResultContract и ActivityResultCallback и возвращает объект ActivityResultLauncher, который применяется для запуска другой activity.

ActivityResultLauncher<I> registerForActivityResult (
				ActivityResultContract<I, O> contract, 
                ActivityResultCallback<O> callback)

ActivityResultContract определяет контракт: данные какого типа будут подаваться на вход и какой тип будет представлять результат.

ActivityResultCallback представляет интерфейс с единственным методом onActivityResult(), который определяет обработку полученного результата. Когда вторая activity закончит работу и возвратит результат, то будет как раз вызываться этот метод. Результат передается в метод в качестве параметра. При этом тип параметра должен соответствовать типу результата, определенного в ActivityResultContract. Например:

ActivityResultLauncher<Intent> mStartForResult = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
    new ActivityResultCallback<ActivityResult>() {
        @Override
        public void onActivityResult(ActivityResult result) {

            // обработка result
        }
});

Класс ActivityResultContracts предоставляет ряд встроенных типов контрактов. Например, в листинге кода выше применяется встроенный тип ActivityResultContracts.StartActivityForResult, который в качестве входного объекта устанавливает объект Intent, а в качестве типа результата - тип ActivityResult.

Запуск activity для получения результата

Метод registerForActivityResult() регистрирует функцию-колбек и возвращает объект ActivityResultLauncher. С помощью этого мы можем запустить activity. Для этого у объекта ActivityResultLauncher вызывается метод launch():

mStartForResult.launch(intent);

В метод lauch() передается объект того типа, который определен объектом ActivityResultContracts в качестве входного.

Практическое применение Activity Result API

Итак, определим в файле 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/textView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Укажите возраст"
        android:textSize="22sp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>
    <EditText
        android:id="@+id/age"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView"/>
    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="onClick"
        android:text="Отправить"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/age"/>

</androidx.constraintlayout.widget.ConstraintLayout>

Для ввода данных здесь определен элемент EditText, а для отправки - кнопка.

Определим в классе MainActivity запуск второй activity:

package com.example.viewapp;

import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    static final String AGE_KEY = "AGE";
    static final String ACCESS_MESSAGE="ACCESS_MESSAGE";

    ActivityResultLauncher<Intent> mStartForResult = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
            new ActivityResultCallback<ActivityResult>() {
                @Override
                public void onActivityResult(ActivityResult result) {

                    TextView textView = findViewById(R.id.textView);
                    if(result.getResultCode() == Activity.RESULT_OK){
                        Intent intent = result.getData();
                        String accessMessage = intent.getStringExtra(ACCESS_MESSAGE);
                        textView.setText(accessMessage);
                    }
                    else{
                        textView.setText("Ошибка доступа");
                    }
                }
            });
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    public void onClick(View view) {
        // получаем введенный возраст
        EditText ageBox = findViewById(R.id.age);
        String age = ageBox.getText().toString();

        Intent intent = new Intent(this, SecondActivity.class);
        intent.putExtra(AGE_KEY, age);

        mStartForResult.launch(intent);
    }
}

Вкратце рассмотрим главные моменты этого кода. Прежде всего, мы определяем объект ActivityResultLauncher, с помощью которого будем запускать вторую activity и передавать ей данные:

ActivityResultLauncher<Intent> mStartForResult = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
            new ActivityResultCallback<ActivityResult>() {
                @Override
                public void onActivityResult(ActivityResult result) {

                    TextView textView = findViewById(R.id.textView);
                    if(result.getResultCode() == Activity.RESULT_OK){
                        Intent intent = result.getData();
                        String accessMessage = intent.getStringExtra(ACCESS_MESSAGE);
                        textView.setText(accessMessage);
                    }
                    else{
                        textView.setText("Ошибка доступа");
                    }
                }
            });

Объект ActivityResultLauncher типизируется типом Intent, так как объект этого типа будет передаваться в метод launch() при запуске второй activity.

Тип контракта определяется типом ActivityResultContracts.StartActivityForResult, который и определяет тип Intent в качестве входного типа и тип ActivityResult в качестве типа результата.

Второй аргумент метода registerForActivityResult() - объект ActivityResultCallback типизируется типом результата - типом ActivityResult и определяет функцию-колбек onActivityResult(), которая получает результат и обрабатывает его. В данном случае обработка состоит в том, что мы выводим в текстовое поле ответ от второй activity.

При обработке мы проверяем полученный код результата:

if(result.getResultCode() == Activity.RESULT_OK)

В качестве результата, как правило, применяются встроенные константы Activity.RESULT_OK и Activity.RESULT_CANCELED. На уровне условностей Activity.RESULT_OK означает, что activity успешно обработала запрос, а Activity.RESULT_CANCELED - что activity отклонила обработку запроса.

С помощью метода getData() результата получаем переданные из второй activity данные в виде объекта Intent:

Intent intent = result.getData();

Далее извлекаем из Intent строку, которая имеют ключ ACCESS_MESSAGE, и выводим ее в текстовое поле.

Таким образом, мы определили объект ActivityResultLauncher. Далее в обработчике нажатия onClick с помощью этого объекта запускаем вторую activity - SecondActivity:

public void onClick(View view) {
    // получаем введенный возраст
    EditText ageBox = findViewById(R.id.age);
    String age = ageBox.getText().toString();

    Intent intent = new Intent(this, SecondActivity.class);
    intent.putExtra(AGE_KEY, age);

    mStartForResult.launch(intent);
}

В обработчике нажатия кнопки onClick() получаем введенный в текстовое поле возраст, добавляем его в объект Intent с ключем AGE_KEY и запускаем SecondActivity с помощью метода launch()

Теперь перейдем к SecondActivity и определим в файле activity_second.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/ageView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:textSize="26sp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <Button
        android:id="@+id/button1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Открыть доступ"
        android:onClick="onButton1Click"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/ageView"/>

    <Button
        android:id="@+id/button2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Отклонить доступ"
        android:onClick="onButton2Click"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/button1"/>

    <Button
        android:id="@+id/button3"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Возраст недействителен"
        android:onClick="onButton3Click"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/button2" />

    <Button
        android:id="@+id/cancel"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Отмена"
        android:onClick="onCancelClick"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/button3" />

</androidx.constraintlayout.widget.ConstraintLayout>

А в классе 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.TextView;

public class SecondActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        Bundle extras = getIntent().getExtras();
        if (extras != null) {
            TextView ageView = findViewById(R.id.ageView);
            String age = extras.getString(MainActivity.AGE_KEY);
            ageView.setText("Возраст: " +  age);
        }
    }
    public void onCancelClick(View v) {
        setResult(RESULT_CANCELED);
        finish();
    }
    public void onButton1Click(View v) {
        sendMessage("Доступ разрешен");
    }
    public void onButton2Click(View v) {
        sendMessage("Доступ запрещен");
    }
    public void onButton3Click(View v) {
        sendMessage("Недопустимый возраст");
    }
    private void sendMessage(String message){

        Intent data = new Intent();
        data.putExtra(MainActivity.ACCESS_MESSAGE, message);
        setResult(RESULT_OK, data);
        finish();
    }
}

Три кнопки вызывают метод sendMessage(), в который передают отправляемый ответ. Это и будет то сообщение, которое получить MainActivity в методе onActivityResult.

Для возврата результата необходимо вызвать метод setResult(), в который передается два параметра:

  • числовой код результата

  • отправляемые данные

После вызова метода setResult() нужно вызвать метод finish, который уничтожит текущую activity.

Одна кнопка вызывает обработчик onCancelClick(), в котором передается в setResult только код результата - RESULT_CANCELED.

То есть условно говоря, мы получаем в SecondActivity введенный в MainActivity возраст и с помощью нажатия определенной кнопки возвращаем некоторый результат в виде сообщения.

В зависимости от нажатой кнопки на SecondActivity мы будем получать разные результаты в MainActivity:

Получение результата из Activity в Android и Java Метод startActivityForResult в Android и Java
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850