Основы Android в Kotlin: введение в отладку сбивает с толку

У меня очень простой вопрос. Я следую руководству по разработке кодлабы в предложенном порядке и терплю неудачу в разделе 6 «Введение в отладку»: «Запись работающего приложения». Я нахожу объяснение очень запутанным, потому что оно довольно минимальное для новичка.

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

В этом уроке нам нужно изменить существующий код, чтобы обновить приложение Текстовый вид с помощью инструкции Лог.д, чтобы мы увидели обновленный ID Division_textview на экране телефона.

Я пробовал множество способов добавить окончательный оператор

findViewById<TextView>(R.id.division_textview).setText("${numerator / denominator}")

но не могу добавить его куда угодно, чтобы значения обновлялись в моем эмуляторе. Я не получаю ошибок, но поскольку в этом уроке нет «кода решения», а все предыдущие изображения урока служат довольно запутанной картине того, как именно должен выглядеть окончательный код, может ли кто-нибудь помочь мне с этим?

Мне действительно нужно убедиться, что мой эмулятор работает правильно (об ошибках не сообщается) и что отсутствие результатов — это мой код, а не моя установка.

Это урок, о котором идет речь (спасибо за совет!)

урок

Код из моего MainActivity.kt в дополнение к полезному предложению ниже. Обратите внимание, что я понимаю, что это не «оптимальный» код, я просто пытаюсь следовать инструкциям на данный момент.

package com.example.debugging

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.TextView

private const val TAG = "MainActivity"

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val helloTextView: TextView = findViewById(R.id.division_textview)
        helloTextView.text = "Hello, debugging!"
        logging()
        division()
    }

    fun division() {
        val numerator = 60
        var denominator = 4
        repeat(4) {
            Thread.sleep(3)
            findViewById<TextView>(R.id.division_textview).setText("${numerator / denominator}")
            Log.v(TAG, "${numerator / denominator}")
            denominator--
        }
    }

    fun logging() {
            Log.e(TAG, "ERROR: a serious error like an app crash")
            Log.w(TAG, "WARN: warns about the potential for serious errors")
            Log.i(TAG, "INFO: reporting technical information, such as an operation succeeding")
            Log.d(TAG, "DEBUG: reporting technical information useful for debugging")
            Log.v(TAG, "VERBOSE: more verbose than DEBUG logs")
        }
    }

Может помочь нам связать инструкции, которым вы следуете...

Tenfour04 17.03.2022 15:56

если честно, я думаю, что даже просьба о ссылке может быть не такой уж полезной, эти кодовые лаборатории могут исчезнуть в будущем, есть ли шанс, что вы можете опубликовать весь соответствующий код здесь, на SO? Я предполагаю, что это действие, не могли бы вы опубликовать это в своем вопросе?

a_local_nobody 17.03.2022 16:03

Я полностью согласен с @Tenfour04 выше и действительно заметил, как внутри самой Android Studio предположил, что мое значение Int для Thread.sleep будет в миллисекундах. Итак, я попытался манипулировать этим значением, например, 3000, но ничего не изменилось. Я также задавался вопросом, является ли моя «проблема» просто тем, что из-за времени, необходимого для фактической перекомпиляции представления эмулятора, процедура завершилась. Я не хочу критиковать Google или того, кто написал руководства, но, честно говоря, я нашел несколько случаев противоречивых или отсутствующих инструкций, и я только что закончил введение!

whatshisface 17.03.2022 16:37
1
3
29
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я думаю, что это очень небрежно написанный и неправильный учебник. (Да, даже если это от Google.) Если вы спите в основном потоке, вы не увидите изменения содержимого текстового представления до тех пор, пока не будет выполнен весь цикл repeat, поэтому вы увидите только окончательное значение после того, как denominator уже уменьшен до 0. Кроме того, в учебнике утверждается, что вы увидите, что он будет меняться каждые три секунды, хотя код с Thread.sleep(3) будет приостанавливаться только на 3 Миллиseconds. А затем в своем реальном примере они использовали Thread.sleep(1), что противоречит их инструкциям.

Вместо этого попробуйте этот код:

