Урок 5. Kotlin. Добавление второго экрана в android-приложение. Передача данных через Intent

Продолжаем курс по обучению основам разработки мобильных приложений в Android Studio на языке Kotlin.

В этом уроке создадим второй экран в приложении, и настроим взаимодействие между экранами с передачей данных.

Предыдущий урок, в котором мы обрабатывали нажатия кнопок, здесь

Продолжаем разработку приложения на языке Kotlin, которое мы делали на прошлом уроке.  Исходный код можно скачать на странице прошлого урока.
Пока что наше приложение имеет только один экран. В этом уроке мы добавим второе активити, которое будет отображать экран с данными, полученными на основе данных с первого экрана. При нажатии кнопки Random будет отображаться окно со случайным числом от нуля до текущего значения счетчика.

Вы узнаете

  • Как запустить новое активити с помощью интента
  • Как передать данные во второе активити через интент
  • Как получить данные, переданные через интент во втором активити

Создаем новое активити

Урок 5. Kotlin. Добавление второго экрана в android-приложение. Передача данных через Intent

  1. Раскройте пакет с именем com.example.android.myfirstapp по пути apps > java > com.example.android.myfirstapp.
  2. Правым кликом выберите команду File > New > Activity > Empty Activity.
  3. В окне настроек нового активити установите для него имя SecondActivity. Убедитесь, что в поле Source Language установлен Kotlin.

Также проверьте им пакета, оно должно соответствовать вашему приложению.  Если вы не выделили имя пакета в меню при вызове команды добавления нового активити, установите в это поле android.example.com.myfirstapp.

4. Нажмите  Finish. Android Studio создаст файл на языке Kotlin и файл макета на языке XML  для нового активити.

5. Дождитесь синхронизации gradle в Android Studio.Gradle это система сборки, которая используется в Android Studio для компиляции и постройки приложения. Вы будете видеть сообщения от gradle о прогрессе сборки приложения внизу экрана.

Изучите файл манифеста

Урок 5. Kotlin. Добавление второго экрана в android-приложение. Передача данных через Intent

  1. Откройте файл манифеста приложения по пути app > manifests > AndroidManifest.xml.Файл манифеста содержит информацию о приложении, включая список всех активити.
  2. Обратите внимание на текст между тегами <activity>  для MainActivity:Как видите, тег <activity> содержит параметр имени активити. MainActivity запускается после при старте приложения, поэтому включает дополнительные параметры, которые определяют его как стартовое активити.
  3. Изучите тег <activity> для второго активити. Он содержит только параметр имени.

Каждое активити должно быть определено в файле манифеста. Вы можете добавить новое активити в приложение не через меню добавления активити, но тогда вам нужно будет вручную прописать его в манифесте.

Изучите файл Kotlin нового активити

  1. Откройте файл SecondActivity.kt.
  2. Обратите внимание на метод onCreate(). Постмотрите на вызов setContentView(). Этот метод указывает файл макета activity_second.xml как разметку нового активити.
setContentView(R.layout.activity_second);

В этом активити мы добавим метод отображения случайного числа. Но сначала нам нужно определить поле в макете для его отображения.

Создаем макет для нового активити

Экран нового активити будет отображать заголовок и случайный номер. На вкладке дизайн редактора макетов можно увидеть, как будет выглядеть экран:

Урок 5. Kotlin. Добавление второго экрана в android-приложение. Передача данных через Intent
Добавьте TextView для заголовка

  1. Откройте файл activity_second.xml. Вы увидите пустой ConstraintLayout. Это макет по умолчанию для шаблона Empty Activity.
  2. Добавьте  TextView из палитры компонентов. Этот TextView будет использовано для отображения заголовка вверху экрана.
  3. Ограничение верхнего края TextView установим по верхней границе окна, левый край по левой стороне, а правый край по правой стороне экрана. Нижний край не ограничиваем.
  4. Установите значение ширину match_parent, а высоту wrap_content, поэтому высота изменится в соответствии с высотой содержимого.
  5. Установите идентификатор @+id/textview_label.
  6. Установите верхний, левый и правый отступ 24dp. Левый и правый отступы могут также иметь значение “start” и “end” для поддержки локализации языков с написанием справа налево.
  7. Установите значение параметра цвета текста @color/colorPrimaryDark и размер текста 24sp.
  8. Поместите текст в TextView  “Это случайное число между 0 и %1d.” Спецификатор %1d будет заменен числом в процессе работы приложения.
  9. Поместите текст в ресурсы с именем random_heading.Урок 5. Kotlin. Добавление второго экрана в android-приложение. Передача данных через Intent

