Android kotlin: Современная Android разработка на Kotlin. Часть 1 / Хабр

Содержание

Kotlin Android Extensions deprecated. Что делать? Инструкция по миграции / Хабр

Возможно, вы уже слышали, что Kotlin Android Extensions — плагин для Kotlin теперь deprecated.
kotlinx.android.synthetic is no longer a recommended practice. Removing in favour of explicit findViewById

Безусловно, это было очень удобно, особенно если у вас проект полностью на Kotlin. Однако, мир меняется и теперь нужно искать альтернативы. В этой статье мы кратко рассмотрим, что такое плагин Kotlin Android Extension, какие были проблемы с ним и что теперь нам, Android-разработчикам делать. Частично, использовался материал этой статьи. Итак, поехали.

Кратко о Kotlin Android Extensions


Kotlin Android Extensions — это плагин для Kotlin, позволяющий восстанавливать view из Activities, Fragments, и Views без написания стандартного бойлерплэйт-кода типа findViewById.
Плагин генерирует дополнительный код, который позволяет получить доступ к view в виде XML, так же, как если бы вы имели дело с properties с именем id, который вы использовали при определении структуры.

Также он создаёт локальный кэш view. При первом использовании свойства, плагин выполнит стандартный findViewById. В последующем, view будет восстановлен из кэша, поэтому доступ к нему будет быстрее.

Если это всё так удобно, то зачем его сделали deprecated?

Проблемы Kotlin Android Extensions


  • Используется глобальный нэйминг идентификаторов. Могут возникнуть ситуации, когда один и тот же идентификатор имеется у разных view в разных лэйаутах — соответственно только на этапе работы приложения вы узнаете о том, что использовали не тот id.
  • Возможно использовать только в проектах на Kotlin (кэп)
  • Отсутствует Null Safety. В случае, когда view представлена в одной конфигурации и отсутствует в другой — может возникнуть краш, т.к отсутствует обработка таких ситуаций
  • Невозможно использовать в многомодульных проектах. Очень распространённый сценарий: у вас есть модуль UI Kit, хранящий общие UI-компоненты, которые вы хотите переиспользовать в других модулях.
    До сих пор висит issues которое вряд ли поправят. В таком сценарии обычно используют старый добрый findViewById 🙁
  • Резюмируя приведённые недостатки, нетрудно понять, что этот подход не идеален — хотя, безусловно, очень удобен на небольших проектах. На больших проектах с многомодульной архитектурой и сотнями экранов — использование Kotlin Android Extensions уже не кажется идеальным решением.

Альтернативные способы


  • Использование KotterKnife (кек, даже не думайте).
  • Старый добрый FindViewById() — уже получше, но так себе.
  • Использование AndroidAnnotations (привет из 2015)
  • View Binding от Google — бинго!

View Binding от Google


Итак, победителем в этом списке выглядит ViewBinding от Google (не путайте с DataBinding). Давайте кратко рассмотрим, что это такое.

View Binding — это инструмент, который позволяет проще писать код для взаимодействия с view. При включении View Binding в определенном модуле он генерирует binding классы для каждого файла разметки (layout) в модуле. Объект сгенерированного binding класса содержит ссылки на все view из файла разметки, для которых указан android:id

Главные преимущества View Binding — это Null safety и Type safety.

Начало работы с View Binding


Начать работать с ViewBinding достаточно просто. Нужно добавить опцию в build.gradle:
android {
    ...
    buildFeatures {
        viewBinding true
    }
}

После этого можно уже использовать. Каждый сгенерированный binding класс содержит ссылку на корневой view разметки (root) и ссылки на все view, которые имеют id. Имя генерируемого класса формируется как «название файла разметки», переведенное в camel case + «Binding». Например, для файла разметки result_profile.xml:
<LinearLayout ... >
    <TextView android:id="@+id/name" />
    <ImageView android:cropToPadding="true" />
    <Button android:id="@+id/button"
        android:background="@drawable/rounded_button" />
</LinearLayout>

Будет сгенерирован класс ResultProfileBinding, содержащий 2 поля: TextView name и Button button.

Использование в Activity


Например у вас вот такой layout:
<?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" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>

Результат работы ViewBinding:
public final class ActivityMainBinding implements ViewBinding {
  @NonNull
  private final ConstraintLayout rootView;

  @NonNull
  public final TextView textView;

Использовать viewBinding можно так:
private lateinit var binding: ResultProfileBinding

override fun onCreate(savedInstanceState: Bundle?) {
    super. onCreate(savedInstanceState)
    binding = ResultProfileBinding.inflate(layoutInflater)
    val view = binding.root
    setContentView(view)
}

И теперь, после того, как получили ссылки на view:
binding.name.text = viewModel.name
binding.button.setOnClickListener { viewModel.userClicked() }

Если вы используете ViewBinding во фрагменте и держите ссылку на binding во фрагменте (а не только в методе onCreateView()) то не забывайте очищать ссылки в методе onDestroyView().

Пример:

private var _binding: ResultProfileBinding? = null // This property is only valid between onCreateView and // onDestroyView. private val binding get() = _binding!! override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { _binding = ResultProfileBinding.inflate(inflater, container, false) val view = binding.root return view } override fun onDestroyView() { super.onDestroyView() _binding = null }

Это необходимо делать из-за жизненного цикла фрагмента и view:

В целом, переключиться на ViewBinding достаточно не сложно, хотя и жаль, что Kotlin Android Extensions объявлен deprecated. Не забудьте присоединиться к нам в Telegram, а на платформе AndroidSchool.ru публикуются полезные материалы для Android-разработчика и современные туториалы.

Полезные ссылки:

Kotlin. Android KTX

Статья проплачена кошками — всемирно известными производителями котят.

Если статья вам понравилась, то можете поддержать проект.

Kotlin упростил написание кода по сравнению с Java, но нет предела совершенству. Благодаря гибкости Kotlin можно создавать расширения к существующим классам и сделать код ещё проще. Чтобы не изобретать велосипед каждый раз, наиболее удачные примеры решили выделить в отдельную группу, которая получила название Android KTX.

Подключаем библиотеку (один из вариантов).


// добавьте в секцию android
kotlinOptions {
    jvmTarget = JavaVersion.VERSION_1_8.toString()
}

// для секции dependencies
implementation 'androidx.
core:core-ktx:1.2.0' //fragment implementation 'androidx.fragment:fragment-ktx:<version>' // pallete implementation 'androidx.pallete:palette-ktx:<version>' //SQLite implementation 'androidx.sqlite:sqlite-ktx:<version>' // collections implementation 'androidx.collection:collection-ktx:<version>'

Примеры

Несколько примеров для знакомства.

Uri

Если у вас есть строка, которую нужно перевести в Uri, то писали следующую конструкцию.


val uriString = "http://developer.alexanderklimov.ru/android"
val uriOld = Uri.parse(uriString)
Log.d("KTX", uri.host)

Теперь можно писать проще. Код стал читаемым.


val uriString = "http://developer.alexanderklimov.ru/android"
val uri = uriString.toUri()
Log.d("KTX", uri.host)

SharedPreferences

При работе с файлами настройки приходится писать однотипный код.


sharedPreferences.edit()
        .putBoolean(key, value)
        .apply()

Сокращаем код. Разница не слишком большая, но выглядит опрятнее.


sharedPreferences.edit { 
    putBoolean(key, value) 
}

Bitmap/Drawable


// get a drawable from resources
va myDrawable = ContextCompat.getDrawable(context, R.drawable.cat)

// convert the drawable to a bitmap
val bitmap = myDrawable.toBitmap()

Масштабируем Bitmap с помощью scale()

Удобная функция scale() поможет изменить размеры картинки.


// get bitmap from drawable resource
val bitmap = BitmapFactory.decodeResource(resources,R.drawable.table_cat)

// scale bitmap using android ktx
val scaledBitmap = bitmap.scale(
    300, // width
    300, // height
    false // filter
)

button.setOnClickListener {
    imageView. setImageBitmap(scaledBitmap)
}

Смотри также пример Пропорциональное изменение размеров по ширине или высоте

View.drawToBitmap

Конвертирует компонент в изображение. Создадим карточку CardView и созданное изображение карточки поместим в ImageView.


<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="8dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.
501" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/button" tools:srcCompat="@tools:sample/avatars[13]" /> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:backgroundTint="#333399" android:text="Card To Bitmap" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/cardView" /> <androidx.cardview.widget.CardView android:id="@+id/cardView" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="16dp" android:layout_marginTop="24dp" android:layout_marginEnd="8dp" android:elevation="8dp" app:cardBackgroundColor="#3B2F2F" app:cardCornerRadius="4dp" app:contentPadding="12dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> <androidx.
constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/textView" android:layout_width="0dp" android:layout_height="wrap_content" android:background="#B0BF1A" android:fontFamily="monospace" android:gravity="center" android:padding="16dp" android:text="View To Bitmap" android:textAppearance="@style/TextAppearance.AppCompat.Large" android:textSize="35sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx. constraintlayout.widget.ConstraintLayout> </androidx.cardview.widget.CardView> </androidx.constraintlayout.widget.ConstraintLayout>

Код для щелчка кнопки.


package ru.alexanderklimov.ktx

import android.graphics.Bitmap
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.drawToBitmap
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContentView(R.layout.activity_main)

        button.setOnClickListener {
            // draw a bitmap from cardView
            val bitmap: Bitmap = cardView.drawToBitmap(Bitmap.Config.ARGB_8888)

            // show to generated bitmap to imageView
            imageView.setImageBitmap(bitmap)
        }
    }
}

Span


