Шаг 261.
Основы Kotlin.
Знакомство с сопрограммами. Извлечение оперативных данных

    На этом шаге мы рассмотрим особенности выполнения этой операции.

    Теперь, когда вы испытали функцию преобразования, настало время извлечения оперативных данных о характеристиках персонажа из веб-службы.

    Прежде чем начать реализацию, добавим несколько разрешений в манифест приложения Android, чтобы разрешить выполнять сетевые запросы. Найдите и откройте манифест: src/main/AndroidManifest.xml. Добавьте разрешения, как показано ниже.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <application
        android:allowBackup="true"
        .   .   .   .
    </application>

</manifest>


Рис.1. Добавление необходимых разрешений (AndroidManifest.xml)

    Теперь запросим данные из веб-службы. Простейший способ запросить данные из веб-службы - использовать экземпляр java.net.URL. Kotlin включает функцию-расширение для URL, readText, которая подключается к конечной точке веб-службы, буферизует данные и преобразует их в строку. Это то, что нам нужно.

    Объявите новую константу в CharacterGenerator с адресом конечной точки вебслужбы, а также новую функцию с именем fetchCharacterData(), которая читает данные из веб-службы, используя функцию readText(). Не забудьте импортировать класс URL в начале вашего файла, как показано ниже.

package com.example.samodelkin

import java.io.Serializable
import java.net.URL

private const val CHARACTER_DATA_API = "https://chargen-api.herokuapp.com/"
.   .   .   .
object CharacterGenerator {
    .   .   .   .
}

fun fetchCharacterData(): CharacterGenerator.CharacterData {
    val apiData = URL(CHARACTER_DATA_API).readText()
    return CharacterGenerator.fromApiData(apiData)
}


Рис.2. Добавление функции fetchCharacterData() (CharacterGenerator.kt)

    Теперь задействуем новые функции. Добавьте в обработчик нажатий кнопки GENERATE вызов fetchCharacterData().

private const val CHARACTER_DATA_KEY = "CHARACTER_DATA_KEY"

class MainActivity : AppCompatActivity() {
    .   .   .   .
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // setContentView(R.layout.activity_main)

        val binding = ActivityMainBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)

        characterData = savedInstanceState?.characterData ?:
                CharacterGenerator.generate()

        binding.generateButton.setOnClickListener {
//            characterData = CharacterGenerator.//generate()
//                    fromApiData("halfling,Lars Kizzy,14,13,8")

            characterData = fetchCharacterData()
            displayCharacterData(binding)
        }

        displayCharacterData(binding)

    }

    .   .   .   .
}


Рис.3. Вызов fetchCharacterData() (CharacterGenerator.kt)

    Запустите Samodelkin снова и нажмите кнопку GENERATE. Вместо характеристик персонажа вы увидите диалоговые окна как на рисунке 4.


Рис.4. Samodelkin остановлен

    Samodelkin сломался. Почему? Чтобы это узнать, давайте посмотрим на вывод Logcat, куда Android выводит важные сообщения. Выберите вкладку Logcat внизу Android Studio и прокрутите вниз, пока не достигнете красного текста, начинающегося с FATAL EXCEPTION: main (рисунок 5).


Рис.5. Вывод Logcat

    Двумя строками ниже FATAL EXCEPTION вы увидите причину ошибки: исключение android.os.NetworkOnMainThreadException. Исключение возникло из-за попытки выполнить сетевой запрос в главном потоке приложения, что является запрещенной операцией.

    На следующем шаге мы рассмотрим главный поток выполнения в Android.




Предыдущий шаг Содержание Следующий шаг