Это код XML для TextView, которое отображает заголовок:

<TextView

android:id="@+id/textview_label"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_marginLeft="24dp"

android:layout_marginRight="24dp"

android:layout_marginTop="24dp"

android:text="@string/random_heading"

android:textColor="@color/colorPrimaryDark"

android:textSize="24sp"

app:layout_constraintLeft_toLeftOf="parent"

app:layout_constraintRight_toRightOf="parent"

app:layout_constraintTop_toTopOf="parent"

/>

Добавьте TextView для отображения случайного числа

  1. Добавьте TextView для отображения случайного числа.
  2. Установите значения параметров высоты и ширины wrap_content.
  3. Этот TextView будет находиться ниже TextView заголовка. Ограничьте верхний край по нижнему краю TextView заголовка. Остальные ограничения установите по остальным сторонам экрана.
  4. Установите идентификатор @+id/textview_random.
  5. Установите значение верхнего, леаого и правого отступов 24dp.
  6. Установите значение параметров textColor в @android:color/whitetextSize в 72sp, и textStyle в bold.
  7. Напишите букву R в текстовом поле. Этот текст является просто заменителем, пока не будет сгенерировано случайное число.
  8. Установите значение параметра layout_constraintVertical_bias в 0.45.Этот TextView имеет ограничения по всем краям, так что лучше использовать вертикальные смещения, чем отступы для регулировки вертикального положения, чтобы макет одинаково хорошо выглядел в разных ориентациях и размерах экрана.

Это код XML для  TextView которое отображает случайный номер:

<TextView

android:id="@+id/textview_random"

android:text="R"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:textColor="@android:color/white"

android:textSize="72sp"

android:textStyle="bold"

app:layout_constraintTop_toBottomOf="@+id/textview_label"

app:layout_constraintBottom_toBottomOf="parent"

app:layout_constraintLeft_toLeftOf="parent"

app:layout_constraintRight_toRightOf="parent"

app:layout_constraintVertical_bias="0.45"

/>

 

Изменение цвета фона макета

Установите новому активити новый цвет фона, отличающийся от первого:

  1. В файле colors.xml, добавьте новый цвет:
<color name="screenBackground2">#26C6DA</color>

2. В макете для второго активити, установите элементу ConstraintLayout новый цвет. Это можно сделать в панели свойств или в коде XML:

android:background="@color/screenBackground2"

Макет для второго активити готов. Вы можете посмотреть его на вкладке Дизайн.

Теперь пришло время реализовать переход на второй экран.

Запуск второго активити

Интент – это объект для обмена между активити, который абстрактно представляет собой намерение выполнить какое-либо действие. В основном интенты используются для запуска активити. Как только интент отправляется, его получает система Android, и считывает информацию в нем. Для открытия второго экрана, нам нужно создать и отправить объект Intent с указанием активити, которое нужно открыть. Затем вызвать метод startActivity() с передачей объекта Intent, который отправит это сообщение фреймворку Android, который откроет это активити.

Выполните такие шаги:

  1. Откройте класс MainActivity.kt.
  2. Добавьте метод  randomMe(), который будет вызываться, когда нажата кнопка Random.Если вы забыли, как реализовать такой метод, посмотрите на код методов toastMe() и countMe().
  3. Добавьте код для запуска второго активити в тело метода randomMe():
// Create an Intent to start the second activity

val randomIntent = Intent(this, SecondActivity::class.java)



// Start the new activity.

startActivity(randomIntent)

4. Что еще нужно сделать, чтобы связать метод randomMe() с кнопкой Random? Сделайте это самостоятельно. Ищите подсказки в прошлом уроке.

5. Запустите приложение. Нажмите кнопку Random. Второе активити откроется, но оно пока не показывает случайный номер.

Передача информации между активити

На втором экране при открытии должно отображаться случайное число из диапазона от нуля до текущего значения счетчика на первом экране. Для этого второму активити требуется текущее значение счетчика. Мы можем передать эту информацию в интенте, используя метод putExtra(). Второе активити может получить интент, который запустил его, и извлечь данные Extra Data из этого интента.

Обновите MainActivity для передачи дополнительных данных второму активити

  1. В классе SecondActivity.kt, объявите статическую переменную TOTAL_COUNT, для использования ее в качестве ключа для Extra Data.
companion object {

const val TOTAL_COUNT = "total_count"

}

2. Изменим метод randomMe(). Сначала получим текущее значение счетчика из TextView. Конвертируем значение в тип int, затем с помощью метода putExtra() добавим значение в Intent. Метод putExtra() принимает ключ и значение; в качестве ключа укажем константу TOTAL_COUNT из SecondActivity.kt.