val string = buildSpannedString {
	append("no styling text")
	bold {
		append("bold")
		italic { append("bold and italic) }
	}
	inSpans(RelativeSizeSpan(2f), QuoteSpan()){
		append("double sized quote text")
	}
}

Bundle


val bundle = bundleOf(
    "KEY_INT" to 1,
	"KEY_LONG" to 2L,
	"KEY_BOOLEAN" to true,
	"KEY_NULL" to null,
	"KEY_ARRAY" to arrayOf(1, 2, 3)
)

Обратите внимание, что в примерах используется пакет androidx, это позволит не путать их с стандартными пакетами android.

Другие примеры из разных источников.


//default usage
supportFragmentManager
    .beginTransaction()
	.replace(
	    R.id.my_fragment_container,
		myFragment,
		FRAGMENT_TAG
		)
	.commitAllowingStateLoss()
	
// using androidx.fragment:fragment-ktx
supportFragmentManager.transaction(
    allowStateLosss = true
	) {
	    replace(
		    R.id.my_fragment_container,
			myFragment,
			FRAGMENT_TAG)
	}

// using androidx.core:core-ktx
val s = "Hello, Spans!".toSpannable()

val bold = StyleSpan(BOLD)
s += bolds[7..12] = ForegroundColorSpan(Color.RED)

// using androidx.core:core-ktx
menu.forEach{
  // do action
}

// check if an itme is in the menu and remove it
if(menuItem in menu) menu -= menuItem

// default usage
db.beginTransaction()
try{
 // insert data
 db.setTransactionSuccessful()
 } finally {
   db. endTransaction()
   }
   
// using androidx.sqlite:sqlite-ktx
db.transaction {
  // insert data
}

Дополнительные материалы

Недавно появилась отдельная страница со всеми классами с использованием KTX.

Реклама

Первые впечатления от использования Kotlin для Android

  • Сервисы
    • Веб-разработка
    • Мобильная разработка
    • UI/UX Дизайн
    • Тестирование
    • Бизнес-анализ
    • ERP разработка
    • Автоматизация Бизнеса
    • CRM разработка
    • Оптимизация IT-инфраструктуры
    • 1С Автоматизация предприятий
  • Портфолио
  • Технологии
    • Фронтенд
    • Бэкенд
    • Разработка приложений для iOS
    • Разработка приложений под Android
    • Кросс-платформенная разработка
    • Базы данных
    • Интеграции
  • Блог
  • Компания
    • О нас
    • Команда
    • Реферальная программа
  • Карьера
    • Вакансии
  • Контакты
+ 7 495 640 45 97

Menu

Урок 1. Разработка на Kotlin. Установка Android Studio — Fandroid.info

В первом уроке курса по разработке андроид-приложений на языке Kotlin мы установим необходимые средства для разработки приложений, такие как среда разработки Android Studio.

Этот курс предполагает, что вы знакомы с основами программирования. Если вы немного умеете читать код, вы должны разобраться, даже если у вас нет большого опыта программирования. Если вы не знакомы с основами программирования, то мы рекомендуем посмотреть хотя-бы несколько уроков курса CS50.

Установка Android Studio на компьютер

В этом курсе мы создадим приложение Android на языке Kotlin, используя официальную среду разработки Android Studio.  Android Studio — это IDE, созданная на базе программного обеспечения IntelliJ IDEA от JetBrains специально для разработки Android-приложений. Для создания приложений в Kotlin необходимо установить Android Studio 3.0 или более поздней версии.

Среда Android Studio доступна для компьютеров под управлением Windows, Mac и Linux. Установка практически аналогична для всех платформ. Некоторые различия описаны в подробной инструкции по установке на нашем сайте fandroid.info.

Примечание: Последние сведения о системных требованиях и инструкциях по установке содержатся в официальной документации на сайте developer.android.com/studio.

Если вы используете компьютер, на котором уже установлена ​​Android Studio версии 3.0 и выше, переходите к следующему уроку, в котором мы создадим первый проект.

Android Studio использует инструменты Java Develipment Kit в работе. До недавнего времени перед установкой Android Studio нужно было скачать и установить JDK версии 7 или 8 с официального сайта Oracle. Сейчас такой необходимости нет, поскольку Android Studio уже содержит встроенный пакет инструментов JDK.

Если вам необходимо установить официальный JDK, следуйте инструкции  Установка JDK  (Java Development Kit) на нашем сайте fandroid.info, ссылка под видео.

Установка Android Studio

  1. Откройте страницу загрузки Android Studio на официальном сайте https://developer.android.com/studio/index.html

На данный момент доступна для загрузки версия Android Studio 3.0.

Скачайте дистрибутив для вашей операционной системы

В процессе скачивания можно ознакомится с видео инструкциями по установке Android Studio для вашей операционной системы.

  1. Запустите дистрибутив для установки
  • Примите настройки по умолчанию для всех шагов.
  • Убедитесь, что выбраны все компоненты для установки
  1. После завершения установки Мастер установки загружает и устанавливает дополнительные компоненты. Будьте терпеливы, потому что это может занять некоторое время в зависимости от скорости вашего интернет-соединения.
  2. После завершения загрузки Android Studio запускается, и вы готовы к созданию первого проекта.

К созданию проекта мы перейдем в следующем уроке, а пока на стартовом экране откройте в меню Configure> SDK Manager, который управляет всеми установленными компонентами среды разработки.

На вкладке SDK Platforms можно увидеть, что загружена только последняя версия Android.  Нужно пометить для загрузки несколько последних версий, самых популярных на текущий момент, и скачать их. Процесс загрузки и распаковки происходит автоматически, вам следует только набраться терпения и дождаться его окончания. После окончания установки вы увидите в окне SDK Manager, что выбранные компоненты помечены как загруженные.

Самые популярные версии Android на текущий момент можно посмотреть в статистике на официальном сайте https://developer.android.com/about/dashboards/index.html

Возможные проблемы: Если имя пользователя ПК в Windows написано кириллицей, то Android Studio не будет правильно работать, поскольку среда разработки не читает кириллицу в пути к файлам. Переименуйте пользователя английскими буквами.

При возникновении проблем с установкой вы можете задать вопросы в комментариях под видео на канале Start Android и в комментариях ниже. Кроме того, вы можете воспользоваться различными форумами по программированию, такими как StackOverFlow. Обычно бывает достаточно ввести часть текста ошибки в поиске на StackOverFlow, чтобы найти подсказку к решению проблемы.

На этом наш урок подошел к завершению. А на следующем уроке мы создадим проект в среде разработки Android Studio и запустим первое приложение на андроид-устройстве.

Урок 2. Kotlin. Создание проекта в Android Studio и запуск приложения на андроид-устройстве

Как создать приложение для Android на языке Kotlin — Fandroid.info

Курс по разработке android-приложений на языке Kotlin

Начинаем новый курс по разработке андроид-приложений на языке Kotlin. В этом курсе вы узнаете, как создать и запустить свое первое приложение для Android на Котлине. Если вы не знакомы с языком,  рекомендуем заглянуть в раздел Основы Котлин

Kotlin это статически типизированный язык программирования, который работает на JVM и полностью совместим с языком программирования Java. Kotlin с 2017 года является официально поддерживаемым языком разработки приложений для Android, наряду с языком Java.

Исторически сложилось, что первым официальным языком для разработки андроид-приложений была Java. Несмотря на появление языка Kotlin и признание его в качестве официального языка для Android в 2017 году,  не все разработчики переводят свои проекты с Java на Kotlin. Однако много новых проектов пишется на Котлине, поскольку это удобный и современный язык. 

Какой язык учить: Kotlin или Java?

Многих начинающих разработчиков сейчас волнует вопрос, какой язык изучать для разработки андроид-приложений, Java или Kotlin.

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

На нашем сайте вы можете изучить Основы Kotlin

Также на нашем сайте есть Продвинутые курсы по созданию реальных андроид-приложений на языке Котлин

Нужно ли учить Java?

Реальность такова, что Java на сегодняшний день пока остается основным языком разработки андроид-приложений. На Java написано очень много кода – по сути,  большинство действующих приложений. С использованием Java написано огромное количество примеров, туториалов и мануалов. Kotlin пока отстает в этом плане. Поэтому, если вы не владеете языком Java, вам трудно будет претендовать на вакансию андроид-разработчика. Следовательно, Java тоже необходимо изучать.

Уроки по основам Java

Изучать сразу два языка программирования?

Изучение сразу двух языков программирования может показаться трудной задачей. Но в нашем случае есть положительный момент. Как уже говорилось, Kotlin работает на виртуальной машине Java и полностью совместим с языком Java. Это значит, что в код, написанный на Java можно встраивать код на Kotlin и наоборот. То есть вы можете применять оба языка одновременно не только в одной среде разработки, но и в одном приложении. Конечно, для этого нужно изучить основы обоих языков и научиться применять их.

На нашем сайте вы найдете много уроков по разработке мобильных приложений и игр на языке Java.

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

Все уроки на Kotlin

Разработка Android-приложений на Kotlin — Stepik

Операционная система Android стала бесспорным лидером на мобильных устройствах. На момент создания данного курса под ее управлением было выпущено более двух миллиардов устройств для которых было написано более трех миллионов приложений. Поэтому, каждый разработчик мобильных приложений и игр вынужден поддерживать Android, если хочет добиться успеха.

Одним из краеугольных камней успеха Android является использование модифицированной Java-машины для исполнения  своих приложений. Такое решение позволяет использовать в приложениях существующую кодовую базу JVM-совместимых языков (Java, Scala, Kotlin). При этом, если недавно единственным официально поддерживаемым языком разработки из этого списка была Java, то теперь у разработчиков есть возможность создавать свои приложения на Kotlin. Данный язык был спроектирован так, чтобы с одной стороны унаследовать многие достоинства Java, но при этом скомпенсировать ее известные слабости. В результате получился полностью совместимый язык со строгой типизацией, который специалисты считают потенциальной заменой для Java.

В курсе будут рассмотрены основы синтаксиса  Kotlin, синтаксические конструкции для создания программ в процедурном и объектно-ориентированном стиле. Будут раскрыты основные отличия мобильной разработки от разработки под такие платформы как ПК и ноутбуки. Для мобильных приложений будут подробно рассмотрены наиболее существенные ограничения, с которыми необходимо считаться для эффективной работы приложения на реальных устройствах. Кроме того, будет дан краткий обзор архитектуры ОС Android, показано как настроить среду для разработки. Также будет подробно рассмотрен состав исходных кодов мобильных приложений на Kotlin, способы их запуска и отладки. В завершении будут рассмотрены основные принципы построения мобильных пользовательских интерфейсов, а также подробно рассказано как самостоятельно проектировать и программировать UI.

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

Курс не претендует на звание учебника по Kotlin — дается необходимый минимум материала для того, чтобы начать писать мобильные приложения на этом языке. Для более подробного изучения Kotlin мы рекомендуем курс Максима Бесогонова https://stepik.org/course/5448

Курс подразумевает определенный объем самостоятельной работы с документацией. Для решения некоторых заданий вам потребуется самостоятельно изучить методы работы с объектами Kotlin / Android.

Kotlin для Android — язык программирования Kotlin

Редактировать страницу

Мобильная разработка для Android была первой на Kotlin с момента проведения Google I / O в 2019 году.

Используя Kotlin для разработки Android, вы можете получить следующие преимущества:

  • Меньше кода в сочетании с большей читабельностью . Тратьте меньше времени на написание кода и работу над пониманием чужого кода.
  • Зрелый язык и среда . С момента своего создания в 2011 году Kotlin непрерывно развивался не только как язык. но в целом экосистема с надежным инструментарием.Теперь он полностью интегрирован в Android Studio и активно используется многими компаниями. для разработки приложений под Android.
  • Поддержка Kotlin в Android Jetpack и других библиотеках . Расширения KTX добавляют функции языка Kotlin, такие как сопрограммы, функции расширения, лямбда-выражения и именованные параметры в существующие библиотеки Android.
  • Взаимодействие с Java . Вы можете использовать Kotlin вместе с языком программирования Java в своих приложениях без необходимости переноса всего кода. в Котлин.
  • Поддержка мультиплатформенной разработки . Вы можете использовать Kotlin для разработки не только Android, но также iOS, серверных и веб-приложений. Воспользуйтесь преимуществами совместного использования общего кода между платформами.
  • Код безопасности . Меньше кода и лучшая читаемость приводят к меньшему количеству ошибок. Компилятор Kotlin обнаруживает эти оставшиеся ошибки, делая код безопасным.
  • Легкое обучение . Kotlin очень легко изучить, особенно для разработчиков Java.
  • Большое сообщество . Kotlin пользуется большой поддержкой и большим вкладом сообщества, которое растет во всем мире. По данным Google, более 60% из 1000 лучших приложений в Play Store используют Kotlin.

Многие стартапы и компании из списка Fortune 500 уже разработали приложения для Android с использованием Kotlin — см. Список на веб-сайте Google для разработчиков Kotlin.

Если вы хотите начать использовать Kotlin для разработки Android, прочтите рекомендации Google по началу работы с Kotlin на Android.

Если вы новичок в Android и хотите научиться создавать приложения с помощью Kotlin, ознакомьтесь с этим курсом Udacity.

Kotlin Android Tutorial | Начало работы с Kotlin для приложений Android

Kotlin — это язык, который можно запускать на JVM. Google объявил Kotlin одним из официально поддерживаемых языков программирования в Android Studio, и сообщество Android быстро переходит с Java на Kotlin. В этом руководстве по Kotlin для Android я расскажу вам, как создать приложение для Android с помощью Kotlin.

В этой статье рассматриваются следующие темы:

Давайте приступим!

Что такое Котлин?

Kotlin — это статически типизированный язык программирования общего назначения с выводом типов. Он широко используется для разработки приложений для Android. Kotlin разработан для полного взаимодействия с Java, а версия его стандартной библиотеки для JVM зависит от библиотеки классов Java, но вывод типов позволяет сделать его синтаксис более кратким. Kotlin в основном нацелен на JVM, но также компилируется в JavaScript или собственный код.Kotlin спонсируется JetBrains и Google через Kotlin Foundation. Если вы хотите узнать больше о Kotlin, вы можете обратиться к этой статье в Kotlin Tutorial .

Теперь давайте разберемся с основными принципами Android.

Введение в Android

Android — мобильная операционная система, разработанная Google. Он основан на ядре Linux и разработан в первую очередь для мобильных устройств с сенсорным экраном, таких как смартфоны и планшеты.

Android — самая успешная и мощная мобильная операционная система на рынке сегодня.Итак, прежде чем приступить к этому, давайте сначала разберемся, почему именно Android?

  • Открытый исходный код
  • Настраиваемая операционная система
  • Снижение затрат на разработку и общую сложность
  • Более широкий охват сообщества и разработчиков
  • Интеграция между приложениями
  • Более высокий коэффициент успеха
  • Богатая среда разработки — различные приложения могут быть разработан

Вы можете узнать больше об архитектуре Android и ее функциях с помощью Android Tutorial. Теперь давайте посмотрим, как настроить Android Studio в вашей системе.

Введение в Android Studio

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

Вы также можете использовать IntelliJ для разработки приложений Android, но Android Studio больше подходит для разработки приложений.Теперь давайте посмотрим, как установить его в вашей системе.

Шаг 1: Загрузите Android Studio по этой ссылке.

Шаг 2: После загрузки откройте Android Studio и щелкните Начать новый проект Android Studio на экране приветствия или File | Новый | Новый проект .

Шаг 3: Выберите действие, которое определяет поведение вашего приложения. Для вашего первого приложения. Выберите Пустое действие , которое просто показывает экран, и нажмите Далее .

Шаг 4: После этого вам нужно выбрать предпочтительный язык программирования и нажать следующую кнопку. Если вы хотите узнать больше об установке, прочтите эту статью об установке Android Studio.

Шаг 5: После того, как все настроено и ваш проект настроен, структура вашего проекта будет выглядеть, как показано ниже.

Это не что иное, как анатомия приложения Android, которое состоит из приложения , Java, Res и скриптов Gradle .Узнайте подробности этого с помощью Руководства по анатомии приложений для Android.

Теперь давайте напишем программу и создадим простое приложение для входа в систему Android.

Создание первого приложения Android с использованием Kotlin

Здесь я собираюсь создать приложение для входа в Android . Здесь первый экран — это страница приветствия, как показано ниже.

Чтобы создать и спроектировать этот экран, вам необходимо настроить макет. Для этого вам нужно открыть папку макета и дважды щелкнуть activity_main.xml , как показано ниже.

Открыв XML-файл, вам нужно создать элементы на основе структуры, на которую вы хотите, чтобы ваш экран выглядел. Перед созданием элементов я открою вкладку дизайна и перетащу кнопки на свой экран, как показано ниже.

После этого я вернусь и настрою файл activity_main.xml и создам все элементы. Ваш код выглядит так:

 



<Кнопка
android: text = "Нажмите здесь, чтобы войти"
android: layout_width = "wrap_content"
android: layout_height = "wrap_content"
android: id = "@ + id / click" android: layout_marginTop = "16dp"
app: layout_constraintTop_toBottomOf = "@ + id / textView" android: layout_marginEnd = "96dp"
android: layout_marginRight = "96dp" app: layout_constraintEnd_toEndOf = "@ + id / textView" />

 

Примечание: Если синхронизация проекта Gradle завершилась ошибкой при первом открытии проекта, щелкните ссылку «Установить недостающие платформы и синхронизировать проект» в окне «Сообщения». загружен и установлен Android Studio.

После этого вам необходимо создать файл класса Kotlin, чтобы добавить слушателей для вызова действий из файла XML. Итак, здесь я добавлю слушателей для вызова действий для кнопок и текстовых представлений, которые я создал в файле XML.

 пакет com.example.kotlinandroid

импортировать android.content.Intent
импортировать androidx.appcompat.app.AppCompatActivity
импортировать android.os.Bundle
импортировать android.widget.Button
импортировать android.widget.Toast

class MainActivity: AppCompatActivity () {

переопределить веселье onCreate (savedInstanceState: Bundle?) {
super.onCreate (savedInstanceState)
setContentView (R.layout.activity_main)

val but_click = findViewById 

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

Теперь я создам дизайн в соответствии с приведенным выше изображением на вкладке «Дизайн» второго действия, то есть в файле activity_login.xml , как показано ниже.

После этого я настрою свой XML-файл, как показано на экране выше.

 








<Кнопка
android: text = "Войти"
android: layout_width = "wrap_content"
android: layout_height = "wrap_content"
android: id = "@ + id / логин"
app: layout_constraintStart_toStartOf = "@ + id / pass" android: layout_marginTop = "29dp"
android: layout_marginLeft = "23dp" android: layout_marginStart = "23dp"
app: layout_constraintTop_toBottomOf = "@ + id / pass" />
 constraintlayout.widget.ConstraintLayout> 

После этого вам нужно создать файл класса Kotlin, чтобы добавить слушателей для вызова действий из файла XML. Итак, здесь я добавлю слушателей для вызова действий для поля электронной почты и пароля, а также для кнопок, которые я создал в файле XML.

 пакет com.example.kotlinandroid

импортировать android.content.Intent
импортировать androidx.appcompat.app.AppCompatActivity
импортировать android.os.Bundle
импортировать android.widget.Кнопка
импортировать android.widget.EditText
импортировать android.widget.Toast

логин класса: AppCompatActivity () {

переопределить веселье onCreate (savedInstanceState: Bundle?) {
super.onCreate (savedInstanceState)
setContentView (R.layout.activity_login)
val email = findViewById (R.id.email) как EditText
val pass = findViewById (R.id.pass) как EditText

val btnLogin = findViewById (R.id.login) как кнопка
btnLogin.setOnClickListener {
// считываем значение из EditText в строковую переменную
val ema: String = email. text.toString ()
val pas: String = пройти.text.toString ()
// проверяем, есть ли у EditText значения или нет
if (ema.trim (). length == 0) {
Toast.makeText (applicationContext, «Поле электронной почты не может быть пустым», Toast.LENGTH_SHORT) .show ()
}
if (pas.trim (). length == 0) {
Toast.makeText (applicationContext, «Поле пароля не может быть пустым», Toast.LENGTH_SHORT) .show ()
}

if (ema.equals ("[email protected]") && (pas.equals ("123456"))) {
val intent = намерение (this, home :: class.java)
startActivity (намерение)
} else {
Toast.makeText (applicationContext, «Неверный адрес электронной почты или пароль !!», Toast.LENGTH_SHORT) .show ()
}
}
}
} 

Теперь у вас остался последний экран. Это ваш домашний экран. Как только вы введете действительное имя пользователя и пароль, вы перейдете к следующему экрану, как показано ниже.

Мне также нужно настроить этот экран. Теперь я создам дизайн в соответствии с приведенным выше изображением на вкладке «Дизайн» второго действия, то есть в файле activity_home. xml , как показано ниже.

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

 




 constraintlayout.widget.ConstraintLayout> 

После этого вам нужно создать файл класса Kotlin, чтобы добавить слушателей для вызова действий из файла XML. Итак, здесь я добавлю слушателей для вызова действий для текстового представления и изображения, которое я создал в XML-файле.

 пакет com.example.kotlinandroid

импортировать androidx.appcompat.app.AppCompatActivity
импортировать android.os.Bundle
class home: AppCompatActivity () {
переопределить веселье onCreate (savedInstanceState: Bundle?) {
супер.onCreate (savedInstanceState)
setContentView (R.layout.activity_home)
}
} 

После настройки всех трех экранов вы должны проверить сборку gradle и затем запустить проект. Когда вы это сделаете, он попросит вас выбрать виртуальное устройство, и вам нужно будет выбрать то, которое вам нравится, и запустить код. Будет запущено ваше первое мобильное приложение.

Вот как вам нужно создать свое первое приложение для Android с использованием языка программирования Kotlin. Если вы хотите узнать основы Android, прочтите эту статью в Android Tutorial.

На этом мы подошли к концу статьи о Kotlin Android Tutorial. Надеюсь, вы понимаете все, что было поделено с вами в этой статье.

Теперь, когда вы ознакомились с нашим учебным пособием по Kotlin Android, вы можете пройти сертификационный курс по разработке приложений для Android от Edureka. Есть вопрос для нас? Пожалуйста, укажите это в комментариях к разделу блога «Kotlin Android Tutorial», и мы свяжемся с вами.

Освоение Kotlin Coroutines в Android

Я пишу эту статью, чтобы поделиться своими знаниями о Kotlin Coroutines, которые я усвоил на собственном горьком опыте.

Эта статья предназначена для всех, кто интересуется Kotlin Coroutines, но не знает, что это такое. Цель состоит в том, чтобы вы поняли, что такое Kotlin Coroutines, а это означает, что при написании этого было сделано несколько упрощений. Если вы понимаете, что такое Kotlin Coroutines, моя миссия будет выполнена. Если вы прочитаете эту статью полностью, я уверен, что моя миссия будет выполнена.

Знания приходят к тем, кто их жаждет.

В этом руководстве мы собираемся освоить Kotlin Coroutines в Android, рассмотрев следующие темы:

  • Что именно такое Coroutines?
  • Почему необходимо решение, которое предоставляет Kotlin Coroutines?
  • Пошаговое руководство по внедрению Kotlin Coroutines в Android.
  • Какие области видимости в Kotlin Coroutines?
  • Обработка исключений в Kotlin Coroutines.
  • Проект по изучению Kotlin Coroutines для Android на примерах.

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

Coroutines, очень эффективная и полная структура для управления параллелизмом более производительным и простым способом.

Давайте разберемся, что такое корутины, очень просто.

Что такое сопрограммы?

Coroutines = Co + Routines

Здесь Co означает взаимодействие и Routines означает функций.
Это означает, что когда функции взаимодействуют друг с другом, мы называем это сопрограммами.

Давайте разберемся в этом на примере. Я написал приведенный ниже код по-другому просто для понимания.Предположим, у нас есть две функции: functionA и functionB .

functionA, как показано ниже:

  fun functionA (case: Int) {
    when (case) {
        1 -> {
            taskA1 ()
            функцияB (1)
        }
        2 -> {
            taskA2 ()
            функцияB (2)
        }
        3 -> {
            taskA3 ()
            функцияB (3)
        }
        4 -> {
            taskA4 ()
            функцияB (4)
        }
    }
}  

И functionB, как показано ниже:

  fun functionB (case: Int) {
    when (case) {
        1 -> {
            taskB1 ()
            functionA (2)
        }
        2 -> {
            задачаB2 ()
            functionA (3)
        }
        3 -> {
            taskB3 ()
            functionA (4)
        }
        4 -> {
            taskB4 ()
        }
    }
}  

Затем мы можем вызвать функцию A, как показано ниже:

  functionA (1)  

Здесь functionA выполнит задачу taskA1 и передаст управление функции functionB для выполнения задачи taskB1 .

Затем functionB выполнит taskB1 и вернет управление функции functionA для выполнения task A2 и так далее.

Важно то, что functionA и functionB взаимодействуют друг с другом.

С Kotlin Coroutines вышеуказанное взаимодействие может быть выполнено очень легко, без использования , когда или переключают case , которые я использовал в приведенном выше примере для понимания.

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

Вот несколько возможных вариантов:

  • Он может выполнить несколько строк функции A, затем выполнить несколько строк функции B, а затем еще несколько строк функции A и так далее. Это будет полезно, когда поток простаивает и ничего не делает, в этом случае он может выполнить несколько строк другой функции.Таким образом, он может полностью использовать преимущества потока. В конечном итоге сотрудничество помогает в многозадачности.
  • Это позволит писать асинхронный код синхронным способом. Об этом мы поговорим позже в этой статье.

В целом, сопрограммы делают многозадачность очень простой.

Итак, мы можем сказать, что Coroutines и потоки оба являются многозадачными. Но разница в том, что потоки управляются ОС, а сопрограммы — пользователями , поскольку они могут выполнять несколько функций, используя преимущества сотрудничества.

Это оптимизированный фреймворк, написанный поверх фактического многопоточности с использованием преимуществ кооперативного характера функций, что делает его легким и в то же время мощным. Итак, мы можем сказать, что Coroutines — это легкие потоки. Облегченный поток означает, что он не отображается в собственном потоке, поэтому не требует переключения контекста на процессоре, поэтому они работают быстрее.

Что означает, когда я говорю « не отображается в собственном потоке »?

Сопрограммы доступны на многих языках. По сути, существует два типа сопрограмм:

Kotlin реализует сопрограммы без стека — это означает, что сопрограммы не имеют собственного стека, поэтому они не отображаются в собственном потоке.

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

Сопрограмму можно рассматривать как легкий поток. Как и потоки, сопрограммы могут работать параллельно, ждать друг друга и взаимодействовать. Самая большая разница в том, что сопрограммы очень дешевы, почти бесплатны: мы можем создавать их тысячи и платить очень мало с точки зрения производительности.С другой стороны, настоящие потоки дороги в запуске и хранении. Тысяча потоков может стать серьезной проблемой для современной машины.

Сопрограммы не заменяют потоки, это больше похоже на структуру для управления ими.

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

Теперь, когда мы поняли, что такое сопрограммы. Теперь нам нужно знать, почему нужны решения, которые предоставляют Kotlin Coroutines.

Если вы готовитесь к следующему собеседованию по Android, Присоединяйтесь к нашему профессиональному курсу Android , чтобы узнать последние новости об Android и получить работу в ведущих технологических компаниях.

Зачем нужны Kotlin Coroutines?

Давайте возьмем очень стандартный вариант использования приложения Android, который выглядит следующим образом:

  • Извлечь пользователя с сервера.
  • Показать пользователя в пользовательском интерфейсе.
  fun fetchUser (): User {
    // делаем сетевой вызов
    // возвращаем пользователя
}

fun showUser (пользователь: Пользователь) {
    // показать пользователя
}

fun fetchAndShowUser () {
    val user = fetchUser ()
    showUser (пользователь)
}  

Когда мы вызываем функцию fetchAndShowUser , она генерирует NetworkOnMainThreadException , поскольку сетевой вызов не разрешен в основном потоке.

Есть много способов решить эту проблему. Вот некоторые из них:

1. Использование обратного вызова: Здесь мы запускаем fetchUser в фоновом потоке и передаем результат с помощью обратного вызова.

  fun fetchAndShowUser () {
    fetchUser {пользователь ->
        showUser (пользователь)
    }
}  

2. Использование RxJava: Подход реактивного мира. Таким образом мы можем избавиться от вложенного обратного вызова.

  fetchUser ()
        .subscribeOn (Schedulers.io ())
        .observerOn (AndroidSchedulers.mainThread ())
        .subscribe {пользователь ->
            showUser (пользователь)
        }  

3. Использование сопрограмм: Да, сопрограммы.

  suspend fun fetchAndShowUser () {
     val user = fetchUser () // выборка в потоке ввода-вывода
     showUser (user) // снова в потоке пользовательского интерфейса
}  

Здесь приведенный выше код выглядит синхронным, но асинхронным. Посмотрим, как это возможно.

Реализация Kotlin Coroutines в Android

Добавьте зависимости Kotlin Coroutines в проект Android, как показано ниже:

  dependencies {
  реализация "орг.jetbrains.kotlinx: kotlinx-coroutines-core: x.x.x "
  реализация "org.jetbrains.kotlinx: kotlinx-coroutines-android: x.x.x"
}  

Теперь наша функция fetchUser будет выглядеть следующим образом:

  suspend fun fetchUser (): User {
    return GlobalScope.async (Dispatchers.IO) {
        // делаем сетевой вызов
        // возвращаем пользователя
    }.Ждите()
}  

Не волнуйтесь, в этой статье мы постепенно будем изучать suspend, GlobalScope, async, await и Dispatchers.IO.

И fetchAndShowUser, как показано ниже:

  suspend fun fetchAndShowUser () {
    val user = fetchUser () // выборка в потоке ввода-вывода
    showUser (user) // снова в потоке пользовательского интерфейса
}  

И функция showUser, как показано ниже, такая же, как и раньше:

  fun showUser (user: User) {
    // показать пользователя
}  

Мы ввели здесь две вещи, а именно:

  • Диспетчеры : Диспетчеры помогают сопрограммам определять поток, в котором должна выполняться работа. Существует три основных типа диспетчеров: IO, Default и Main . Диспетчер ввода-вывода используется для работы с сетью и дисками. По умолчанию используется для интенсивной работы процессора. Main — это поток пользовательского интерфейса Android. Чтобы использовать их, нам нужно обернуть работу в функцию async . Асинхронная функция выглядит как показано ниже.
  suspend fun async () // реализация удалена для краткости  
  • suspend : Функция приостановки — это функция, которую можно запускать, приостанавливать и возобновлять.

Функции приостановки можно вызывать только из сопрограммы или другой функции приостановки. Вы можете видеть, что функция async , которая включает ключевое слово suspend . Итак, чтобы использовать это, нам нужно приостановить и нашу функцию .

Итак, fetchAndShowUser может быть вызван только из другой функции приостановки или сопрограммы. Мы не можем заставить функцию onCreate действия приостановить , поэтому нам нужно вызвать ее из сопрограмм, как показано ниже:

  override fun onCreate (savedInstanceState: Bundle?) {
    супер. onCreate (savedInstanceState)
    
    GlobalScope.launch (Dispatchers.Main) {
        fetchAndShowUser ()
    }
    
}  

Что на самом деле

  переопределить удовольствие onCreate (savedInstanceState: Bundle?) {
    super.onCreate (savedInstanceState)

    GlobalScope.launch (Dispatchers.Main) {
        val user = fetchUser () // выборка в потоке ввода-вывода
        showUser (user) // снова в потоке пользовательского интерфейса
    }
    
}  

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

В Kotlin есть две функции для запуска сопрограмм:

Launch vs Async в Kotlin Coroutines

Разница в том, что запуск {} ничего не возвращает, а async {} возвращает экземпляр Deferred , который имеет функцию await () , которая возвращает результат сопрограммы, как у нас есть future в Java, в котором мы выполняем future. get () для получения результата.

Другими словами:

  • запуск : запустить и забыть
  • async : выполнить задачу и вернуть результат

Давайте рассмотрим пример для изучения запуска и асинхронности.

У нас есть функция fetchUserAndSaveInDatabase, как показано ниже:

  suspend fun fetchUserAndSaveInDatabase () {
    // получаем пользователя из сети
    // сохраняем пользователя в базе данных
    // и ничего не возвращаем
}  

Теперь мы можем использовать запуск, как показано ниже:

  GlobalScope.launch (Dispatchers.Main) {
    fetchUserAndSaveInDatabase () // выполняем в потоке ввода-вывода
}  

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

Но когда нам нужен результат, нам нужно использовать async .

У нас есть две функции, которые возвращают User, как показано ниже:

  suspend fun fetchFirstUser (): User {
    // делаем сетевой вызов
    // возвращаем пользователя
}

приостановить веселье fetchSecondUser (): User {
    // делаем сетевой вызов
    // возвращаем пользователя
}  

Теперь мы можем использовать async , как показано ниже:

  GlobalScope. launch (Dispatchers.Main) {
    val userOne = async (Dispatchers.IO) {fetchFirstUser ()}
    val userTwo = async (Dispatchers.IO) {fetchSecondUser ()}
    showUsers (userOne.await (), userTwo.await ()) // снова в потоке пользовательского интерфейса
}  

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

У нас также есть видеоформат для Launch vs Async. Проверьте здесь.

Если вы хотите проверить полную реализацию «Параллельных множественных сетевых вызовов с использованием Kotlin Coroutines», проверьте этот блог .

Итак, теперь, когда мы поняли разницу между функцией запуска и функцией async .

Есть что-то под названием withContext .

  suspend fun fetchUser (): User {
    return GlobalScope.async (Dispatchers.IO) {
        // делаем сетевой вызов
        // возвращаем пользователя
    }.Ждите()
}  

withContext — это не что иное, как еще один способ написания асинхронного кода, при котором нам не нужно писать await () .

  suspend fun fetchUser (): User {
    return withContext (Dispatchers.IO) {
        // делаем сетевой вызов
        // возвращаем пользователя
    }
}  

Но есть еще много вещей, которые мы должны знать о withContext и await .

Теперь давайте использовать withContext в нашем примере async для fetchFirstUser и fetchSecondUser параллельно.

  GlobalScope.launch (Диспетчеры.Основной) {
    val userOne = withContext (Dispatchers.IO) {fetchFirstUser ()}
    val userTwo = withContext (Dispatchers.IO) {fetchSecondUser ()}
    showUsers (userOne, userTwo) // снова в потоке пользовательского интерфейса
}  

Когда мы используем withContext , он будет работать последовательно, а не параллельно. Это большая разница.

Правила большого пальца:

  • Используйте withContext , когда вы выполняете , а не требуется параллельное выполнение.
  • Используйте async только тогда, когда вам нужно параллельное выполнение.
  • Для получения результата можно использовать withContext и async , что невозможно при запуске .
  • Используйте withContext , чтобы вернуть результат одной задачи.
  • Используйте async для результатов нескольких задач, которые выполняются параллельно.

Области действия в сопрограммах Kotlin

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

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

В упражнении нам нужно реализовать CoroutineScope.

  class MainActivity: AppCompatActivity (), CoroutineScope {

    переопределить val coroutineContext: CoroutineContext
        get () = Диспетчеры. Главное + задание

    private lateinit var job: Job

}  

В функциях onCreate и onDestroy.

  переопределить удовольствие onCreate (savedInstanceState: Bundle?) {
    super.onCreate (savedInstanceState)
    job = Job () // создаем задание
}

override fun onDestroy () {
    job.cancel () // отменить задание
    super.onDestroy ()
}  

Теперь просто используйте запуск, как показано ниже:

  запуск {
    val userOne = async (Dispatchers.IO) {fetchFirstUser ()}
    val userTwo = async (Dispatchers.IO) {fetchSecondUser ()}
    showUsers (userOne.await (), userTwo.await ())
}  

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

Когда нам нужна глобальная область действия, которая является областью нашего приложения, а не областью действия, мы можем использовать GlobalScope, как показано ниже:

  GlobalScope.launch (Dispatchers. Main) {
    val userOne = async (Dispatchers.IO) {fetchFirstUser ()}
    val userTwo = async (Dispatchers.IO) {fetchSecondUser ()}
}  

Здесь, даже если действие будет уничтожено, функции fetchUser продолжат работу, как мы использовали GlobalScope .

Вот почему области видимости в Kotlin Coroutines очень полезны.

Обработка исключений в Kotlin Coroutines

Обработка исключений — еще одна важная тема. Мы должны этому научиться.

При использовании запуска

Один из способов — использовать блок try-catch:

  GlobalScope.launch (Dispatchers.Main) {
    пытаться {
        fetchUserAndSaveInDatabase () // делаем в потоке ввода-вывода и обратно в поток пользовательского интерфейса
    } catch (исключение: Exception) {
        Log.d (TAG, "$ исключение обработано!")
    }
}  

Другой способ — использовать обработчик:

Для этого нам нужно создать обработчик исключений, как показано ниже:

  val handler = CoroutineExceptionHandler {_, exception ->
    Журнал. d (TAG, "$ исключение обработано!")
}  

Затем мы можем прикрепить обработчик, как показано ниже:

  GlobalScope.launch (Dispatchers.Main + handler) {
    fetchUserAndSaveInDatabase () // делаем в потоке ввода-вывода и обратно в поток пользовательского интерфейса
}  

Если есть исключение в fetchUserAndSaveInDatabase , оно будет обработано обработчиком, который мы подключили.

При использовании в области действия мы можем прикрепить исключение в нашем coroutineContext , как показано ниже:

  class MainActivity: AppCompatActivity (), CoroutineScope {

    переопределить val coroutineContext: CoroutineContext
        get () = Диспетчеры.Главный + работа + обработчик

    private lateinit var job: Job

}  

И используйте, как показано ниже:

  запуск {
    fetchUserAndSaveInDatabase ()
}  

При использовании async

При использовании async нам нужно использовать блок try-catch для обработки исключения, как показано ниже.

  val deferredUser = GlobalScope.async {
    fetchUser ()
}
пытаться {
    val user = deferredUser.await ()
} catch (исключение: Exception) {
    Log.d (TAG, "$ исключение обработано!")
}  

Теперь давайте рассмотрим еще несколько реальных примеров использования обработки исключений в Android Development.

Предположим, у нас есть два сетевых вызова, как показано ниже:

И мы делаем сетевые вызовы последовательно, как показано ниже:

  запуск {
    пытаться {
        val users = getUsers ()
        val moreUsers = getMoreUsers ()
    } catch (исключение: Exception) {
        Log.d (TAG, "$ исключение обработано!")
    }
}  

Если один из сетевых вызовов завершится неудачно, он перейдет непосредственно к блоку перехвата .

Но предположим, что мы хотим вернуть пустой список для сетевого вызова, который потерпел неудачу, и продолжить ответ от другого сетевого вызова.Мы можем добавить блок try-catch к отдельному сетевому вызову, как показано ниже:

  launch {
    пытаться {
        val users = try {
            getUsers ()
        } catch (e: Exception) {
            emptyList <Пользователь> ()
        }
        val moreUsers = try {
            getMoreUsers ()
        } catch (e: Exception) {
            emptyList <Пользователь> ()
        }
    } catch (исключение: Exception) {
        Log.d (TAG, "$ исключение обработано!")
    }
}  

Таким образом, если произойдет какая-либо ошибка, она продолжит работу с пустым списком.

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

  запуск {
    пытаться {
        val usersDeferred = async {getUsers ()}
        val moreUsersDeferred = асинхронный {getMoreUsers ()}
        val users = usersDeferred.await ()
        val moreUsers = moreUsersDeferred.await ()
    } catch (исключение: Exception) {
        Log.d (TAG, "$ исключение обработано!")
    }
}  

Здесь мы столкнемся с одной проблемой: если произойдет какая-либо сетевая ошибка, приложение выйдет из строя! , это будет НЕ перейдет в блок catch .

Чтобы решить эту проблему, нам нужно будет использовать coroutineScope , как показано ниже:

  launch {
    пытаться {
        coroutineScope {
            val usersDeferred = async {getUsers ()}
            val moreUsersDeferred = асинхронный {getMoreUsers ()}
            val users = usersDeferred.await ()
            val moreUsers = moreUsersDeferred.await ()
        }
    } catch (исключение: Exception) {
        Log.d (TAG, "$ исключение обработано!")
    }
}  

Теперь, если произойдет какая-либо сетевая ошибка, она перейдет в блок catch .

Но предположим еще раз, мы хотим вернуть пустой список для сетевого вызова, который потерпел неудачу, и продолжить ответ от другого сетевого вызова. Нам нужно будет использовать supervisorScope и добавить блок try-catch к отдельному сетевому вызову, как показано ниже:

  launch {
    пытаться {
        supervisorScope {
            val usersDeferred = async {getUsers ()}
            val moreUsersDeferred = асинхронный {getMoreUsers ()}
            val users = try {
                usersDeferred.Ждите()
            } catch (e: Exception) {
                emptyList <Пользователь> ()
            }
            val moreUsers = try {
                moreUsersDeferred.await ()
            } catch (e: Exception) {
                emptyList <Пользователь> ()
            }
        }
    } catch (исключение: Exception) {
        Log.d (TAG, "$ исключение обработано!")
    }
}  

Опять же, таким образом, если возникает какая-либо ошибка, она продолжит работу с пустым списком.

Вот как помогает supervisorScope .

Заключение:

  • Хотя НЕ использует async , мы можем продолжить с try-catch или CoroutineExceptionHandler и добиться чего угодно на основе наших сценариев использования.
  • При использовании async в дополнение к try-catch у нас есть два варианта: coroutineScope и supervisorScope .
  • С async используйте supervisorScope с отдельным try-catch для каждой задачи в дополнение к try-catch верхнего уровня, если вы хотите продолжить выполнение других задач, если одна или некоторые из них не удалось.
  • С async , используйте coroutineScope с try-catch верхнего уровня , когда вы выполняете НЕ хотите продолжить выполнение других задач, если какая-либо из них не удалась.
Основное отличие состоит в том, что coroutineScope будет отменять, когда любой из его дочерних элементов терпит неудачу. Если мы хотим продолжить выполнение других задач, даже если одна из них не удалась, мы используем supervisorScope. SupervisorScope не отменяет других дочерних элементов, когда один из них выходит из строя.

Вот как может выполняться обработка исключений в Kotlin Coroutines.

Думаю, сегодня мы получили неплохой объем знаний. Большое вам спасибо за ваше время.

Теперь давайте начнем использовать Kotlin Coroutines.

Изучите Kotlin Coroutines для Android на примерах

Поделитесь этим блогом с другими разработчиками, чтобы распространять знания.

Если вы готовитесь к следующему собеседованию по Android, Присоединяйтесь к нашему профессиональному курсу Android , чтобы узнать последние новости об Android и получить работу в ведущих технологических компаниях.

Удачного обучения 🙂

Team MindOrks

Покажите свою любовь, поделившись этим блогом с другими разработчиками.

Нажмите здесь, чтобы поделиться в Twitter.

Также давайте станем друзьями в Twitter, Linkedin, Github, Quora и Facebook.

Работа с Kotlin в Android Studio — Kotlin Blog

С выпуском M6 мы объявили о поддержке Android Studio.Давайте подробнее рассмотрим, как приступить к работе с Android Studio и Kotlin.

Установка подключаемого модуля Kotlin

Как и в случае с IntelliJ IDEA, чтобы установить плагин Kotlin, вам нужно щелкнуть Preferences (Настройки) и выбрать запись Plugins. Самый простой способ — просто начать вводить plugin , как только появится диалоговое окно.

Хотя мы можем загрузить плагин и установить его с диска, самый простой способ — это нажать на Установить плагин JetBrains… и выбрать Kotlin из списка.Щелкните правой кнопкой мыши и выберите Загрузить и установить

Следуйте инструкциям, чтобы перезапустить среду IDE.

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

Добавление исходной папки для Kotlin

Типичный проект Android имеет следующий макет

, где исходный код проекта находится в папке main / java .Поскольку мы хотим использовать Kotlin (мы можем смешивать и сопоставлять Java и Kotlin в одном проекте), нам нужно создать новую папку в main с именем kotlin. В скрипте Gradle мы позже определим эту папку как исходный корень.

Настройка Gradle

Нам нужно настроить некоторые зависимости и исходные папки в конфигурации Gradle. Откройте файл build.gradle и скопируйте следующий

 buildscript {
    репозитории {
        mavenCentral ()
    }
    dependencies {
          classpath 'org.jetbrains.kotlin: kotlin-gradle-plugin: 0.6. + '
        classpath 'com.android.tools.build:gradle:0.5.+'
    }
}

применить плагин: 'android'
  применить плагин: 'kotlin-android' 

репозитории {
    mavenCentral ()
}

dependencies {
      скомпилируйте 'org.jetbrains.kotlin: kotlin-stdlib: 0.6. +' 
}

android {
    compileSdkVersion 17
    buildToolsVersion "17.0.0"

    defaultConfig {
        minSdkВерсия 7
        targetSdkVersion 16
    }
      sourceSets {
        main.java.srcDirs + = 'src / main / kotlin'
    } 
} 

Обновление : заменить « 0.6. + »с установленной вами версией плагина Kotlin.

Полужирным шрифтом выделены части, относящиеся к Kotlin:

  • Выберите плагин Kotlin для Gradle и версию, которую мы используем. Версия M6 соответствует версии 0.6.69.
  • Примените плагин kotlin-android
  • Импортировать стандартную библиотеку Kotlin
  • Укажите, где расположены файлы исходного кода

Указание sourceSet автоматически пометит созданную нами ранее папку ( main / kotlin ) как корень исходного кода в Android Studio.

После обновления файла Gradle мы сможем успешно собрать проект Android, написанный на Kotlin.

Hello World на Kotlin

Самый простой способ опробовать Kotlin с Android — создать проект Android по умолчанию и преобразовать код в Kotlin, что IDE может сделать за нас.

  1. Создайте новый проект Android (мы опускаем шаги по созданию новых проектов Android).
  2. Добавьте папку kotlin и обновите файл Gradle, как указано выше.

  3. Выберите файл MainActivity и в меню Code выберите Convert Java File to Kotlin File . Мы можем не создавать резервную копию.

  4. Как только мы это сделаем, Android Studio автоматически обнаружит, что это файл Kotlin, и спросит нас, хотим ли мы переместить его в папку kotlin. Мы так и делаем.

После того, как проект построен, мы сможем его запустить.

Могу ли я объединить Java и Kotlin в одном проекте Android?
Совершенно верно.Фактически, проверьте наш репозиторий GitHub для некоторых примеров.

Могу ли я использовать ночные сборки Kotlin?
Да, можно. Просто обновите проект Gradle, чтобы он указывал на снимки, и добавьте соответствующий репозиторий.

 buildscript {
    репозитории {
        mavenCentral ()
     maven {
      url 'http://oss.sonatype.org/content/repositories/snapshots'
        }
    }
    dependencies {
          путь к классам 'org.jetbrains.kotlin: kotlin-gradle-plugin: 0.1-SNAPSHOT' 

    }
}
.. .
репозитории {
    mavenCentral ()
    maven {
        url 'http://oss.sonatype.org/content/repositories/snapshots' 
    }
}

dependencies {
      скомпилируйте 'org.jetbrains.kotlin: kotlin-stdlib: 0.1-SNAPSHOT' 
} 

Вы забыли упомянуть еще какие-нибудь вкусности?
Теперь, когда вы спросили, у нас также есть некоторые внешние аннотации для Android JDK. Android Studio автоматически предложит вам добавить их в проект.

Хотя в этом посте мы использовали Android Studio, обратите внимание, что разработка Android с помощью Kotlin также возможна с IntelliJ IDEA и доступна уже довольно давно.Как всегда, мы ценим любую обратную связь.

Аутентификация приложений Android, разработанных на Kotlin

TL; DR: В сегодняшнем посте мы узнаем, как создать простое приложение для Android, написанное на Kotlin, и защитить его с помощью JWT. Мы собираемся использовать Auth0, чтобы выдать нам access_token и собираемся использовать этот токен для связи с API. В конце мы также поговорим о том, как мы будем обрабатывать токены, выпущенные самодельным решением, а не Auth0.

«Узнайте, как создать безопасное приложение для Android с помощью Kotlin».

Твитнуть

Является ли Kotlin хорошим выбором для разработки под Android?

В мае прошлого года на презентации Google I / O команда Android объявила о первоклассной поддержке Kotlin. Итак, да, Kotlin — хороший выбор для разработки под Android. В противном случае команда Android никогда бы не пошла на такой шаг. Кроме того, последние 4 года Android Studio базировалась на платформе IntelliJ.Для тех, кто не знает, IntelliJ — это продукт компании JetBrains, создателя языка программирования Kotlin. Таким образом, мы можем быть уверены, что при выборе Kotlin для нашего следующего проекта опыт разработки будет гладким. По крайней мере, с точки зрения поддержки IDE.

Чем Котлин отличается от Java?

Kotlin — это совершенно новый язык программирования с другим синтаксисом. У разработчиков Java не возникнет особых проблем при чтении исходного кода проекта, написанного на Kotlin.Хотя есть много различий и много интересных функций, которые Java-разработчики должны изучить, прежде чем погрузиться в Kotlin.

Если вы никогда раньше не использовали Kotlin, вы все равно можете следить за этим сообщением в блоге, поскольку в нем не так много продвинутых тем. Но для полноты картины вот список ресурсов, где вы можете узнать больше о Kotlin:

Кроме того, имейте в виду, что JetBrains много инвестирует в инструменты, чтобы помочь разработчикам Java перейти на Kotlin. Например, IntelliJ и Android Studio 3.0 поставляются с инструментами, которые автоматически переводят исходный код Java в Kotlin.

Разработка приложения для Android на Kotlin

Чтобы начать новый проект, вы можете воспользоваться мастером Create New Project , который поставляется с Android Studio. Его использование довольно простое, и требуется всего несколько шагов, как показано в этом руководстве. Но, чтобы ускорить процесс, мы собираемся клонировать этот репозиторий на нашей локальной машине.

Этот пост был сделан с использованием Android Studio 3 Canary 3 .Новые версии IDE должны поддерживаться, пока мы обновляем версии плагина Kotlin и оболочки Gradle.

  git clone https://github.com/auth0-blog/kotlin-app.git
  

После этого мы собираемся открыть его в Android Studio через Открыть существующий проект Android Studio вариант:

Если вы впервые используете Android Studio, вам также потребуется установить эмулятор Android или интегрировать собственное устройство Android с IDE.У меня не было проблем с установкой нового эмулятора Android локально через IDE. Но по какой-либо причине, если вы застряли, вы можете проверить этот ресурс, чтобы узнать, помогает ли он.

Чтобы гарантировать, что все работает должным образом, запустим приложение как есть. Это можно сделать с помощью кнопки Run app (зеленая кнопка воспроизведения в верхней части IDE), которая запустит приложение на выбранном эмуляторе (или на вашем собственном устройстве) с помощью Hello World! сообщение.

Что мы будем строить на Kotlin

Как уже упоминалось, мы собираемся создать простое приложение. Это приложение будет состоять из трех компонентов:

  1. Список дел. Этот список будет получен из RESTful API, который будет общедоступным.
  2. Входной текст и кнопка, позволяющая пользователям добавлять новые элементы в существующий список. Это будет доступно только зарегистрированным пользователям.
  3. Функция входа и регистрации, предоставляемая Auth0.Мы собираемся получить access_token от Auth0 и будем использовать его для взаимодействия с защищенной конечной точкой.

Загрузка RESTful API

RESTful API, который мы собираемся использовать, представляет собой приложение Express, которое можно найти здесь. Поэтому перед разработкой функций, упомянутых в нашем приложении Kotlin, нам нужно будет клонировать этот репозиторий.

  git clone https://github.com/auth0-blog/nodejs-auth0/
cd nodejs-auth0
npm install
  

Поскольку наш RESTful API будет защищен Auth0, мы собираемся зарегистрировать бесплатную учетную запись (т.е.е. если у нас его еще нет). Поскольку Auth0 управляет идентификацией на основе стандартов, таких как OAuth и OpenID Connect, мы будем следовать передовым методам и создавать API-представление нашего бэкэнда в веб-инструменте управления. На этой странице нажмите кнопку Create API и заполните форму, как показано ниже:

Первое поле в этой форме, называемое Имя , является просто понятным именем в инструменте, и его значение не имеет для нас значения. Второе поле, Идентификатор , — это аудитория нашего API.Мы собираемся использовать это значение при настройке нашего бэкенда, а также в нашем приложении Kotlin для Android. Последнее поле, Signing Algorithm , определяет, как будут подписываться наши токены. RS256 использует закрытый ключ для подписи токенов и открытый ключ для его проверки. Чтобы узнать больше о том, как работает процесс подписания, прочтите эту статью.

Auth0 также создаст тестовое приложение, когда мы закончим создание нашего API. Если мы перейдем в меню Applications , мы увидим приложение под названием Kotlin To Do App (Test Application) .Давайте откроем это приложение, чтобы скопировать из него значение домена .

С этим значением мы сможем запускать наш RESTful API. В корневом каталоге клонированного репозитория введем следующие команды:

  экспорт AUTH0_AUDIENCE = kotlin-todo-app
экспорт AUTH0_DOMAIN = krebshaus.auth0.com
экспорт AUHT0_ALGORITHM = RS256

индекс узла
  

Имейте в виду, что значения, экспортированные выше, относятся к моей учетной записи в Auth0. Ваше значение для переменной среды AUTH0_DOMAIN наверняка будет отличаться.Два других значения, AUTH0_AUDIENCE и AUHT0_ALGORITHM , будут такими же, как у меня, если вы ничего не меняли при настройке API.

После выполнения последней команды, node index , наш RESTful API будет запущен. Мы можем отправить два простых запроса для проверки:

  # get to do items
завиток http: // локальный: 8080
# что приведет к: [«Покормить собак», «Подстричь лужайку», «Купить пиццу»]

# пытаемся опубликовать новый элемент без токена авторизации
curl -d 'новый элемент' -X POST -v http: // localhost: 8080
# что приведет к получению кода статуса 401 (неавторизованный)
  

Использование RESTful API с Kotlin

Чтобы начать разработку нашего приложения Kotlin to-do для Android, мы сначала займемся взаимодействием с серверной частью.Чтобы взаимодействовать с нашим RESTful API, мы собираемся внести три изменения в наш проект. Во-первых, нам нужно добавить зависимость к Volley. Этого можно добиться, изменив файл ./app/build.gradle следующим образом:

  // ...

dependencies {
    // ...
    скомпилировать com.android.volley: volley: 1.0.0 '
}

// ...
  

Второе изменение, которое нам понадобится, — это явное определение того, что наше приложение Android будет использовать подключение к Интернету. Это будет сделано путем редактирования файла ./app/src/main/AndroidManifest.xml файл следующим образом:

  


    

    


  

После определения зависимости от Volley и того, что нашему приложению требуется разрешение на использование Интернета, мы создадим служебный класс, который будет обрабатывать все взаимодействия с нашей серверной частью.Мы определим этот класс как родственный класс MainActivity , назвав его ToDoAPIUtils.kt со следующим кодом:

  пакет com.auth0.samples.kotlinapp

импортировать android.app.Activity
импортировать android.widget.ArrayAdapter
импортировать android.widget.ListView
импортировать android.widget.Toast
импорт com.android.volley.Request
импорт com.android.volley.RequestQueue
импорт com.android.volley.Response
импорт com.android.volley.toolbox.JsonArrayRequest
импортировать org.json.JSONArray

val ENDPOINT = "http://10.0.2.2:8080/"

fun getItems (activity: Activity, queue: RequestQueue, listView: ListView) {
    val jsonArrayRequest = JsonArrayRequest (Request.Method.GET, ENDPOINT, null,
            Response.Listener  {ответ ->
                val list = ArrayList  ()

                (От 0 до response.length ()). MapTo (list) {
                    ответ [это] .toString ()
                }

                val адаптер = ArrayAdapter (активность,
                        андроид.R.layout.simple_list_item_1, список)
                listView.adapter = адаптер
            },
            Response.ErrorListener {ошибка ->
                Toast.makeText (
                        activity.applicationContext,
                        error.toString (),
                        Toast.LENGTH_SHORT) .show ()
            }
    )
    // добавляем getItems в очередь
    queue.add (jsonArrayRequest)
}
  

Этот файл содержит единственную функцию (на данный момент), которая будет отправлять GET запросов к бэкэнду и заполнять ListView ответом.Обратите внимание, что в Kotlin функции могут быть объявлены на верхнем уровне файла, что означает, что вам не нужно создавать класс для хранения функции.

Еще одним важным аспектом приведенного выше кода является то, что ENDPOINT жестко запрограммирован на http://10.0.2.2:8080/ . Этот URL-адрес относится к RESTful API, который мы запустили ранее, поэтому, если вы не используете эмулятор, вам может потребоваться изменить это значение на IP-адрес вашего компьютера в вашей локальной сети.

Визуализация дел

Поскольку у нас уже есть функция, которая будет извлекать элементы из нашего бэкэнда, мы будем использовать ее для отображения их пользователю.Поскольку список элементов общедоступен, мы собираемся показать его в первом представлении, макете activity_main.xml , на который ссылается MainActivity . Определим содержимое этого файла следующим образом:

  


    


  

После этого мы обновим MainActivity следующим кодом:

  пакет com.auth0.samples.kotlinapp

импортировать android.os.Bundle
импортировать android.support.v7.app.AppCompatActivity
импортировать android.widget.ListView
импорт com.android.volley.toolbox.Volley

class MainActivity: AppCompatActivity () {

    переопределить веселье onCreate (savedInstanceState: Bundle?) {
        супер.onCreate (savedInstanceState)
        setContentView (R.layout.activity_main)

        // настройка Volley RequestQueue
        val queue = Volley.newRequestQueue (это)

        // получаем ссылку на ListView
        val listToDo = findViewById (R.id.list_todo) как ListView

        // передача активности, очереди и ListView функции
        // потребляет конечную точку RESTful
        getItems (это, очередь, listToDo)
    }
}
  

Это последнее изменение, которое нам нужно внести в наше приложение, чтобы увидеть список дел.Давайте запустим приложение на эмуляторе (или на нашем собственном устройстве), чтобы увидеть его.

Защита приложения Kotlin с помощью Auth0

Поскольку мы уже визуализировали общедоступный список дел в нашем приложении, теперь мы собираемся работать над уровнем аутентификации. Это позволит нашим пользователям войти в наше приложение (а также зарегистрироваться), что сгенерирует JWT (веб-токен JSON). Этот JWT, называемый access_token , будет проверен нашим сервером, чтобы разрешить или запретить пользователям добавлять новые элементы в список дел.

Чтобы интегрировать наше приложение с Auth0, нам нужно добавить зависимость к этой библиотеке с открытым исходным кодом. Мы делаем это, изменяя файл ./app/build.gradle следующим образом:

  // ...

android {
    // ...
    dataBinding {
        enabled = true
    }
}

dependencies {
    // ...
    kapt 'com.android.databinding: compiler: 3.0.0-alpha4'
    скомпилировать com.auth0.android:auth0:1.8.0 '
}

// ...
  

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

После этого мы изменим MainActivity и его макет, чтобы добавить кнопку, при нажатии которой запускается процесс аутентификации. Давайте начнем с добавления кнопки аутентификации в файл app / src / main / res / layout / activity_main.xml , который будет выглядеть следующим образом:

  


    <данные>
        
        
    

    

        <Кнопка android: id = "@ + id / login_button"
            android: layout_width = "match_parent"
            android: layout_height = "wrap_content"
            android: text = "Пожалуйста, представьтесь."
            android: visibility = "@ {loggedIn? View.GONE: Просмотр.ВИДИМЫЙ} "/>

        

    

  

Обычно мы определяем метки и статические тексты в файле strings.xml . Однако, чтобы упростить руководство, мы оставим их определенными в файле макета.

Нам пришлось изменить основной элемент в этом файле на макет , чтобы правильно определить переменную loggedIn .Эта переменная используется в этом макете, чтобы скрыть кнопку входа в систему, когда пользователь успешно идентифицирован. Его значение будет управляться (и связываться) классом MainActivity .

Давайте сосредоточимся на обновлении класса MainActivity , чтобы интегрировать его с библиотекой Auth0, а также на управление состоянием переменной loggedIn :

  пакет com.auth0.samples.kotlinapp

импортировать android.app.Dialog
импортировать android.content.Intent
импортировать android.databinding.DataBindingUtil
импортировать android.os.Bundle
импортировать android.support.v7.app.AppCompatActivity
импортировать android.widget.ListView
импортировать android.widget.Toast
импорт com.android.volley.toolbox.Volley
импортировать com.auth0.android.Auth0
импорт com.auth0.android.authentication.AuthenticationException
импортировать com.auth0.android.provider.AuthCallback
импортировать com.auth0.android.provider.WebAuthProvider
импортировать com.auth0.android.result.Credentials
импорт com.auth0.samples.kotlinapp.databinding.ActivityMainBinding

class MainActivity: AppCompatActivity () {

    привязка var: ActivityMainBinding? = ноль

    переопределить веселье onCreate (savedInstanceState: Bundle?) {
        супер.onCreate (savedInstanceState)
        setContentView (R.layout.activity_main)

        // настройка Volley RequestQueue
        val queue = Volley.newRequestQueue (это)

        // ссылка на объект привязки представления
        привязка = DataBindingUtil.setContentView (это, R.layout.activity_main)

        // loggedIn по умолчанию должен иметь значение false, чтобы отображалась кнопка
        привязка? .loggedIn = false

        // получаем ссылку на ListView
        val listToDo = findViewById (R.id.list_todo) как ListView

        // передача активности, очереди и ListView функции
        // потребляет конечную точку RESTful
        getItems (это, очередь, listToDo)

        // запуск метода входа в систему при нажатии кнопки
        val loginButton = findViewById (R.id.login_button)
        loginButton.setOnClickListener {login ()}
    }

    // Auth0 вызывает намерение при успешном входе в систему
    переопределить развлечение onNewIntent (intent: Intent) {
        if (WebAuthProvider.resume (намерение)) {
            возвращение
        }
        super.onNewIntent (намерение)
    }

    приватный вход для веселья () {
        val account = Auth0 (getString (R.string.auth0_client_id), getString (R.string.auth0_domain))
        account.isOIDCConformant = true

        WebAuthProvider.init (аккаунт)
                .withScheme ("демонстрация")
                .withAudience ("kotlin-todo-app")
                .start (это, объект: AuthCallback {
                    переопределить удовольствие onFailure (dialog: Dialog) {
                        runOnUiThread {dialog.show ()}
                    }

                    переопределить удовольствие onFailure (исключение: AuthenticationException) {
                        runOnUiThread {
                            Toast.makeText (
                                    this @ MainActivity, "Упс, что-то пошло не так!",
                                    Тост.LENGTH_SHORT) .show ()
                        }
                    }

                    переопределить удовольствие onSuccess (учетные данные: учетные данные) {
                        CredentialsManager.saveCredentials (это @ MainActivity, учетные данные)
                        привязка? .loggedIn = true
                    }
                })
    }
}
  

Функция onCreate была изменена, чтобы получить ссылку на объект привязки, связанный с макетом, чтобы инициализировать переменную loggedIn как false и установить прослушиватель на loginButton .Функция входа в систему, которая вызывается, когда пользователь нажимает кнопку входа в систему, запускает компонент WebAuthProvider , предоставляемый библиотекой Auth0. Этот компонент должен быть инициализирован экземпляром Auth0 , который зависит от идентификатора клиента приложения Kotlin To Do (тестовое приложение) и от нашего домена Auth0. Это тот же домен, который мы экспортировали как переменную среды перед запуском серверного приложения.

Оба эти свойства, auth0_client_id и auth0_domain , считываются из строк .xml файл. Давайте откроем этот файл и добавим им значения, которые мы находим в Kotlin To Do App (тестовое приложение) , которое было создано для нас на Auth0:

  <ресурсы>
     KotlinApp 
    
     4gDhRaCvv2ESmAlL0JAtYX3SD8OkFoi3 
     krebshaus.auth0.com 

  

Возвращаясь к изменениям, внесенным в класс MainActivity , важно отметить, что мы также настроили WebAuthProvider на:

  • использовать схему demo , которая поможет Android запускать наше приложение, когда ссылка, начинающаяся с demo: // , называется
  • использует аудиторию kotlin-todo-app , которая является названием API, который мы создали для инструмента управления Auth0.

Функция start для WebAuthProvider ожидает, что реализация AuthCallback будет обрабатывать результаты попыток входа и регистрации. Чтобы определить нашу реализацию, мы создали встроенный класс, который при возникновении ошибки просто отображает сообщение Toast о том, что «что-то пошло не так». И когда процесс входа или регистрации завершается успешно, мы сохраняем учетные данные в CredentialsManager . Этот менеджер не является частью библиотеки, предоставляемой Auth0, мы фактически должны его реализовать.

CredentialsManager будет иметь две обязанности: хранить учетные данные вошедшего в систему пользователя; и предоставить метод для получения access_token этого пользователя. Мы также создадим этот класс как родственный класс MainActivity , назвав его CredentialsManager.kt . Этот класс будет содержать следующий код:

  пакет com.auth0.samples.kotlinapp

импортировать android.content.Context
импортировать com.auth0.android.result.Полномочия

object CredentialsManager {
    частный val PREFERENCES_NAME = "auth0"
    private val ACCESS_TOKEN = "токен_доступа"

    fun saveCredentials (context: Context, credentials: Credentials) {
        val sp = context.getSharedPreferences (
                PREFERENCES_NAME, Context.MODE_PRIVATE)

        sp !!. edit (). putString (ACCESS_TOKEN, credentials.accessToken)
                .применять()
    }

    fun getAccessToken (context: Context): String {
        val sp = context.getSharedPreferences (
                PREFERENCES_NAME, Контекст.MODE_PRIVATE)

        вернуть sp !!. getString (ACCESS_TOKEN, null)
    }
}
  

Обратите внимание, что мы начинаем определение этого класса с объекта вместо класса . Это идиоматический способ определить синглтонов в Котлине.

Чтобы завершить изменения в нашем проекте, нам нужно зарегистрировать фильтр намерений внутри тега нашего основного действия и сделать так, чтобы это действие запускалось как отдельная задача. Давайте откроем ./app/src/main/AndroidManifest.xml и заменим его следующим содержимым:

  


    

    <приложение
        android: allowBackup = "true"
        android: icon = "@ mipmap / ic_launcher"
        android: label = "@ строка / имя_приложения"
        android: roundIcon = "@ mipmap / ic_launcher_round"
        android: supportsRtl = "true"
        android: theme = "@ style / AppTheme">
        <активность android: name = ".Основное занятие"
                  android: launchMode = "singleTask">
            
                <действие android: name = "android.intent.action.MAIN" />

                
            

            
                <действие android: name = "android.intent.action.VIEW" />

                
                

                <данные
                    android: host = "@ строка / auth0_domain"
                    android: pathPrefix = "/ android / com.auth0.samples.kotlinapp / callback"
                    android: scheme = "demo" />
            
        
    


  

Перед тестированием интеграции с Auth0 нам нужно вернуться на страницу Application в инструменте управления и внести две модификации.Во-первых, мы должны настроить параметр Allowed Callback URLs нашего приложения, чтобы он принимал следующий URL:

  демонстрация: //krebshaus.auth0.com/android/com.auth0.samples.kotlinapp/callback
  

Конечно, домен krebshaus.auth0.com в этом URL должен быть изменен в соответствии с вашим доменом на Auth0.

Во-вторых, мы должны изменить Application Type на Native , чтобы включить PKCE.

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

Использование токенов доступа для взаимодействия с серверной частью

Мы успешно интегрировали наше приложение Kotlin с Auth0 и смогли получить от него access_token . Теперь мы сосредоточимся на использовании этого токена для связи с серверной частью. Мы начнем с добавления EditText и еще одной Button в макет MainActivity , а затем мы будем использовать их оба для добавления новых элементов в список дел.Чтобы добавить эти элементы в наш макет, давайте откроем файл activity_main.xml и вставим их в качестве первых дочерних элементов элемента LinearLayout :

  

    
    
        

        <Кнопка
            android: id = "@ + id / add_item"
            android: layout_width = "match_parent"
            android: layout_height = "wrap_content"
            android: text = "Добавить элемент"
            android: visibility = "@ {loggedIn? View.VISIBLE: View.GONE}" />
        
    

  

Оба элемента будут отображаться, только если пользователь вошел в систему , как определено в их свойствах android: visibility .Теперь мы можем добавить слушателя, который будет запускать запрос POST к бэкэнду, к новой кнопке. Мы достигаем этого, изменяя MainActivity следующим образом:

  пакет com.auth0.samples.kotlinapp

// ...
импортировать android.widget.EditText

class MainActivity: AppCompatActivity () {

    // ...

    переопределить веселье onCreate (savedInstanceState: Bundle?) {
        // ...

        val addItemButton = findViewById (R.id.add_item)
        val itemEditText = findViewById (R.id.item) как EditText
        addItemButton.setOnClickListener {
            val item = itemEditText.text.toString ()
            addItem (очередь, элемент, CredentialsManager.getAccessToken (это), {
                itemEditText.text.clear ()
                Toast.makeText (this, «Элемент добавлен», Toast.LENGTH_SHORT) .show ()
                getItems (это, очередь, listToDo)
            })
        }
    }

    // ...
}
  

Слушатель этой кнопки вызывает addItem , функцию, которую нам еще нужно создать.Эта функция будет отвечать за отправку HTTP-запроса POST на бэкэнд с access_token пользователя. Создадим его в классе ToDoAPIUtils :

  // ...
импортировать android.util.Log
import com.android.volley.AuthFailureError
импорт com.android.volley.toolbox.StringRequest

// ...

fun addItem (queue: RequestQueue, item: String, accessToken: String, done: () -> Unit) {
    val postRequest = объект: StringRequest (Request.Method.POST, ENDPOINT,
            Отклик.Слушатель  {
                сделанный()
            },
            Response.ErrorListener {
                ошибка -> Log.w ("APIRequest", error.toString ())
            }
    ) {
        @Throws (AuthFailureError :: класс)
        переопределить удовольствие getBody (): ByteArray {
            вернуть item.toByteArray ()
        }

        @Throws (AuthFailureError :: класс)
        переопределить удовольствие getHeaders (): Map  {
            заголовки val: Map  = hashMapOf (
                    «Авторизация» на «Bearer $ accessToken»,
                    "Content-Type" на "text / plain"
            )
            возвращать заголовки
        }
    }
    // добавляем POST REQUEST в очередь
    очередь.добавить (postRequest)
}
  

Функция addItem , которую мы определили выше, использует класс StringRequest , предоставляемый Volley . Во-первых, мы инструктируем этот класс вести себя как запрос POST к бэкэнду ENDPOINT (URL-адрес нашего RESTful API). Затем мы определяем двух слушателей: один для успешного запроса, а другой для сбоя (где мы просто записываем, что пошло не так).

Если все работает, как ожидалось, мы запускаем обратный вызов done , который является последним параметром, принимаемым функцией addItem .Да, мы можем легко передавать такие функции обратного вызова в Kotlin. Этот обратный вызов, который мы определили при последнем изменении класса MainActivity , отвечает за обновление списка задач после успешного запроса POST.

Мы также перезаписали два метода класса StringRequest :

  • Функция getBody для отправки элемента (введенного пользователем) в виде строки в теле запроса POST.
  • Функция getHeaders , чтобы пометить Content-Type запроса как text / plain и добавить access_token аутентифицированного пользователя.

Эти изменения - все, что нам нужно в нашем приложении Kotlin для правильного взаимодействия с защищенной конечной точкой RESTful. Теперь, когда пользователь вводит элемент в текстовый ввод, наше приложение Kotlin отправляет запрос на бэкэнд с элементом и access_token . Затем серверная часть получает этот access_token , проверяет его по общему ключу, предоставленному Auth0, а затем добавляет полученный элемент в список дел.

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

Создание домашнего решения безопасности

Если мы не хотим полагаться на самые современные функции, предоставляемые Auth0, мы также можем разработать собственное решение безопасности с JWT. Мы не будем вдаваться в подробности процесса рефакторинга, но вот обзор шагов, необходимых для развития нашего собственного решения:

  1. Нам нужно будет реорганизовать наш RESTful API, чтобы сгенерировать для нас токен access_token , а не только проверять его.
  2. Нам также потребуется реорганизовать серверную часть, чтобы принимать новые регистрации, извлекать пароль и т. Д. (Функции, которые Auth0 предоставляет по умолчанию).
  3. Нам нужно добавить действие в нашем приложении Kotlin для обработки входа и регистрации.
  4. Нам потребуется добавить еще одно действие для обработки восстановления пароля.

Изменения в приложении Kotlin не были бы такими сложными, если бы мы избегали расширенных функций, таких как интеграция с Active Directory и социальными провайдерами (которые все тривиально с Auth0).Что касается внутреннего рефакторинга, в блоге Auth0 есть множество статей, в которых рассматриваются домашние решения на разных языках и платформах, например:

Вы можете проверить эти ресурсы, если вам нужно разработать собственное решение.

Заключение

Разработка безопасного приложения для Android с помощью Kotlin - тривиальная задача, как нам удалось увидеть в этом сообщении в блоге. Если у вас не было предыдущих знаний о Kotlin, скорее всего, у вас не было проблем с его продвижением. Интеграция Kotlin с существующими библиотеками и фреймворками Java упрощает процесс его изучения.Но чтобы использовать этот язык в полную силу, необходимо много часов программирования и обучения.

«Разработка безопасного приложения для Android с помощью Kotlin - тривиальная задача».

Твитнуть

Кроме того, у нас была возможность убедиться, что защитить мобильные приложения Kotlin с помощью JWT просто. Когда мы полагаемся на надежного поставщика управления идентификацией, такого как Auth0, все становится еще более гладким и безопасным.Нам не нужно было реализовывать собственные функции входа и регистрации в мобильном приложении, даже в нашей серверной части. Мы только что настроили несколько вещей в нашей бесплатной учетной записи Auth0 и интегрировали библиотеку с открытым исходным кодом в наше приложение.

Используя Auth0, мы также можем быть уверены, что если нам потребуется повысить безопасность нашего приложения с помощью многофакторной аутентификации, добавить функцию Обнаружение взломанного пароля или интегрироваться с другими поставщиками диспетчера удостоверений, такими как Facebook или SAML, процесс будет гладким и хорошо документированы.

Android Kotlin ListView Пример

Android Kotlin ListView Пример

В большинстве приложений очень часто бывает, что список элементов данных отображается в пользовательском интерфейсе. В приложениях Android список элементов данных может быть показан пользователям с помощью ListView.

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

Android ListView отображает данные вертикально, при этом каждый элемент располагается под предыдущими элементами данных. ListView можно прокручивать. Вы можете использовать ListView без каких-либо проблем для отображения нескольких элементов данных в пользовательском интерфейсе. Но для отображения больших объемов данных в виде списка вам необходимо использовать RecyclerView для создания хорошо работающих приложений.

Содержание

Адаптер ListView

ListView использует объект адаптера для отображения данных. Адаптеры ListView являются реализациями интерфейса ListAdapter.Адаптеры ListView принимают список элементов данных и макет элемента, которые будут использоваться для каждого элемента в качестве входных данных. После того, как объект адаптера упакован, его необходимо передать объекту ListView, вызвав метод setAdapter ().

Android предоставляет ArrayAdapter и CursorAdapter. ArrayAdapter можно использовать для отображения массива элементов в ListView. CursorAdapter используется для отображения данных из курсора в ListView.

Пользовательский ListAdapter может быть создан путем расширения BaseAdapter или его подклассов и реализации getView и других методов.В следующих разделах мы увидим, как создать собственный адаптер просмотра списка.

Шаги по использованию ListView

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

    

В действии получите объект ListView.

  val lv = findViewById  (R.id.products)  

Затем получите список данных из локальной или удаленной базы данных и передайте его экземпляру адаптера представления списка. Например, список строк можно показать в ListView с помощью ArrayAdapter. Макет элемента simple_list_item_1 содержит TextView, который отображает элемент строки.

  val prodAdapter = ArrayAdapter  (это,
android.R.layout.simple_list_item_1, prodsList)  

Затем передайте объект адаптера в ListView, вызвав метод setAdapter.

  лв.адаптер = prodAdapter  

Пользовательский адаптер списка

Для отображения сложных элементов данных, то есть списка данных, содержащего элементы, каждый из которых имеет несколько свойств, необходимо создать пользовательский адаптер списка. Вы можете создать собственный ListAdapter, расширив ArrayAdapter или BaseAdapter.

В методе getView, используя переданный ему аргумент позиции элемента, вам необходимо получить элемент данных для этой позиции, затем раздуть макет элемента и заполнить представления в макете элемента данными из элемента данных.

Следующий код Kotlin показывает, как создать собственный ListAdapter.

  импорт android.content.Context
импортировать android.graphics.Color
импортировать android.view.LayoutInflater
импортировать android.view.View
импортировать android.view.ViewGroup
импортировать android.widget.ArrayAdapter
импортировать android.widget.ImageView
импортировать android.widget.TextView
импортировать android.widget.Toast
импорт java.util. *

class AttractionsAdapter (items: ArrayList , ctx: Context):
        ArrayAdapter  (ctx, R.layout.attraction_item, items) {

    // держатель представления используется для предотвращения вызовов findViewById
    частный класс AttractionItemViewHolder {
        внутреннее изображение var: ImageView? = ноль
        внутренний заголовок var: TextView? = ноль
        внутреннее описание var: TextView? = ноль
        внутренние часы var: TextView? = ноль
    }

    переопределить удовольствие getView (i: Int, view: View ?, viewGroup: ViewGroup): View {
        var view = view

        val viewHolder: AttractionItemViewHolder

        if (view == null) {
            val inflater = LayoutInflater.из (контекст)
            view = inflater.inflate (R.layout.attraction_item, viewGroup, false)

            viewHolder = АттракционItemViewHolder ()
            viewHolder.title = view !!. findViewById  (R.id.title) как TextView
            viewHolder.description = view.findViewById  (R.id.description) как TextView
            viewHolder.hours = view.findViewById  (R.id.hours) как TextView
            // показывает, как применить стили к представлениям элемента для определенных элементов
            если (я == 3)
                viewHolder.часов !!. setTextColor (Color.DKGRAY)
            viewHolder.image = view.findViewById  (R.id.image) как ImageView
        } else {
            // не нужно вызывать findViewById, можно использовать существующие из сохраненного держателя представления
            viewHolder = view.tag как AttractionItemViewHolder
        }

        val привлекательность = getItem (я)
        viewHolder.title !!. text = привлекательность !!. title
        viewHolder.description !!. text = Attraction.description
        viewHolder.hours !!. text = Attraction.hours
        viewHolder.изображение !!. setImageResource (привлекательность. изображение)

        // показывает, как обрабатывать события просмотра элементов
        viewHolder.image !!. setOnClickListener {
            Toast.makeText (context, "Изображение клика" + привлекательность !!. Title,
                    Toast.LENGTH_SHORT) .show ()
        }

        view.tag = viewHolder

        Вернуться мнение
    }
}  

Держатель представления

Пользовательский адаптер, показанный выше, использует объект держателя представления, чтобы избежать вызовов findViewById, если объект представления существует для позиции, переданной методу getView.

Объект держателя вида содержит все виды элемента. Объект держателя представления сохраняется как тег в родительском представлении макета элемента при его первом создании. В методе getView, если переданное ему представление не равно null, вы можете получить объект-держатель представления из представления и получить доступ к представлениям элемента.

Стилизация ListView

Стилизуя представления макета элемента, используемые для отображения элементов данных, вы можете сделать внешний вид ListView таким, чтобы он соответствовал теме вашего приложения. Чтобы различать каждый элемент в списке по стилю, вы можете использовать разные цвета, шрифт, размер текста и т. Д. Для элементов в разных положениях и применять их в адаптере списка к представлениям элементов.

Например, вы можете назначить другой цвет текста TextView элемента в определенной позиции в списке в методе getView для listadapter.

  если (i == 3)
viewHolder.hours !!. setTextColor (Color.DKGRAY)  

Вы можете настроить высоту разделителя элементов, установив высоту для объекта ListView.

  lv.dividerHeight = 10  

События обработки ListView

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

  lv.onItemClickListener = AdapterView.OnItemClickListener {
            адаптерView, view, i, l ->
            Toast.makeText (это @ PlaceAttractionsActivity,
                    "вы выбрали товар" + (i + 1),
                    Toast.LENGTH_LONG) .show ()
        }  

Если вам нужно отслеживать и реагировать на события представлений в элементах, вам необходимо обработать эти события в адаптере списка, добавив соответствующий обработчик событий в представления элементов. Например, следующий код добавляет OnClickListener в представление изображения.

  viewHolder.image !!. SetOnClickListener {
    Toast.makeText (context, "Изображение клика" + привлекательность !!. Title,
            Toast.LENGTH_SHORT) .show ()
}  

Пример ListView Kotlin

Пример ListView Kotlin отображает список туристических достопримечательностей выбранного места.

Main Activity
  import android.content.Intent
импортировать android.support.v7.app.AppCompatActivity
импортировать android.os.Bundle
импортировать android.view.View

class SelectPlaceActivity: AppCompatActivity () {

    переопределить веселье onCreate (savedInstanceState: Bundle?) {
        супер.onCreate (savedInstanceState)
        setContentView (R.layout.select_place)
    }

    fun showAttractions (view: View) {
        val i = намерение ()
        i.setClass (это, PlaceAttractionsActivity :: class.java)
        startActivity (я)
    }
}  
Список действий
  import android.os.Bundle
импортировать android.support.v7.app.AppCompatActivity
импортировать android.widget.AdapterView
импортировать android.widget.ListView
импортировать android.widget.Toast
импорт java.util. *

class PlaceAttractionsActivity: AppCompatActivity () {

    частные достопримечательностиByCity = HashMap > ()

    переопределить веселье onCreate (savedInstanceState: Bundle?) {
        супер.onCreate (savedInstanceState)
        setContentView (R.layout.place_attractions)

        loadAttractionsData ()

        val lv = findViewById  (R.id.place_attractions)

        val seattleAttractions = getAttractionsByPlace ("Сиэтл")
        val привлекательностиAdapter = АттракционыAdapter (seattleAttractions, это)
        lv.adapter = attributesAdapter

        lv.dividerHeight = 10

        lv.onItemClickListener = AdapterView.OnItemClickListener {
            адаптерView, view, i, l ->
            Тост.makeText (это @ PlaceAttractionsActivity,
                    «вы выбрали аттракцион» + (i + 1),
                    Toast.LENGTH_LONG) .show ()
        }
    }

    весело getAttractionsByPlace (место: String): ArrayList  {
        вал достопримечательности = достопримечательностиByCity [место]
        если (достопримечательности! = null) вернуть достопримечательности else return ArrayList  ()
    }

    fun loadAttractionsData () {
        addSeattleAttractions (Достопримечательности по городу)
    }

    fun addSeattleAttractions (sitesByCity: MutableMap >) {
        val достопримечательностиLst = ArrayList  ()

        var привлекательность = Притяжение ()
        достопримечательности.title = "Сиэтл Спейс Нидл"
        привлекательности.description = "Путешествие к вершине 520 футов Спейс-Нидл" +
                «смотровая площадка с бесподобным видом на центр Сиэтла» +
                "Маунт-Ренье и Пьюджет-Саунд"
        Привлечение.hours = "10:00 - 20:00"
        Привлечение.image = R.drawable.space_needle

        достопримечательностиLst.add (аттракцион)

        Привлечение = Притяжение ()
        Привлечение.title = "Рынок Пайк-плейс"
        Привлечение.description = "Рынок Пайк-плейс - это общедоступный рынок", +
                «открыт 17 августа 1907 года, и один из старейших непрерывно» +
                «управляла государственными фермерскими рынками в Соединенных Штатах."
        Привлечение.hours = "9 утра - 4 вечера"
        Привлечение.image = R.drawable.pike_place_market

        достопримечательностиLst.add (аттракцион)

        Привлечение = Притяжение ()
        Привлечение.title = "Керри Парк"
        Привлечение.description = "Керри Парк - это парк площадью 1,26 акра на" +
                «южный склон холма Королевы Анны в Сиэтле, штат Вашингтон», +
                «расположен на углу Второй авеню Вест и Вест Хайленд Драйв»
        Привлечение.hours = "4:00 - 23:00"
        достопримечательности.image = R.drawable.kerry_park

        достопримечательностиLst.add (аттракцион)

        Привлечение = Притяжение ()
        Привлечение.title = "Национальный парк горы Рейнир"
        Привлечение.description = "Гора Рейнир - самая высокая гора Каскада" +
                «Хребет Тихоокеанского Северо-Запада и самая высокая гора» +
                "в американском штате Вашингтон".
        Привлечение.hours = "10:00 - 17:00"
        Привлечение.image = R.drawable.mountrainier

        достопримечательностиLst.add (аттракцион)

        Привлечение = Притяжение ()
        достопримечательности.title = "Музей авиации"
        Привлечение.description = "Музей авиации является частной некоммерческой организацией" +
                «и космический музей на северо-западе США».
                «Он расположен к югу от Сиэтла».
        Привлечение.hours = "10:00 - 17:00"
        Привлечение.image = R.drawable.musium_of_flights

        достопримечательностиLst.add (аттракцион)

        Привлечение = Притяжение ()
        Привлечение.title = "Водопад Сноквалми"
        Привлечение.description = "Водопад Сноквалми - один из водопадов штата Вашингтон" +
                «самые популярные живописные достопримечательности.Более 1,5 миллиона "+
                «посетители приходят к водопаду каждый год».
        Привлечение.hours = "4:00 - 23:00"
        Привлечение.image = R.drawable.snoqualmie_falls

        достопримечательностиLst.add (аттракцион)

        достопримечательностиByCity.put ("Сиэтл", достопримечательностиLst)
    }
}  
Схема действия списка
  

    
  
Макет элемента
  


    

    

     
.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Theme: Overlay by Kaira Extra Text
Cape Town, South Africa