diff --git a/app/build.gradle b/app/build.gradle
index a414e0e8..c848f005 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -8,7 +8,7 @@ android {
compileSdkVersion 34
defaultConfig {
applicationId "otus.homework.coroutines"
- minSdkVersion 23
+ minSdkVersion 24
targetSdkVersion 34
versionCode 1
versionName "1.0"
@@ -33,6 +33,8 @@ android {
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0'
+ implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0'
implementation 'androidx.core:core-ktx:1.12.0'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index fe34985b..8ffb859f 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,10 +7,15 @@
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
+ android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Coroutines">
-
+
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..9bd16e84
--- /dev/null
+++ b/app/src/main/java/otus/homework/coroutines/CatImage.kt
@@ -0,0 +1,10 @@
+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,
+)
diff --git a/app/src/main/java/otus/homework/coroutines/CatImageService.kt b/app/src/main/java/otus/homework/coroutines/CatImageService.kt
new file mode 100644
index 00000000..27a08f4d
--- /dev/null
+++ b/app/src/main/java/otus/homework/coroutines/CatImageService.kt
@@ -0,0 +1,11 @@
+package otus.homework.coroutines
+
+import retrofit2.http.GET
+
+private const val VERSION_API = "v1/"
+
+interface CatImageService {
+
+ @GET("${VERSION_API}images/search")
+ suspend fun getRandomImages(): List
+}
\ 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..90e4b2b5 100644
--- a/app/src/main/java/otus/homework/coroutines/CatsPresenter.kt
+++ b/app/src/main/java/otus/homework/coroutines/CatsPresenter.kt
@@ -1,35 +1,69 @@
package otus.homework.coroutines
-import retrofit2.Call
-import retrofit2.Callback
-import retrofit2.Response
+import kotlinx.coroutines.CoroutineName
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.async
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.net.SocketTimeoutException
+import kotlin.coroutines.cancellation.CancellationException
+
+interface ICatsPresenter {
+ fun onInitComplete()
+ fun attachView(catsView: ICatsView)
+ fun detachView()
+}
class CatsPresenter(
- private val catsService: CatsService
-) {
+ private val catsService: CatsService,
+ private val catImageService: CatImageService,
+): ICatsPresenter {
private var _catsView: ICatsView? = null
+ private val presenterScope = PresenterScope(CoroutineName("CatsCoroutine"))
+ private var workJob: Job? = null
- fun onInitComplete() {
- catsService.getCatFact().enqueue(object : Callback {
-
- override fun onResponse(call: Call, response: Response) {
- if (response.isSuccessful && response.body() != null) {
- _catsView?.populate(response.body()!!)
+ override fun onInitComplete() {
+ if (workJob?.isActive == true) {
+ _catsView?.handle(R.string.cats_wait_next_fact)
+ return
+ }
+ workJob = presenterScope.launch {
+ try {
+ withContext(Dispatchers.IO) {
+ val factDeferred = async {
+ catsService.getCatFact()
+ }
+ val imageDeferred = async {
+ catImageService.getRandomImages()
+ }
+ withContext(Dispatchers.Main) {
+ _catsView?.populate(
+ factDeferred.await(),
+ imageDeferred.await()
+ )
+ }
}
+ } catch (timeOutException: SocketTimeoutException) {
+ _catsView?.handle(R.string.app_request_timeout)
+ } catch (_: CancellationException) {
+ } catch (t: Throwable) {
+ CrashMonitor.trackError(t)
+ _catsView?.handle(t.message.toString())
}
-
- override fun onFailure(call: Call, t: Throwable) {
- CrashMonitor.trackWarning()
- }
- })
+ }
}
- fun attachView(catsView: ICatsView) {
+ override fun attachView(catsView: ICatsView) {
_catsView = catsView
}
- fun detachView() {
+ override fun detachView() {
_catsView = null
+ CrashMonitor.trackWarning("Stop detachView")
+ presenterScope.cancel()
}
}
\ 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..829b930c 100644
--- a/app/src/main/java/otus/homework/coroutines/CatsService.kt
+++ b/app/src/main/java/otus/homework/coroutines/CatsService.kt
@@ -1,10 +1,9 @@
package otus.homework.coroutines
-import retrofit2.Call
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..8a60c9ba 100644
--- a/app/src/main/java/otus/homework/coroutines/CatsView.kt
+++ b/app/src/main/java/otus/homework/coroutines/CatsView.kt
@@ -1,10 +1,18 @@
package otus.homework.coroutines
import android.content.Context
+import android.content.Intent
import android.util.AttributeSet
import android.widget.Button
+import android.widget.ImageView
import android.widget.TextView
+import android.widget.Toast
+import androidx.annotation.StringRes
import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.core.content.ContextCompat.startActivity
+import androidx.core.os.bundleOf
+import com.squareup.picasso.Picasso
+
class CatsView @JvmOverloads constructor(
context: Context,
@@ -12,21 +20,67 @@ class CatsView @JvmOverloads constructor(
defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr), ICatsView {
- var presenter :CatsPresenter? = null
+ var presenter: ICatsPresenter? = null
override fun onFinishInflate() {
super.onFinishInflate()
findViewById