- Retrofit на Android с Kotlin
- 0. Установка
- 1. Добавление зависимостей
- 2. Создание классов данных
- Классы данных в Котлине
- 3. Создание API-интерфейса
- Синглтоны и сопутствующие объекты в Котлине
- 4. Создание репозитория
- Строковые шаблоны в Котлине
- 5. Делаем запрос и получаем ответ API при помощи RxJava
- Полезные ссылки:
- Заключение
- Retrofit2 на Android используя Kotlin
- 0. Создание проекта
- 1. Добавление зависимостей
- 2. Добавление data class’ов
- 3. Создание Client
- 4. Работа с Interface
- 5. Common
- 6. Макет
- 7. Adapter
- 8. MainActivity
- SalaSuresh / ApiClient.kt
Retrofit на Android с Kotlin
Одним из самых захватывающих объявлений на Google I/O в этом году стала официальная поддержка Kotlin для разработки под Android.
Котлин на самом деле не новый язык, ему уже >5 лет и он довольно зрелый. Здесь вы можете получить более подробную информацию о языке
Я планирую поделиться некоторыми «практиками» использования Kotlin в разработке Android.
Retrofit — очень популярная библиотека для работы с сетью, и она широко используется в сообществе разработчиков. Даже Google использует его в своих образцах кода.
В этой статье я расскажу о том, как использовать REST API в ваших приложениях с помощью Retrofit + Kotlin + RxJava. Мы будем использовать API Github для получения списка разработчиков Java в Омске, Россия. Также, я затрону некоторые особенности языка программирования и расскажу о том, как мы можем применять их к тому, что мы, разработчики Android, делаем ежедневно — вызывать API.
0. Установка
В Android Studio 3.0 (Preview) теперь есть встроенная поддержка Kotlin, без ручной установки плагинов. Отсюда можно установить preview-версию.
1. Добавление зависимостей
Чтобы использовать Retrofit, вам нужно добавить зависимости в файл build.gradle:
RxJava2 поможет сделать наши вызовы реактивными.
GSON-конвертер будет обрабатывать десериализацию и сериализацию тел запроса и ответа.
RxAndroid поможет нам с привязкой RxJava2 к Android.
2. Создание классов данных
Как правило, следующим шагом является создание классов данных, которые являются POJO (Plain Old Java Objects) и которые будут представлять ответы на вызовы API.
С API Github пользователи будут представлены как объекты.
Как это будет выглядеть на Kotlin:
Классы данных в Котлине
Классы данных в Kotlin — это классы, специально разработанные для хранения данных.
Компилятор Kotlin автоматически помогает нам реализовать методы equals (), hashCode () и toString () в классе, что делает код еще короче, потому что нам не нужно это делать самостоятельно.
Мы можем переопределить реализацию по умолчанию любого из этих методов путем определения метода.
Отличной особенностью является то, что мы можем создавать результаты поиска в одном файле Kotlin — скажем, SearchResponse.kt. Наш окончательный класс ответа на поиск будет содержать все связанные классы данных и выглядеть следующим образом:
SearchResponse.kt
3. Создание API-интерфейса
Следующим шагом, который мы обычно делаем в Java, является создание интерфейса API, который мы будем использовать для создания запросов и получения ответов.
Как правило, в Java я хотел бы создать удобный «фабричный» класс, который создает службу API, когда это необходимо, и я бы сделал что-то вроде этого:
GithubApiService.java
Чтобы использовать этот интерфейс, мы делаем следующие вызовы:
Чтобы повторить тоже самое в Котлине, у нас будет эквивалентный интерфейс GithubApiService.kt, который будет выглядеть так:
GithubApiService.kt
Использование этого интерфейса и фабричного класса будет выглядеть так:
Обратите внимание, что нам не нужно было использовать «имя» сопутствующего объекта для ссылки на метод, мы использовали только имя класса.
Синглтоны и сопутствующие объекты в Котлине
Чтобы понять, какие сопутствующие объекты в Котлине есть, мы должны сначала понять, какие объявления объектов находятся в Котлине. Объявление объекта в Котлине — это способ, которым одиночный элемент создается в Котлине.
Синглтоны в Котлине так же просты, как объявление объекта и присвоение ему имени. Например:
Использование указанного выше объявления объекта:
Благодаря этому мы смогли создать поставщика, который предоставит нам экземпляр репозитория (который поможет нам подключиться к API Github через GithubApiService).
Объявление объекта инициализируется при первом доступе — так же, как работает Singleton.
Однако, объекты-компаньоны — это тип объявления объекта, который соответствует ключевому слову companion. Объекты Companion можно сравнить с статическими методами или полями на Java. Фактически, если вы ссылаетесь на объект-компаньон с Java, он будет выглядеть как статический метод или поле.
Сопутствующий объект — это то, что используется в версии GithubApiService.kt Kotlin выше.
4. Создание репозитория
Поскольку мы стараемся как можно больше абстрагировать наши процессы, мы можем создать простой репозиторий, который обрабатывает вызов GithubApiService и строит строку запроса.
Строка запроса, соответствующая нашей спецификации для этого демонстрационного приложения (для поиска разработчиков Java в Омске) с использованием API Github, — это местоположение: Omsk + language: Java, поэтому мы создадим метод в репозитории, который позволит нам построить эту строку, передавая местоположение и язык в качестве параметров.
Наш поисковый репозиторий будет выглядеть так:
Строковые шаблоны в Котлине
В блоке вышеприведенного кода мы использовали функцию Kotlin, называемую «String templates», чтобы построить нашу строку запроса. Строковые шаблоны начинаются со знака доллара — $ и значение переменной, следующей за ней, конкатенируется с остальной частью строки. Это аналогичная функция для строковой интерполяции в groovy.
5. Делаем запрос и получаем ответ API при помощи RxJava
Теперь, когда мы настроили наши классы ответов, наш интерфейс репозитория, теперь мы можем сделать запрос и получить ответ API с помощью RxJava. Этот шаг похож на то, как мы будем делать это на Java. В коде Kotlin это выглядит так:
Мы сделали наш запрос и получили ответ. Теперь можем делать с ним все, что захотим.
Полезные ссылки:
Заключение
Таким образом, в этом посте мы рассмотрели некоторые интересные возможности/свойства языка Kotlin и способы их применения при использовании Retrofit + RxJava для сетевых вызовов.
- Классы данных
- Объявления объектов
- Сопутствующие объекты
- Строковые шаблоны
- Взаимодействие с Java
Источник
Retrofit2 на Android используя Kotlin
Сегодня мы рассмотрим работу с Retrofit 2. Правды ради стоит отметить, что мы будем работать еще с 2 отдельными библиотеками, а именно Picasso и Spots-dialog.
Это статью я рекомендую к прочтению только для тех, кто еще не работал с Retrofit 2. Ведь в этой статье я буду описывать все максимально подробно, чтобы все поняли.
0. Создание проекта
Здесь все максимально просто, создаем новый проект в Android Studio, выбираем Empty Activity. Далее необходимо выбрать язык программирования, у нас это будет Kotlin.
1. Добавление зависимостей
Сейчас нам нужно добавить все необходимые библиотеки, поэтому мы заходим в build.gradle и добавляем следующие:
Как вы уже могли заметить здесь мы добавили все необходимые библиотеки, в том числе и Spots progress dialog. Более подробно вы можете ознакомится с этим здесь. После чего в build.gradle(Modul:app) мы должны вставить это:
Осталось лишь зайти в manifests и добавить разрешение на использование телефона
2. Добавление data class’ов
Прежде чем перейти к второму пункту нам нужно узнать, а откуда получать данные? Парсить будет отсюда.
Отлично, далее копируем содержимое этого сайта и идем сюда. Сюда мы вставляем ранее скопированный текст с нашего сайта, после того как мы нажали на tree нам выдался список, раскроем его, теперь мы видим, что у нас есть 8 объектов. Если кто-то не понял, то я покажу вам скрин:
То что вы видите справа это наш текст, который мы скопировали, а то что справа, это уже обработанные данные.
Теперь вернемся к Android Studio мы создаем папку называем ее Model там мы создаем kotlin class и называем ее Movie из обычного класса мы преобразуем data class, мы просто перед class добавим data, а фигурные скобки заменяем на круглые, далее в скобках указываем переменные которые мы уже подсмотрели на сайте, кстати переменные должны быть нулабельного типа.
Если вы зададитесь вопросом, а почему папка называется Model, то я вам скажу, что:
Model — это логика, которая связанна с данными приложения. Другими словами это POJO, классы работы с API, базой данных.
3. Создание Client
Далее мы создаем папку Retrofit, а в папке мы создаем object, и называем его RetrofitClient, далее создаем переменную retrofit типа Retrofit, после этого создаем функцию и называем ее getCleint(baseUrl: String) и тип возвращаемого значения Retrofit. В теле функции необходимо выполнить проверку retrofit’a на null и если ретрофит равен null, то мы к ретрофиту присваиваем Retrofit.Builder() присоединяем baseUrl с параметром baseUrl далее присоединяем метод addconverterFactory c параметром GsonConverterFactory.create() и билдим с помощью метода build() и возвращаем ретрофит в ненулевой тип
Builder в Retrofit — это экземпляр, который использует интерфейс и API Builder, чтобы задать определение конечной точки URL для операций HTTP
4. Работа с Interface
Interface — нужен для создания абстрактных классов.
Создаем пакет Interface в него мы кладем Interface и называем RetrofitServieces. Создаем Get запрос в скобках пишем кавычки, а в кавычках указывает ветку с которой будем парсить данные у нас это marvel. Но перед этим стоит сказать что такое GET и POST запрос
GET — запрашивает данные с определенного ресурса(сайта)
POST — отправляет данные на сервер для последующей обработки
Хорошо, теперь нужно создать функцию getMovieList, которая должна будет возвращать Call типа MutableList, a MutableList должен быть типа Movie
5. Common
Сейчас мы должны создать папку Common, в эту папку мы кладем object и называем его Common, создаем переменную, называем ее BASE_URL и в нее мы должны положить ссылку с которой парсим данные, но не класть последнюю ветку, так как именно с нее мы получаем данные. Создаем переменную retrofitServices, у нее есть метод get() к нему мы присваиваем RetrofitClient, а уже потом к RetrofitClient мы сетим метод getClient c параметром RetrofitServices::class.java
6. Макет
Переходим к activity_main.xml и добавляем туда RecyclerView
В папке layout создаем item_layout в root element указываем CardView
7. Adapter
Теперь мы должны создать пакет Adapter, в него мы кладем класс и называем его MyMovieAdapter
Adapter отвечает за извлечение данных из набора данных и за создание объектов View по основе этих данных.
В классе MyMovieAdapter мы создаем переменные, которые будут доступны только в этом классе private val movieList: MutableList типа Movie и указываем тип возвращаемого значения у нас это будет RecyclerView.Adapter типа MyMovieAdapter.MyViewHolder
Имплементируем методы, а именно onCreateViewHolder, getItemCount и onBindViewHolder.
Создаем класс MyViewHolder, в данном класс указываем параметр itemView: View и тип возвращаемого значения RecyclerView.ViewHolder и в тело данного класса мы помещаем переменные, например:
val image:ImageView = itemView.image_movie image_movie у нас тянется из item_layout
и так указываем для всех оставшихся view элементов.
Создам функцию bind c параметром listItem: Movie, здесь мы можем сделать наши view элементы кликабельными, я думаю вы умеете это делать.
Далее мы переделываем getItemCount() в override fun getItemCount() = movieList.size. Здесь все просто, мы создали функцию и возвращаем movieList.size. Отлично, осталось лишь разобраться с onBindViewHolder и onCreateViewHolder
onCreateViewHolder — создает новый объект ViewHolder всякий раз, когда RecyclerView нуждается в этом.
onBindViewHolder — принимает объект ViewHolder и устанавливает необходимые данные для соответствующей строки во view компоненте
Сейчас мы разберем случай c onCreateViewHolder тип возвращаемого значения MyViewHolder.
Создаем переменную itemView присваиваем ей LayoutInflater.from(parent.context).inflate(R.layout.item_layout, parent, false) и возвращаем MyViewHolder с параметром itemView. Теперь переходим к onBindViewHolder в теле мы создаем переменную listItem: Movie и присваиваем movieList[position]. Далее к holder’y мы присоединяем метод bind с параметрами listItem. Далее используем библиотеку Picasso.
Picasso.get().load(movieList[position].imageurl).into(holder.image). После чего добавляем holder.txt_name.text = movieList[position].name, и так мы делаем со всеми нашими view элементами
8. MainActivity
Отлично! Осталось совсем чуть-чуть. Переходим в MainActivity для начала мы создадим переменные, и чтобы не объявлять их типа null объявим их через lateinit var mService: RetrofitServices, нам необходимо создать еще 3 таких, а именно: LinearLayoutManager, MyMovieAdapter, AlertDialog. Вы можете назвать их как хотите, это роли не сыграет. В методе onCreate мы к RetrofitServices присваиваем Common.retrofitServices. На следующей строке к нашему recyclerView мы присоединяем setHasFixedSize(true) — благодаря этому методу мы сможем оптимизировать свой список, после мы к нашему layoutManager присваиваем LinearLayoutManager(this).
Layout Manager — это вещь, которая отвечает позиционирование View компонентов, которые больше не видны пользователю. Далее все также легко к нашему списку присоединяем layoutManager и уже к этому присваиваем layoutManager. Хорошо, теперь работа с библиотекой SpotsDialog. указываем ранее названную переменную с типом AlertDialog присваиваем SpotsDialog присоединяем метод Builder после этого присоединяем метод setCancelablec c параметром true к этому мы должны присоединить метод setContext c параметром this и присоединить метод build.
Теперь мы должны создать новую функцию за пределами метода onCreate назваться функция будет getAllMovieList. В теле этой функции мы должны указать наш dialog и присоединить к нему метод show()
далее к mService добавляем метод getMovieList .enqueue(object: Callback < )
Сейчас нам необходимо имплементировать методы, у нас их две onResponse и onFailure
и в onResponse, а именно в теле данного метода мы к adapter’y присваиваем
далее к adapter’y присваиваем метод notifyDataSetChanged(). К нашему списку мы присоединяем adapter и присваиваем adapter. после к dialog присваиваем метод dismiss(). Это значит то, что наш диалог пропадет после того, как наши данные загрузятся.
Источник
SalaSuresh / ApiClient.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
xml version = » 1.0 » encoding = » utf-8 » ?> |
android .support.constraint.ConstraintLayout xmlns : android = » http://schemas.android.com/apk/res/android « |
xmlns : tools = » http://schemas.android.com/tools « |
android : layout_width = » match_parent « |
android : layout_height = » match_parent « |
tools : context = » com.example.suresh.myapplication.MainActivity » > |
android .support.v7.widget.RecyclerView |
android : id = » @+id/recyclerview_demo « |
android : layout_width = » match_parent « |
android : layout_height = » match_parent »/> |
android .support.constraint.ConstraintLayout> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
package com.suresh.retrofitdemo |
import retrofit2.Retrofit |
import retrofit2.converter.gson.GsonConverterFactory |
/* * |
* Created by Dumadu on 26-Oct-17. |
*/ |
public class ApiClient < |
public var BASE_URL : String = » https://next.json-generator.com/api/json/get/ « |
public var retrofit : Retrofit ? = null |
public fun getApiClient (): Retrofit ? < |
if (retrofit == null ) < |
retrofit = Retrofit . Builder () |
.baseUrl( BASE_URL ) |
.addConverterFactory( GsonConverterFactory .create()).build() |
> |
return retrofit |
> |
> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
package com.suresh.retrofitdemo |
import retrofit2.Call |
import retrofit2.http.POST |
/* * |
* Created by Dumadu on 26-Oct-17. |
*/ |
public interface ApiInterface < |
@POST( » E1Pn7khWG » ) |
fun getHospitalsList (): Call ArrayList Hospitals >> |
> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
package com.suresh.retrofitdemo |
import com.google.gson.annotations.SerializedName |
/* * |
* Created by Dumadu on 26-Oct-17. |
*/ |
public class Hospitals < |
public var id : String? = null |
@SerializedName( » hospital_name » ) |
public var hospitalName : String? = null |
public var address : String? = null |
> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
xml version = » 1.0 » encoding = » utf-8 » ?> |
LinearLayout xmlns : android = » http://schemas.android.com/apk/res/android « |
android : layout_width = » match_parent « |
android : layout_height = » wrap_content « |
android : orientation = » horizontal » > |
ImageView |
android : id = » @+id/image_picture « |
android : layout_width = » 50dp « |
android : layout_height = » 50dp « |
android : padding = » 5dp « |
android : src = » @mipmap/ic_launcher_round »/> |
LinearLayout |
android : layout_width = » match_parent « |
android : layout_height = » wrap_content « |
android : orientation = » vertical « |
android : padding = » 5dp » > |
TextView |
android : id = » @+id/text_name « |
android : layout_width = » match_parent « |
android : layout_height = » wrap_content « |
android : text = » Name « |
android : textStyle = » bold »/> |
TextView |
android : id = » @+id/text_address « |
android : layout_width = » match_parent « |
android : layout_height = » wrap_content « |
android : text = » Message »/> |
LinearLayout > |
LinearLayout > |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
package com.suresh.retrofitdemo |
import android.os.Bundle |
import android.support.v7.app.AlertDialog |
import android.support.v7.app.AppCompatActivity |
import android.support.v7.widget.DividerItemDecoration |
import android.support.v7.widget.LinearLayoutManager |
import android.support.v7.widget.RecyclerView |
import android.widget.Toast |
import com.example.suresh.myapplication.R |
import retrofit2.Call |
import retrofit2.Callback |
import retrofit2.Response |
/* * |
* Created by Dumadu on 26-Oct-17. |
*/ |
class MainActivity : AppCompatActivity (), RecyclerViewAdapter.hospitalClickListener < |
var hospitalsData : ArrayList Hospitals > = ArrayList () |
override fun getItem ( position : Int ) < |
val alertDialog = AlertDialog . Builder ( this @MainActivity) |
alertDialog.setTitle(hospitalsData.get(position).hospitalName) |
alertDialog.setMessage(hospitalsData.get(position).address) |
alertDialog.setPositiveButton( » OK » ) |
Toast .makeText( this @MainActivity, » OK » , Toast . LENGTH_SHORT ).show() |
> |
// alertDialog.setNegativeButton(«No») |
// Toast.makeText(this@MainActivity, «No», Toast.LENGTH_SHORT).show() |
// > |
alertDialog.show() |
> |
override fun onCreate ( savedInstanceState : Bundle ? ) < |
super .onCreate(savedInstanceState) |
setContentView( R .layout.activity_main) |
var recyclerView : RecyclerView = findViewById( R .id.recyclerview_demo) |
recyclerView.layoutManager = LinearLayoutManager ( this ) |
recyclerView.addItemDecoration( DividerItemDecoration ( this , DividerItemDecoration . VERTICAL )) |
var apiInterface : ApiInterface = ApiClient ().getApiClient() !! .create( ApiInterface :: class .java) |
apiInterface.getHospitalsList().enqueue( object : Callback ArrayList Hospitals >> < |
override fun onResponse ( call : Call ArrayList Hospitals >> ? , response : Response ArrayList Hospitals >> ? ) < |
hospitalsData = response?.body() !! |
recyclerView.adapter = RecyclerViewAdapter (response?.body() !! , this @MainActivity) |
> |
override fun onFailure ( call : Call ArrayList Hospitals >> ? , t : Throwable ? ) < |
> |
>) |
> |
> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Источник