В этом уроке:
- разбираемся, зачем нужны requestCode и resultCode в onActivityResult
На прошлом уроке мы поверхностно рассмотрели, как вызвать Activity, и как сделать так, чтобы она вернула результат. Рассмотрим немного подробней этот механизм. Создадим приложение, которое будет вызывать два разных Activity и получать от них результат. Как мы помним, результат приходит в метод onActivityResult. И requestCode используется, чтобы отличать друг от друга пришедшие результаты. А resultCode – позволяет определить успешно прошел вызов или нет.
Создадим проект:
Project name: P0301_ActivityResult
Build Target: Android 2.3.3
Application name: ActivityResult
Package name: ru.startandroid.develop.p0301activityresult
Create Activity: MainActivity
Нарисуем экран в main.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <TextView android:id="@+id/tvText" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:gravity="center_horizontal" android:text="Hello World" android:textSize="20sp"> </TextView> <LinearLayout android:id="@+id/linearLayout1" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="20dp" android:orientation="horizontal"> <Button android:id="@+id/btnColor" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginRight="5dp" android:layout_weight="1" android:text="Color"> </Button> <Button android:id="@+id/btnAlign" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="5dp" android:layout_weight="1" android:text="Alignment"> </Button> </LinearLayout> </LinearLayout>
На экране TextView с текстом. И две кнопки для выбора цвета шрифта и выравнивания текста в TextView. Нажатие на кнопку будет вызывать Activity для выбора и получать обратно результат.
Давайте начнем кодить в MainActivity.java:
package ru.startandroid.develop.p0301activityresult; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; public class MainActivity extends Activity implements OnClickListener { TextView tvText; Button btnColor; Button btnAlign; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); tvText = (TextView) findViewById(R.id.tvText); btnColor = (Button) findViewById(R.id.btnColor); btnAlign = (Button) findViewById(R.id.btnAlign); btnColor.setOnClickListener(this); btnAlign.setOnClickListener(this); } @Override public void onClick(View v) { // TODO Auto-generated method stub } }
Определили экранные элементы, прописали обработчик кнопкам и пока остановимся на этом.
Создадим два других Activity. Начнем с Activity для выбора цвета. Создадим layout-файл color.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <Button android:id="@+id/btnRed" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="5dp" android:layout_weight="1" android:text="Red"> </Button> <Button android:id="@+id/btnGreen" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="5dp" android:layout_weight="1" android:text="Green"> </Button> <Button android:id="@+id/btnBlue" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="5dp" android:layout_weight="1" android:text="Blue"> </Button> </LinearLayout>
Создаем класс ColorActivity. ColorActivity.java:
package ru.startandroid.develop.p0301activityresult; import android.app.Activity; import android.content.Intent; import android.graphics.Color; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class ColorActivity extends Activity implements OnClickListener { Button btnRed; Button btnGreen; Button btnBlue; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.color); btnRed = (Button) findViewById(R.id.btnRed); btnGreen = (Button) findViewById(R.id.btnGreen); btnBlue = (Button) findViewById(R.id.btnBlue); btnRed.setOnClickListener(this); btnGreen.setOnClickListener(this); btnBlue.setOnClickListener(this); } @Override public void onClick(View v) { Intent intent = new Intent(); switch (v.getId()) { case R.id.btnRed: intent.putExtra("color", Color.RED); break; case R.id.btnGreen: intent.putExtra("color", Color.GREEN); break; case R.id.btnBlue: intent.putExtra("color", Color.BLUE); break; } setResult(RESULT_OK, intent); finish(); } }
Как обычно определяем элементы, присваиваем обработчик кнопкам и реализуем onClick. В onClick мы создаем Intent, затем определяем, кнопка с каким цветом была нажата и помещаем в Intent объект с именем color и значением цвета. Ставим статус RESULT_OK, указываем, что надо вернуть объект intent в качестве результата и закрываем Activity. Для значения цветов используем системные константы.
Аналогично создаем Activity для выбора выравнивания.
Layout-файл align.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <Button android:id="@+id/btnLeft" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="5dp" android:layout_weight="1" android:text="Left"> </Button> <Button android:id="@+id/btnCenter" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="5dp" android:layout_weight="1" android:text="Center"> </Button> <Button android:id="@+id/btnRight" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="5dp" android:layout_weight="1" android:text="Right"> </Button> </LinearLayout>
AlignActivity.java:
package ru.startandroid.develop.p0301activityresult; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.Gravity; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class AlignActivity extends Activity implements OnClickListener { Button btnLeft; Button btnCenter; Button btnRight; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.align); btnLeft = (Button) findViewById(R.id.btnLeft); btnCenter = (Button) findViewById(R.id.btnCenter); btnRight = (Button) findViewById(R.id.btnRight); btnLeft.setOnClickListener(this); btnCenter.setOnClickListener(this); btnRight.setOnClickListener(this); } @Override public void onClick(View v) { Intent intent = new Intent(); switch (v.getId()) { case R.id.btnLeft: intent.putExtra("alignment", Gravity.LEFT); break; case R.id.btnCenter: intent.putExtra("alignment", Gravity.CENTER); break; case R.id.btnRight: intent.putExtra("alignment", Gravity.RIGHT); break; } setResult(RESULT_OK, intent); finish(); } }
Здесь все аналогично, как и в ColorActivity. Только работаем не с цветами, а с выравниванием. Не забудьте прописать оба Activity в манифесте.
Теперь можем завершить код в MainActivity.java. Добавим пару своих констант в класс для удобства:
final int REQUEST_CODE_COLOR = 1; final int REQUEST_CODE_ALIGN = 2;
Эти константы далее будем использовать в качестве requestCode.
Допишем метод onClick:
@Override public void onClick(View v) { Intent intent; switch (v.getId()) { case R.id.btnColor: intent = new Intent(this, ColorActivity.class); startActivityForResult(intent, REQUEST_CODE_COLOR); break; case R.id.btnAlign: intent = new Intent(this, AlignActivity.class); startActivityForResult(intent, REQUEST_CODE_ALIGN); break; } }
Мы определяем, какая кнопка была нажата и посылаем Intent с ожиданием возврата результата. Два вызова отличаются классом вызываемого Activity и параметром requestCode в методе startActivityForResult. При вызове ColorActivity используем константу REQUEST_CODE_COLOR, а при вызове AlignActivity - REQUEST_CODE_ALIGN. Эту константу мы обратно получим в методе обработки результата – onActivityResult, и по ней сможем определить из какого именно Activity пришел результат.
Давайте реализуем метод onActivityResult в MainActivity.java:
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { // запишем в лог значения requestCode и resultCode Log.d("myLogs", "requestCode = " + requestCode + ", resultCode = " + resultCode); // если пришло ОК if (resultCode == RESULT_OK) { switch (requestCode) { case REQUEST_CODE_COLOR: int color = data.getIntExtra("color", Color.WHITE); tvText.setTextColor(color); break; case REQUEST_CODE_ALIGN: int align = data.getIntExtra("alignment", Gravity.LEFT); tvText.setGravity(align); break; } // если вернулось не ОК } else { Toast.makeText(this, "Wrong result", Toast.LENGTH_SHORT).show(); } }
Для наглядности пишем в лог значения переменных.
Вспоминаем, что в ColorActivity и AlignActivity в методе setResult мы ставили статус RESULT_OK при отправке результата. Значит в onActivityResult нам надо ожидать этот статус, как обозначение успешного окончания вызова.
Если вызов прошел успешно (resultCode = RESULT_OK), то мы смотрим значение requestCode. Если оно равно константе REQUEST_CODE_COLOR, то вспоминаем, что мы использовали эту константу в методе startActivityForResult, когда отправляли запрос на выбор цвета. Значит, нам пришел результат этого выбора. Мы берем Intent (data) и извлекаем из него значение объекта с именем color и присваиваем это значение цвету текста в TextView. Константа Color.WHITE в методе getIntExtra означает значение по умолчанию. Т.е. если в Intent не найдется объекта с именем color, то метод вернет белый (white) цвет.
Аналогично для REQUEST_CODE_ALIGN. Эту константу мы использовали для запроса выбора выравнивания. И если в методе onActivityResult параметр requestCode = этой константе, значит пришел ответ на запрос выравнивания. И мы считываем это значение из Intent и присваиваем его атрибуту Gravity для TextView.
Если resultCode не равен RESULT_OK, значит что-то пошло не так. Выводим на экран соответствующее сообщение. Этот случай может наступить, например, если на экране выбора не делать выбор, а нажать кнопку Назад.
Давайте все сохраним и запустим приложение.
Нажмем Color
и выберем, например Red
Цвет изменился
смотрим лог:
requestCode = 1, resultCode = -1
requestCode пришедший в метод onActivityResult равен 1. Все верно, это значение константы REQUEST_CODE_COLOR, которое мы использовали при вызове.
resultCode = -1 – это значение системной константы RESULT_OK
Т.е. все верно, пришел ответ на запрос цвета, и его статус = RESULT_OK.
Теперь жмем Alignment и выбираем Right, получаем выравнивание вправо:
Смотрим лог:
requestCode = 2, resultCode = -1
requestCode = 2, что равно константе REQUEST_CODE_ALIGN. Значит пришел ответ на запрос выравнивания.
resultCode = -1, т.е. RESULT_OK.
Теперь снова жмем Color
но вместо того, чтобы выбрать цвет нажмем кнопку назад
Отобразилось наше сообщение об ошибке. Смотрим логи:
requestCode = 1, resultCode = 0
requestCode = 1 – все верно, мы запрашивали цвет (REQUEST_CODE_COLOR)
resultCode = 0, это значение константы RESULT_CANCELED, значит вызов прошел неудачно
Ограничений на значение статуса в методе setResult нет. RESULT_OK и RESULT_CANCELED – системные общепринятые константы. Но вы можете свободно использовать свои значения, если в этом есть необходимость.
Итак, подведем итог.
requestCode – это в некотором роде ID запроса. Задается в методе startActivityForResult, и проверяется потом в onActivityResult, чтобы точно знать, на какой вызов пришел ответ.
resultCode – статус вызова. Задается в методе setResult, и проверяется в onActivityResult, чтобы понять насколько успешно прошел вызов. Если при вызове что-то пошло не так, то вернется системная константа RESULT_CANCELED.
Полный код MainActivity.java:
package ru.startandroid.develop.p0301activityresult; import android.app.Activity; import android.content.Intent; import android.graphics.Color; import android.os.Bundle; import android.util.Log; import android.view.Gravity; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends Activity implements OnClickListener { final int REQUEST_CODE_COLOR = 1; final int REQUEST_CODE_ALIGN = 2; TextView tvText; Button btnColor; Button btnAlign; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); tvText = (TextView) findViewById(R.id.tvText); btnColor = (Button) findViewById(R.id.btnColor); btnAlign = (Button) findViewById(R.id.btnAlign); btnColor.setOnClickListener(this); btnAlign.setOnClickListener(this); } @Override public void onClick(View v) { Intent intent; switch (v.getId()) { case R.id.btnColor: intent = new Intent(this, ColorActivity.class); startActivityForResult(intent, REQUEST_CODE_COLOR); break; case R.id.btnAlign: intent = new Intent(this, AlignActivity.class); startActivityForResult(intent, REQUEST_CODE_ALIGN); break; } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { // запишем в лог значения requestCode и resultCode Log.d("myLogs", "requestCode = " + requestCode + ", resultCode = " + resultCode); // если пришло ОК if (resultCode == RESULT_OK) { switch (requestCode) { case REQUEST_CODE_COLOR: int color = data.getIntExtra("color", Color.WHITE); tvText.setTextColor(color); break; case REQUEST_CODE_ALIGN: int align = data.getIntExtra("alignment", Gravity.LEFT); tvText.setGravity(align); break; } // если вернулось не ОК } else { Toast.makeText(this, "Wrong result", Toast.LENGTH_SHORT).show(); } } }
На следующем уроке:
- узнаем что такое URI
- вызываем системные приложения (браузер, звонилка, карта)
Присоединяйтесь к нам в Telegram:
- в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.
- в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Compose, Kotlin, RxJava, Dagger, Тестирование, Performance
- ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня