Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

With view model #175

Open
wants to merge 4 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 12 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,22 @@

### Перейти с коллбеков на саспенд функции и корутины

1. Поменять возвращаемый тип в `CatsService` и добавить модификатор `suspend`
2. Переписать логику в презентере с `Callback` на корутины и `suspend` функции
3. Реализовать свой скоуп: PresenterScope с `MainDispatcher` и CoroutineName("CatsCoroutine") в качестве элементов контекста
4. Добавить обработку исключений через try-catch. В случае `java.net.SocketTimeoutException` показываем Toast с текстом "Не удалось получить ответ от сервером". В остальных случаях логируем исключение в `otus.homework.coroutines.CrashMonitor` и показываем Toast с `exception.message`
5. Не забываем отменять Job в `onStop()`
+1. Поменять возвращаемый тип в `CatFactsService` и добавить модификатор `suspend`
+2. Переписать логику в презентере с `Callback` на корутины и `suspend` функции
+3. Реализовать свой скоуп: PresenterScope с `MainDispatcher` и CoroutineName("CatsCoroutine") в качестве элементов контекста
+4. Добавить обработку исключений через try-catch. В случае `java.net.SocketTimeoutException` показываем Toast с текстом "Не удалось получить ответ от сервером". В остальных случаях логируем исключение в `otus.homework.coroutines.CrashMonitor` и показываем Toast с `exception.message`
+5. Не забываем отменять Job в `onStop()`

### Добавить к запросу фактов запрос рандомных картинок с [https://aws.random.cat/meow](https://aws.random.cat/meow)