// added to imports:
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.*

// modified division function
fun division() = lifecycleScope.launch {
    val numerator = 60
    var denominator = 4
    repeat(4) {
        delay(3000)
        findViewById<TextView>(R.id.division_textview).setText("${numerator / denominator}")
        Log.v(TAG, "${numerator / denominator}")
        denominator--
    }
}

Использование = lifecycleScope.launch { превращает вашу функцию в сопрограмму, которая позволяет вам использовать функцию delay() вместо Thread.sleep(), поэтому основной поток получает возможность фактически обновить текстовое представление вместо того, чтобы ждать завершения всего цикла repeat.


Вот альтернативный способ сделать это без сопрограмм, но он не такой красивый:

fun division() = with(Handler(Looper.getMainLooper())) {
    val numerator = 60
    var denominator = 4
    repeat(4) { i ->
        postDelayed({
            findViewById<TextView>(R.id.division_textview).setText("${numerator / denominator}")
            Log.v(TAG, "${numerator / denominator}")
            denominator--
        }, i * 3000L)
    }
}

Спасибо тебе за это! Однако я отмечаю, что при добавлении ваших правок, и хотя я понимаю смысл того, чего они должны достичь, мой экземпляр Android Studio жалуется на оба импорта, заявляя, что они являются «неразрешенной ссылкой». Так что, по-видимому, что-то еще не так с моей общей конфигурацией? Я использую рекомендуемые настройки, например. API 31 и Pixel 5 ... и, насколько я могу судить (очень новичок во всем этом), у меня установлен правильный SDK, только что проверил «синхронизацию» и т. д. Немного застрял в отношении следующих необходимых шагов.

whatshisface 17.03.2022 16:48

В вашем проекте build.gradle добавьте это внутри плагинов: id 'org.jetbrains.kotlin.android' version '1.6.10' apply false. В разделе dependencies вашего модуля build.gradle найдите строку, в которой упоминается android.core, и замените ее на implementation 'androidx.core:core-ktx:1.7.0'. Или просто добавьте эту строку, если еще нет записи android.core.

Tenfour04 17.03.2022 16:51

оба эти параметра конфигурации уже установлены! Ему особенно не нравятся два термина: «lifecycleScope» и «kotlinx».

whatshisface 17.03.2022 16:55

Просто чтобы быть уверенным, там написано core-ktx, а не просто core?

Tenfour04 17.03.2022 16:57

да, он настроен на именно тот текст, который вы предложили.

whatshisface 17.03.2022 16:59

может я это искал? developer.android.com/topic/libraries/architecture/coroutine‌​s

whatshisface 17.03.2022 19:03

Ага, попробуй те. Я в недоумении, в чем может быть проблема. Если вы создаете новый проект с последней версией Android Studio, обычно сопрограммы работают «из коробки». На этом сайте есть более полный список необходимых вам зависимостей, но я думал, что appcompat в сочетании с core-ktx уже включает их как транзитивные зависимости (те, которые загружаются автоматически при загрузке, потому что они зависят от них). Как и в проекте, который я смотрю, у меня не указано lifecycle-runtime-ktx, но оно загружено. Хотя, возможно, я что-то упустил.

Tenfour04 17.03.2022 19:28

Вы можете проверить, какие зависимости загружены (включая все транзитивные), переключив раскрывающийся список Android в верхнем левом углу на Project, а затем развернув Внешние зависимости. Кстати, я только что добавил другой способ сделать это без сопрограмм на случай, если вы просто захотите попробовать.

Tenfour04 17.03.2022 19:31

Спасибо за ваше более позднее решение, оно работает точно так, как ожидалось/предназначено. Я подозреваю, что некоторые из моих проблем с импортом связаны с упаковкой. Я предпочитаю, чтобы мой менеджер пакетов устанавливал вещи, поэтому я избегал ручной установки Android Studio из пакета .zip. Я мог пропустить другие включенные deps. Ничего, теперь все работает и ладно. Самое главное, я понимаю, что это был не совсем «я», а код :D

whatshisface 18.03.2022 17:26

Другие вопросы по теме