From dba39d22fcbc00ffce71fa738bfbe145e3758d1d Mon Sep 17 00:00:00 2001 From: Ruslan Sabirov Date: Wed, 21 Jan 2026 16:55:04 +0300 Subject: [PATCH 1/3] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D1=88=D1=91=D0=BB?= =?UTF-8?q?=20=D1=81=20=D0=BA=D0=BE=D0=BB=D0=BB=D0=B1=D0=B5=D0=BA=D0=BE?= =?UTF-8?q?=D0=B2=20=D0=BD=D0=B0=20=D1=81=D0=B0=D1=81=D0=BF=D0=B5=D0=BD?= =?UTF-8?q?=D0=B4=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B8=20=D0=B8=20?= =?UTF-8?q?=D0=BA=D0=BE=D1=80=D1=83=D1=82=D0=B8=D0=BD=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 1 + .../otus/homework/coroutines/CatsPresenter.kt | 40 ++++++++++++++----- .../otus/homework/coroutines/CatsService.kt | 2 +- .../java/otus/homework/coroutines/CatsView.kt | 6 +++ .../otus/homework/coroutines/CrashMonitor.kt | 3 +- .../otus/homework/coroutines/MainActivity.kt | 1 + 6 files changed, 41 insertions(+), 12 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index a414e0e8..2562ee25 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -40,5 +40,6 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'com.google.android.material:material:1.11.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0" implementation 'com.squareup.picasso:picasso:2.71828' } \ No newline at end of file diff --git a/app/src/main/java/otus/homework/coroutines/CatsPresenter.kt b/app/src/main/java/otus/homework/coroutines/CatsPresenter.kt index e4b05120..134997c2 100644 --- a/app/src/main/java/otus/homework/coroutines/CatsPresenter.kt +++ b/app/src/main/java/otus/homework/coroutines/CatsPresenter.kt @@ -1,28 +1,42 @@ package otus.homework.coroutines +import kotlinx.coroutines.CoroutineName +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import retrofit2.Call import retrofit2.Callback import retrofit2.Response +import java.net.SocketTimeoutException class CatsPresenter( private val catsService: CatsService ) { private var _catsView: ICatsView? = null + private var job: Job? = null - fun onInitComplete() { - catsService.getCatFact().enqueue(object : Callback { + private val presenterScope = CoroutineScope( + Dispatchers.Main + CoroutineName("CatsCoroutine") + ) - override fun onResponse(call: Call, response: Response) { - if (response.isSuccessful && response.body() != null) { - _catsView?.populate(response.body()!!) + fun onInitComplete() { + job?.cancel() + job = presenterScope.launch { + try { + val fact = withContext(Dispatchers.IO) { + catsService.getCatFact() } + _catsView?.populate(fact) + } catch (e: SocketTimeoutException) { + _catsView?.showToast("Не удалось получить ответ от сервера") + } catch (e: Exception) { + CrashMonitor.trackWarning(e) + _catsView?.showToast(e.message ?: "Произошла ошибка") } - - override fun onFailure(call: Call, t: Throwable) { - CrashMonitor.trackWarning() - } - }) + } } fun attachView(catsView: ICatsView) { @@ -32,4 +46,10 @@ class CatsPresenter( fun detachView() { _catsView = null } + + fun onStop() { + job?.cancel() + job = null + } + } \ No newline at end of file diff --git a/app/src/main/java/otus/homework/coroutines/CatsService.kt b/app/src/main/java/otus/homework/coroutines/CatsService.kt index 479b2cfb..ca9e3f73 100644 --- a/app/src/main/java/otus/homework/coroutines/CatsService.kt +++ b/app/src/main/java/otus/homework/coroutines/CatsService.kt @@ -6,5 +6,5 @@ import retrofit2.http.GET interface CatsService { @GET("fact") - fun getCatFact() : Call + suspend fun getCatFact() : Fact } \ No newline at end of file diff --git a/app/src/main/java/otus/homework/coroutines/CatsView.kt b/app/src/main/java/otus/homework/coroutines/CatsView.kt index be04b2a8..11ccbbe2 100644 --- a/app/src/main/java/otus/homework/coroutines/CatsView.kt +++ b/app/src/main/java/otus/homework/coroutines/CatsView.kt @@ -4,6 +4,7 @@ import android.content.Context import android.util.AttributeSet import android.widget.Button import android.widget.TextView +import android.widget.Toast import androidx.constraintlayout.widget.ConstraintLayout class CatsView @JvmOverloads constructor( @@ -24,9 +25,14 @@ class CatsView @JvmOverloads constructor( override fun populate(fact: Fact) { findViewById(R.id.fact_textView).text = fact.fact } + + override fun showToast(message: String) { + Toast.makeText(context, message, Toast.LENGTH_SHORT).show() + } } interface ICatsView { fun populate(fact: Fact) + fun showToast(message: String) } \ No newline at end of file diff --git a/app/src/main/java/otus/homework/coroutines/CrashMonitor.kt b/app/src/main/java/otus/homework/coroutines/CrashMonitor.kt index 32e6b018..51cd183d 100644 --- a/app/src/main/java/otus/homework/coroutines/CrashMonitor.kt +++ b/app/src/main/java/otus/homework/coroutines/CrashMonitor.kt @@ -5,6 +5,7 @@ object CrashMonitor { /** * Pretend this is Crashlytics/AppCenter */ - fun trackWarning() { + fun trackWarning(throwable: Throwable? = null) { + throwable?.printStackTrace() } } \ No newline at end of file diff --git a/app/src/main/java/otus/homework/coroutines/MainActivity.kt b/app/src/main/java/otus/homework/coroutines/MainActivity.kt index a9dafb3b..aa720331 100644 --- a/app/src/main/java/otus/homework/coroutines/MainActivity.kt +++ b/app/src/main/java/otus/homework/coroutines/MainActivity.kt @@ -22,6 +22,7 @@ class MainActivity : AppCompatActivity() { } override fun onStop() { + catsPresenter.onStop() if (isFinishing) { catsPresenter.detachView() } From 74cbdc998302f0ba1a519b5b7ff25d0f274e05e8 Mon Sep 17 00:00:00 2001 From: Ruslan Sabirov Date: Wed, 21 Jan 2026 17:42:10 +0300 Subject: [PATCH 2/3] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB?= =?UTF-8?q?=20=D0=BA=20=D0=B7=D0=B0=D0=BF=D1=80=D0=BE=D1=81=D1=83=20=D1=84?= =?UTF-8?q?=D0=B0=D0=BA=D1=82=D0=BE=D0=B2=20=D0=B7=D0=B0=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D1=81=20=D1=80=D0=B0=D0=BD=D0=B4=D0=BE=D0=BC=D0=BD=D1=8B=D1=85?= =?UTF-8?q?=20=D0=BA=D0=B0=D1=80=D1=82=D0=B8=D0=BD=D0=BE=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/otus/homework/coroutines/CatImage.kt | 17 +++++++++++++ .../coroutines/CatPresentationModel.kt | 6 +++++ .../otus/homework/coroutines/CatsPresenter.kt | 18 ++++++++++---- .../otus/homework/coroutines/CatsService.kt | 4 ++++ .../java/otus/homework/coroutines/CatsView.kt | 22 +++++++++++++---- .../otus/homework/coroutines/DiContainer.kt | 24 +++++++++++++++++-- app/src/main/res/layout/activity_main.xml | 16 ++++++++++--- app/src/main/res/values/strings.xml | 1 + 8 files changed, 94 insertions(+), 14 deletions(-) create mode 100644 app/src/main/java/otus/homework/coroutines/CatImage.kt create mode 100644 app/src/main/java/otus/homework/coroutines/CatPresentationModel.kt diff --git a/app/src/main/java/otus/homework/coroutines/CatImage.kt b/app/src/main/java/otus/homework/coroutines/CatImage.kt new file mode 100644 index 00000000..d6b27a26 --- /dev/null +++ b/app/src/main/java/otus/homework/coroutines/CatImage.kt @@ -0,0 +1,17 @@ +package otus.homework.coroutines + +import com.google.gson.annotations.SerializedName + +data class CatImage( + @field:SerializedName("id") + val id: String, + + @field:SerializedName("url") + val url: String, + + @field:SerializedName("width") + val width: Int, + + @field:SerializedName("height") + val height: Int +) \ No newline at end of file diff --git a/app/src/main/java/otus/homework/coroutines/CatPresentationModel.kt b/app/src/main/java/otus/homework/coroutines/CatPresentationModel.kt new file mode 100644 index 00000000..f46594d9 --- /dev/null +++ b/app/src/main/java/otus/homework/coroutines/CatPresentationModel.kt @@ -0,0 +1,6 @@ +package otus.homework.coroutines + +data class CatPresentationModel( + val fact: String, + val imageUrl: String +) diff --git a/app/src/main/java/otus/homework/coroutines/CatsPresenter.kt b/app/src/main/java/otus/homework/coroutines/CatsPresenter.kt index 134997c2..22f8d9ba 100644 --- a/app/src/main/java/otus/homework/coroutines/CatsPresenter.kt +++ b/app/src/main/java/otus/homework/coroutines/CatsPresenter.kt @@ -4,11 +4,9 @@ import kotlinx.coroutines.CoroutineName import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job +import kotlinx.coroutines.async import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import retrofit2.Call -import retrofit2.Callback -import retrofit2.Response import java.net.SocketTimeoutException class CatsPresenter( @@ -26,10 +24,20 @@ class CatsPresenter( job?.cancel() job = presenterScope.launch { try { - val fact = withContext(Dispatchers.IO) { + val factDeferred = async(Dispatchers.IO) { catsService.getCatFact() } - _catsView?.populate(fact) + val imageDeferred = async(Dispatchers.IO) { + catsService.getCatImage().first() + } + val fact = factDeferred.await() + val image = imageDeferred.await() + + val model = CatPresentationModel( + fact = fact.fact, + imageUrl = image.url + ) + _catsView?.populate(model) } catch (e: SocketTimeoutException) { _catsView?.showToast("Не удалось получить ответ от сервера") } catch (e: Exception) { diff --git a/app/src/main/java/otus/homework/coroutines/CatsService.kt b/app/src/main/java/otus/homework/coroutines/CatsService.kt index ca9e3f73..63567f77 100644 --- a/app/src/main/java/otus/homework/coroutines/CatsService.kt +++ b/app/src/main/java/otus/homework/coroutines/CatsService.kt @@ -7,4 +7,8 @@ interface CatsService { @GET("fact") suspend fun getCatFact() : Fact + + @GET("v1/images/search") + suspend fun getCatImage(): List + } \ No newline at end of file diff --git a/app/src/main/java/otus/homework/coroutines/CatsView.kt b/app/src/main/java/otus/homework/coroutines/CatsView.kt index 11ccbbe2..d993c8ad 100644 --- a/app/src/main/java/otus/homework/coroutines/CatsView.kt +++ b/app/src/main/java/otus/homework/coroutines/CatsView.kt @@ -3,9 +3,11 @@ 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 android.widget.Toast import androidx.constraintlayout.widget.ConstraintLayout +import com.squareup.picasso.Picasso class CatsView @JvmOverloads constructor( context: Context, @@ -15,15 +17,27 @@ class CatsView @JvmOverloads constructor( var presenter :CatsPresenter? = null + private lateinit var factTextView: TextView + private lateinit var catImageView: ImageView + private lateinit var button: Button + override fun onFinishInflate() { super.onFinishInflate() - findViewById