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 5 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.

21 changes: 17 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,23 @@
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(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,35 @@
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.async
import kotlinx.coroutines.launch
import otus.homework.coroutines.data.DiContainer
import otus.homework.coroutines.domain.CatModel
import otus.homework.coroutines.domain.Result

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() {
val deferredFact = viewModelScope.async { catsService.getCatFact() }
Copy link
Collaborator

Choose a reason for hiding this comment

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

А почему ты их вынес за пределы launch?


val deferredImage = viewModelScope.async { catsService.getCatImage() }

viewModelScope.launch(exceptionHandler) {
val catModel = CatModel(deferredFact.await(), deferredImage.await().first())
_result.postValue(Result.Success(catModel))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Ты тут уже на главном потоке, можно setValue вызвать

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,37 @@ package otus.homework.coroutines
import android.content.Context
import android.util.AttributeSet
import android.widget.Button
import android.widget.ImageView
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import com.squareup.picasso.Picasso
import otus.homework.coroutines.domain.CatModel
import otus.homework.coroutines.presentation.CatViewModel

class CatsView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr), ICatsView {

var presenter :CatsPresenter? = null
var catViewModel: CatViewModel? = null

override fun onFinishInflate() {
super.onFinishInflate()
findViewById<Button>(R.id.button).setOnClickListener {
presenter?.onInitComplete()
catViewModel?.onInitComplete()
}
}

override fun populate(fact: Fact) {
findViewById<TextView>(R.id.fact_textView).text = fact.text
override fun populate(model: CatModel) {
findViewById<TextView>(R.id.fact_textView).text = model.fact.fact

Picasso.get()
.load(model.image?.imageUrl)
.into(findViewById<ImageView>(R.id.iv_cat))
}
}

interface ICatsView {

fun populate(fact: Fact)
fun populate(model: CatModel)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package otus.homework.coroutines.presentation

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProvider
import otus.homework.coroutines.CatsView
import otus.homework.coroutines.CrashMonitor
import otus.homework.coroutines.R
import otus.homework.coroutines.domain.Result

class MainActivity : AppCompatActivity() {

private val catViewModel by lazy {
ViewModelProvider(this)[CatViewModel::class.java]
}

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

val view = layoutInflater.inflate(R.layout.activity_main, null) as CatsView
setContentView(view)

view.catViewModel = catViewModel

catViewModel.result.observe(this) {
when(it) {
is Result.Success -> view.populate(it.catModel)
is Result.Error -> CrashMonitor.trackWarning(this, it.exception)
}
}

catViewModel.onInitComplete()
}
}
12 changes: 11 additions & 1 deletion app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,17 @@
android:layout_width="match_parent"
android:padding="16dp"
android:layout_height="match_parent"
tools:context=".MainActivity">
tools:context=".presentation.MainActivity">

<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_cat"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="@id/fact_textView"
/>

<TextView
android:id="@+id/fact_textView"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package otus.homework.coroutines

import org.junit.Test

import org.junit.Assert.*
import org.junit.Test

/**
* Example local unit test, which will execute on the development machine (host).
Expand Down