randomIntent.putExtra(SecondActivity.TOTAL_COUNT, count)

Вот полный код метода randomMe():

fun randomMe (view: View) {

// Create an Intent to start the second activity

val randomIntent = Intent(this, SecondActivity::class.java)



// Get the current value of the text view.

val countString = textView.text.toString()



// Convert the count to an int

val count = Integer.parseInt(countString)



// Add the count to the extras for the Intent.

randomIntent.putExtra(SecondActivity.TOTAL_COUNT, count)



// Start the new activity.

startActivity(randomIntent)

}

Обновите SecondActivity для вычисления и отображения случайного числа

Мы написали код для отправки текущего значения счетчика во второе активити. На следующем шаге настроим SecondActivity.kt для получения и использования значения счетчика.

Напишем метод для извлечения значения счетчика и вычисления на его основе случайного числа

  1. В классе SecondActivity.kt, добавим метод showRandomNumber() без аргументов.
  2. Пропишем в этом методе генерацию и отображение случайного числа, максимальное значение которого соответствует значению счетчика.
  3. Используем метод getIntent() для получения интента, запустившего это активити. Используем метод getIntExtra() для получения extra data из интента; аргументами являются ключ или значение по умолчанию при его отсутствии.

Внимание: при получении данных из интента, вы должны знать их тип. Используйте соответствующий getter метод, например getStringExtra() или getIntExtra().

Полный код метода showRandomNumber():


//Other class code...



fun showRandomNumber() {

   // Get the count from the intent extras

   val count = intent.getIntExtra(TOTAL_COUNT, 0)



   // Generate the random number

   val random = Random()

   var randomInt = 0

   // Add one because the bound is exclusive

   if (count > 0) {

       // Add one because the bound is exclusive

       randomInt = random.nextInt(count + 1)

   }



   // Display the random number.

   textview_random.text = Integer.toString(randomInt)



   // Substitute the max value into the string resource

   // for the heading, and update the heading

   textview_label.text = getString(R.string.random_heading, count)

}

Обновите метод onCreate()

Метод onCreate() вызывается при старте активити. Текущий метод onCreate() для SecondActivity устанавливает макет разметки для экрана. Добавим вызов метода showRandomNumber() в метод onCreate(), он будет обновлять текстовое поле для отображения случайного числа.

  1. Изменим метод onCreate() в SecondActivity. Добавим в конце вызов метода showRandomNumber().
override fun onCreate(savedInstanceState: Bundle?) {

   super.onCreate(savedInstanceState)

   setContentView(R.layout.activity_second)

   showRandomNumber()

}

2. Запустим приложение. Нажмем кнопку счетчика на некоторое время, затем нажмем кнопку Random button. В новом окне должно отобразиться случайное число.

Урок 5. Kotlin. Добавление второго экрана в android-приложение. Передача данных через Intent

На этом наш урок подошел к концу. Исходный код урока вы можете скачать по ссылке. Вопросы можно задавать в комментариях.

Следующий урок, в котором мы изучим жизненный цикл активити:

