Skip to content

HW_1_Kuzmin #174

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

Open
wants to merge 8 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 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
10 changes: 8 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 34
buildToolsVersion "30.0.3"

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

Expand Down Expand Up @@ -42,4 +42,10 @@ dependencies {
implementation 'com.google.android.material:material:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'com.squareup.picasso:picasso:2.71828'

implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1"

implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2"
testImplementation 'junit:junit:4.12'
}
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.

25 changes: 21 additions & 4 deletions app/src/main/java/otus/homework/coroutines/CrashMonitor.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,27 @@
package otus.homework.coroutines

import android.content.Context
import android.util.Log
import android.widget.Toast
import java.net.SocketTimeoutException

object CrashMonitor {

/**
* Pretend this is Crashlytics/AppCenter
*/
fun trackWarning() {
private const val SOCKET_TIME_EXCEPTION_ANSWER = "Не удалось получить ответ от сервера."

fun trackWarning(e: Throwable) {
Log.d(this.toString(), e.toString())
}

fun trackWarning(context: Context, e: Throwable) {
when(e) {
is SocketTimeoutException -> {
Toast.makeText(context, SOCKET_TIME_EXCEPTION_ANSWER, Toast.LENGTH_SHORT).show()
}
else -> {
Log.d(this.toString(), e.toString())
Toast.makeText(context, e.message, Toast.LENGTH_SHORT).show()
}
}
}
}
30 changes: 0 additions & 30 deletions app/src/main/java/otus/homework/coroutines/MainActivity.kt

This file was deleted.

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

import otus.homework.coroutines.domain.CatImage
import otus.homework.coroutines.domain.Fact
import retrofit2.http.GET

interface CatsService {
@GET("fact")
suspend fun getCatFact(): Fact

@GET("https://api.thecatapi.com/v1/images/search")
suspend fun getCatImage(): List<CatImage>
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package otus.homework.coroutines
package otus.homework.coroutines.data

import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
Expand Down
10 changes: 10 additions & 0 deletions app/src/main/java/otus/homework/coroutines/domain/CatImage.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package otus.homework.coroutines.domain

import com.google.gson.annotations.Expose
import com.google.gson.annotations.SerializedName

data class CatImage(
@SerializedName("url")
@Expose
val imageUrl: String?
)
6 changes: 6 additions & 0 deletions app/src/main/java/otus/homework/coroutines/domain/CatModel.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package otus.homework.coroutines.domain

data class CatModel(
val fact: Fact,
val image: CatImage?
)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package otus.homework.coroutines
package otus.homework.coroutines.domain

import com.google.gson.annotations.SerializedName

Expand All @@ -20,5 +20,7 @@ data class Fact(
@field:SerializedName("user")
val user: String,
@field:SerializedName("updatedAt")
val updatedAt: String
val updatedAt: String,

val fact: String
)
6 changes: 6 additions & 0 deletions app/src/main/java/otus/homework/coroutines/domain/Result.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package otus.homework.coroutines.domain

sealed class Result {
class Error(val exception: Throwable): Result()
class Success(val catModel: CatModel): Result()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package otus.homework.coroutines.presentation

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import otus.homework.coroutines.data.DiContainer
import otus.homework.coroutines.domain.CatImage
import otus.homework.coroutines.domain.CatModel
import otus.homework.coroutines.domain.Fact
import otus.homework.coroutines.domain.Result
import java.net.SocketTimeoutException

class CatViewModel: ViewModel(){

private val catsService = DiContainer().service

private val _result = MutableLiveData<Result>()
val result: LiveData<Result> get() = _result

private val exceptionHandler = CoroutineExceptionHandler { _, throwable ->
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Предлагаю оставить CoroutineExceptionHandler длдя необработанных исключений, а socketexction обработать через try/catch или runCatching

_result.value = Result.Error(throwable)
}

fun onInitComplete() {
viewModelScope.launch(exceptionHandler) {

val deferredFact = withContext(Dispatchers.IO) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Так, а тут же не поправил, у тебя последовательные запросы

try {
catsService.getCatFact()
} catch (e: SocketTimeoutException) {
_result.value = Result.Error(e)
}
}

val deferredImage = withContext(Dispatchers.IO) {
try {
catsService.getCatImage()
} catch (e: SocketTimeoutException) {
_result.value = Result.Error(e)
}
}

if (deferredFact != Unit && deferredImage != Unit) {
val catModel =
CatModel(
deferredFact as Fact,
(deferredImage as List<CatImage>).first()
)
_result.value = Result.Success(catModel)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package otus.homework.coroutines.presentation

import kotlinx.coroutines.*
import otus.homework.coroutines.CrashMonitor
import otus.homework.coroutines.ICatsView
import otus.homework.coroutines.data.CatsService
import otus.homework.coroutines.domain.CatImage
import otus.homework.coroutines.domain.CatModel
import otus.homework.coroutines.domain.Fact
import java.net.SocketTimeoutException

class CatsPresenter(
private val catsService: CatsService
) {

private var _catsView: ICatsView? = null
private val presenterScope = CoroutineScope(Dispatchers.Main + CoroutineName("CatsCoroutine"))

fun onInitComplete() {
presenterScope.launch {

val deferredFact = withContext(Dispatchers.IO) {
try {
catsService.getCatFact()
} catch (e: SocketTimeoutException) {
_catsView?.showExceptionMessage("Не удалось получить ответ от сервера.")
showExceptionMessage("Не удалось получить ответ от сервера.")
} catch (e: Exception) {
CrashMonitor.trackWarning(e)
showExceptionMessage(e.message ?: "")
}
}

val deferredImage = withContext(Dispatchers.IO) {
try {
catsService.getCatImage()
} catch (e: SocketTimeoutException) {
showExceptionMessage("Не удалось получить ответ от сервера.")
} catch (e: Exception) {
CrashMonitor.trackWarning(e)
showExceptionMessage(e.message ?: "")
}
}

try {
val fact = deferredFact as Fact
val catImage = (deferredImage as List<CatImage>).first()
_catsView?.populate(CatModel(fact, catImage))
} catch (e: ClassCastException) {
CrashMonitor.trackWarning(e)
}
}
}

private fun showExceptionMessage(text: String) {
_catsView?.showExceptionMessage(text)
}

fun attachView(catsView: ICatsView) {
_catsView = catsView
}
fun detachView() {
_catsView = null
}
fun cancelAllJobs() {
presenterScope.cancel()
}
}
Loading