1. На каждый рефреш экрана должен запрашиваться факт + картинка: добавляем сетевой запрос и реализуем логику аналогичную первой задаче. Для загрузки изображений уже подключена библиотека [Picasso](https://github.com/square/picasso)
2. В метод `view.populate` передаем 1 аргумент, поэтому необходимо реализовать модель презентейшен слоя в которой будут содержаться необходимые данные для рендеринга(текст и ссылка на картинку)
3. Отменятся запросы должны одновременно
+1. На каждый рефреш экрана должен запрашиваться факт + картинка: добавляем сетевой запрос и реализуем логику аналогичную первой задаче. Для загрузки изображений уже подключена библиотека [Picasso](https://github.com/square/picasso)
+2. В метод `view.populate` передаем 1 аргумент, поэтому необходимо реализовать модель презентейшен слоя в которой будут содержаться необходимые данные для рендеринга(текст и ссылка на картинку)
Оптимизируем: конвертер добавим, запустим запросы в сеть одновременно, одновременно попробуем джобы отменить
Для этого сделаем async запуск 2 корутин
+5. Отменятся запросы должны одновременно

### Реализовать решение ViewModel

1. Реализовать наследника `ViewModel` и продублировать в нем логику из `CatsPresenter`, с необходимыми изменениями. Используйте `viewModelScope` в качестве скоупа.
2. Добавить логирование ошибок через CoroutineExceptionHanlder. Используйте класс CrashMonitor в качестве фейкового CrashMonitor инструмента
+1. Реализовать наследника `ViewModel` и продублировать в нем логику из `CatsPresenter`, с необходимыми изменениями. Используйте `viewModelScope` в качестве скоупа.
+2. Добавить логирование ошибок через CoroutineExceptionHanlder. Используйте класс CrashMonitor в качестве фейкового CrashMonitor инструмента
3. Создать sealed класс `Result`. Унаследовать от него классы `Success<T>`, `Error`. Использовать эти классы как стейт необходимый для рендеринга/отображени ошибки
8 changes: 6 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ plugins {
}

android {
compileSdkVersion 30
compileSdkVersion 32
buildToolsVersion "30.0.3"

defaultConfig {
applicationId "otus.homework.coroutines"
minSdkVersion 23
targetSdkVersion 30
targetSdkVersion 32
versionCode 1
versionName "1.0"

Expand All @@ -34,6 +34,10 @@ android {

dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0'
implementation 'androidx.fragment:fragment-ktx:1.3.6'
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Coroutines">
<activity android:name=".MainActivity"
<activity android:name=".presentation.MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
Expand Down
35 changes: 0 additions & 35 deletions app/src/main/java/otus/homework/coroutines/CatsPresenter.kt

This file was deleted.

10 changes: 0 additions & 10 deletions app/src/main/java/otus/homework/coroutines/CatsService.kt

This file was deleted.

32 changes: 0 additions & 32 deletions app/src/main/java/otus/homework/coroutines/CatsView.kt

This file was deleted.

10 changes: 0 additions & 10 deletions app/src/main/java/otus/homework/coroutines/CrashMonitor.kt

This file was deleted.

16 changes: 0 additions & 16 deletions app/src/main/java/otus/homework/coroutines/DiContainer.kt

This file was deleted.

24 changes: 0 additions & 24 deletions app/src/main/java/otus/homework/coroutines/Fact.kt

This file was deleted.

30 changes: 0 additions & 30 deletions app/src/main/java/otus/homework/coroutines/MainActivity.kt

This file was deleted.

11 changes: 11 additions & 0 deletions app/src/main/java/otus/homework/coroutines/data/CatFactsService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package otus.homework.coroutines.data

import otus.homework.coroutines.models.Fact
import otus.homework.coroutines.models.Result
import retrofit2.http.GET

interface CatFactsService {

@GET("fact")
suspend fun getCatFact() : Fact
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package otus.homework.coroutines.data

import otus.homework.coroutines.models.Image
import otus.homework.coroutines.models.Result
import retrofit2.http.GET

interface CatImagesService {
@GET("search")
suspend fun getCatImage(): Array<Image>
Alienstemple marked this conversation as resolved.
Show resolved Hide resolved
}
30 changes: 30 additions & 0 deletions app/src/main/java/otus/homework/coroutines/di/DiContainer.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package otus.homework.coroutines.di

import otus.homework.coroutines.data.CatFactsService
import otus.homework.coroutines.data.CatImagesService
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

class DiContainer {

val catFactsService by lazy {
Retrofit.Builder()
.baseUrl(FACT_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(CatFactsService::class.java)
}

val catImagesService by lazy {
Retrofit.Builder()
.baseUrl(IMAGE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(CatImagesService::class.java)
}

companion object {
private const val FACT_URL = "https://catfact.ninja/"
private const val IMAGE_URL = "https://api.thecatapi.com/v1/images/"
}
}
13 changes: 13 additions & 0 deletions app/src/main/java/otus/homework/coroutines/domain/CrashMonitor.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package otus.homework.coroutines.domain

import android.util.Log

object CrashMonitor {

/**
* Pretend this is Crashlytics/AppCenter
*/
fun trackWarning(warningMessage: String) {
Log.d("TAG", "Crash logged: $warningMessage")
}
}
6 changes: 6 additions & 0 deletions app/src/main/java/otus/homework/coroutines/models/Cat.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package otus.homework.coroutines.models

data class Cat(
val fact: String,
val imageUrl: String
)
10 changes: 10 additions & 0 deletions app/src/main/java/otus/homework/coroutines/models/Fact.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package otus.homework.coroutines.models

import com.google.gson.annotations.SerializedName

data class Fact(
@field:SerializedName("fact")
val fact: String,
@field:SerializedName("length")
val length: Int
)
14 changes: 14 additions & 0 deletions app/src/main/java/otus/homework/coroutines/models/Image.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package otus.homework.coroutines.models

import com.google.gson.annotations.SerializedName

data class Image(
@field:SerializedName("id")
val id: String,
@field:SerializedName("url")
val url: String,
@field:SerializedName("width")
val width: Int,
@field:SerializedName("height")
val height: Int
)
9 changes: 9 additions & 0 deletions app/src/main/java/otus/homework/coroutines/models/Result.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package otus.homework.coroutines.models

sealed class Result<T>(
val data: T? = null,
val error: String? = null
) {
class Success<T> (data: T): Result<T>(data = data)
class Error<T> (error: String): Result<T>(error = error)
}
Loading