Коментарі: 21
  1. alxtlk

    Класный ресурс. Спасибо. У меня все по уроку работает, но в сторке типа
    val randomIntent = Intent(this, SecondActivity::class.java)
    java красная. Протоколирует при комите
    error:(18, 83) Unresolved reference: java
    Может знаете в чем прооблема?

    1. admin (автор)

      Нужно больше информации об ошибке

    2. alxtlk

      Приблизительно так. Всегда. Но активити успешно стартуется. https://drive.google.com/file/d/1ndQmSw8X69LhkJGyUrMd5N8MfnGP90wK/view?usp=sharing
      Метод registerForActivityResult() со следующих уроков без ошибок. Буду благодарен за рекомендации.

    3. admin (автор)

      Попробуйте обновить Gradle. Здесь есть несколько вариантов решения: https://stackoverflow.com/questions/34144392/kotlin-fooclass-java-unresolved-reference-java-error

  2. Vera

    Здравствуйте. У меня в методе showRandomNumber()
    выдается такая ошибка:
    textViewRandom.text = Integer.toString(randomInt)

    textViewLabel.text = getString(R.string.random_heading, count)
    textViewRandom и textViewLabel подсвечиваются красным. Поля ввода создала правильно, присвоила соответствующее id.
    Весь текст метода:
    fun showRandomNumber(){
    val count = intent.getIntExtra(TOTAL_COUNT, 0)
    // Generate the random number
    val random = Random(count)
    var randomInt = 0

    if (count > 0) {

    randomInt = random.nextInt(count + 1)
    }

    textViewRandom.text = Integer.toString(randomInt)

    textViewLabel.text = getString(R.string.random_heading, count)

    1. admin (автор)

      Здравствуйте. Видимо, у вас нет kotlinx.android.synthetic (эта библиотека устарела). Инициализируйте textViewRandom и textViewLabel через findViewById в методе onCreate. Скачайте обновленные исходники (для примера) в конце урока.

    2. Tokhon

      Добрый вечер!

      Наблюдается такая же проблема, не могу понять как ее решить.
      Ввиду того, что делаю свои первые шаги в программировании, многие вещи понять не могу, например, совет от @admin ниже: “Инициализируйте textViewRandom и textViewLabel через findViewById в методе onCreate.” – для меня не понятен и я его воспринимаю так:
      override fun onCreate(savedInstanceState: Bundle?) {
      …….
      var textViewRandom = findViewById
      var textViewLabel = findViewById
      }
      Но понятно, что это не верно.

      Может быть можно как-то загрузить “вручную” библиотеку: kotlinx.android.synthetic ?
      import kotlinx.android.synthetic – не помогает такая строка.

    3. admin (автор)

      Здравствуйте. Не используйте synthetic.
      В активити вне методов объявите переменную для View, например так:
      private lateinit var textView : TextView

      Затем в методе onCreate() инициализируйте ее, передав в метод findViewById ссылку на идентификатор View:
      textView = findViewById(R.id.textView)

    4. Tokhon

      Вроде бы сделал, как в Ваших рекомендациях, но все равно подсвечивается красным:

      textViewRandom.text = Integer.toString(randomInt)
      textViewLabel.text = getString(R.string.random_heading, count)

      Вот код: https://disk.yandex.ru/i/MASaA5_Jurv2VA

      Возможно, я не в том активити изменил (я изменил в SecondActivity.kt) код?

    5. admin (автор)

      Нужно в каждом активити изменять

  3. Bob Anoid

    Если этот урок еще актуален, то необходимо ввести исправление. Дело в том, что Kotlin Android Extensions — kotlinx-плагин для Kotlin теперь deprecated. FindViewById снова рулит.

    1. ayulia

      И как же это обойти?

    2. worho

      ну самое простое, вручную добавлять постоянно плагин.
      apply plugin: ‘kotlin-android-extensions’

    3. Tokhon

      Как добавить и куда этот плагин? apply plugin: ‘kotlin-android-extensions’

    4. admin (автор)

      в секцию plugins файла build.gradle (Module :app):
      plugins {
      id “org.jetbrains.kotlin.android.extensions” version “1.8.0”
      }

  4. Teacat

    В методе showRandomNumber(): должно быть Random(count) ? Если просто Random() как у вас написано, выдает Cannot create an instance of an abstract class

  5. Alex Darkside

    Здравствуйте, у меня это строчка кода выдает ошибку.
    randomIntent.putExtra(SecondActivity.TOTAL_COUNT, count)

    1. admin (автор)

      Здравствуйте, текст ошибки покажите пожалуйста.

  6. sargon

    Спасибо за ответ. Из урока 5, я уяснил, что между пунктами а) и в) может присутствовать еще кое-что, запись параметра (или любого числа параметров):
    val randomIntent = Intent(this, SecondActivity::class.java)
    randomIntent.putExtra(SecondActivity.TOTAL_COUNT, count)
    startActivity(randomIntent)
    Кстати, довольно любопытное использование объекта SecondActivity.TOTAL_COUNT в этом вызове. На первый взгляд может показаться, что это прямо куда-то внутрь экземпляра класса SecondActivity (в константу?!) записывается число count. Но нет, ничего подобного! Я так понимаю, к интенту RandomIntent можно прикрутить любое количество параметров, идентифицируемых по уникальному ключу, строке текста. Стало быть, вот эта строка кода с putExtra втыкает в интент новый параметр в форме ключ-значение, где ключ равен “totalcount” (константа из класса SecondActiity), а значение равно count.

  7. sargon

    Вы пишете “Для открытия второго экрана, нам нужно создать и отправить объект Intent с указанием активити, которое нужно открыть. Затем вызвать метод startActivity() с передачей объекта Intent, который отправит это сообщение фреймворку Android, который откроет это активити.”

    То есть
    a) Создать Intent
    б) Отправить Intent
    в) Вызвать StartActivity с указанием этого Intent.

    А разве б) и в) – не одно и то же? В приведенном вами коде две строки, не три:
    val randomIntent = Intent(this, SecondActivity::class.java)
    startActivity(randomIntent)

    1. admin (автор)

      Вы правы, это одно и то же.

Додати коментар