Skip to content

Commit 1a28346

Browse files
Task Otus-Android#3 completed
1 parent 0aec6bb commit 1a28346

File tree

7 files changed

+137
-19
lines changed

7 files changed

+137
-19
lines changed

app/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,5 +44,6 @@ dependencies {
4444
implementation 'com.squareup.picasso:picasso:2.71828'
4545

4646
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1'
47+
implementation 'androidx.fragment:fragment-ktx:1.3.6'
4748

4849
}
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package otus.homework.coroutines
22

3-
data class CatViewModel(
3+
data class CatsModel(
44
val fact: String,
55
val pictureUrl: String,
66
)

app/src/main/java/otus/homework/coroutines/CatsPresenter.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import kotlinx.coroutines.*
55
import java.net.SocketTimeoutException
66
import kotlin.coroutines.CoroutineContext
77

8+
//Не используется
89
class CatsPresenter(
910
private val catsService: CatsService,
1011
private val catPictureService: CatPictureService,
@@ -40,7 +41,7 @@ class CatsPresenter(
4041
Log.e("CatsPresenter", "requests success!!!")
4142
val fact = responseFact.body() as Fact
4243
val picture = responsePicture.body() as Picture
43-
_catsView?.populate(CatViewModel(fact.text, picture.url))
44+
_catsView?.populate(CatsModel(fact.text, picture.url))
4445
} else {
4546
throw Exception(
4647
if (responseFact.body() == null || responsePicture.body() == null) {

app/src/main/java/otus/homework/coroutines/CatsView.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,17 @@ class CatsView @JvmOverloads constructor(
1515
defStyleAttr: Int = 0
1616
) : ConstraintLayout(context, attrs, defStyleAttr), ICatsView {
1717

18-
var presenter :CatsPresenter? = null
18+
var vm: CatsVm? = null
1919
private val picasso by lazy { Picasso.get() }
2020

2121
override fun onFinishInflate() {
2222
super.onFinishInflate()
2323
findViewById<Button>(R.id.button).setOnClickListener {
24-
presenter?.onInitComplete()
24+
vm?.onInitComplete()
2525
}
2626
}
2727

28-
override fun populate(model: CatViewModel) {
28+
override fun populate(model: CatsModel) {
2929
findViewById<TextView>(R.id.fact_textView).text = model.fact
3030
model.pictureUrl.let { url ->
3131
picasso
@@ -44,6 +44,6 @@ class CatsView @JvmOverloads constructor(
4444
}
4545

4646
interface ICatsView {
47-
fun populate(model: CatViewModel)
47+
fun populate(model: CatsModel)
4848
fun showToast(text: String)
4949
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package otus.homework.coroutines
2+
3+
import android.util.Log
4+
import androidx.lifecycle.*
5+
import kotlinx.coroutines.CoroutineExceptionHandler
6+
import kotlinx.coroutines.async
7+
import kotlinx.coroutines.launch
8+
import java.net.SocketTimeoutException
9+
10+
class CatsVm(
11+
private val catsService: CatsService,
12+
private val catPictureService: CatPictureService,
13+
) : ViewModel() {
14+
15+
init {
16+
onInitComplete()
17+
}
18+
19+
private val _showToast: MutableLiveData<String> = MutableLiveData("")
20+
val showToast: LiveData<String> = _showToast
21+
fun resetToast() {
22+
_showToast.postValue("")
23+
}
24+
25+
private val _catsData: MutableLiveData<CatsModel?> = MutableLiveData()
26+
val catsData: LiveData<CatsModel?> = _catsData
27+
28+
29+
fun onInitComplete() {
30+
viewModelScope.launch(CoroutineExceptionHandler { coroutineContext, throwable ->
31+
//Обрабатываем непредвиденную ошибку
32+
CrashMonitor.trackWarning(throwable)
33+
changeUI(Error(throwable.message ?: throwable.toString()))
34+
}
35+
) {
36+
lateinit var result: Result
37+
38+
try {
39+
//Запускаем запросы одновременно
40+
val deferredFact = async { catsService.getCatFact() }
41+
val deferredPicture = async { catPictureService.getCatPicture() }
42+
43+
//Ждём выполнение всех запросов
44+
val responseFact = deferredFact.await()
45+
val responsePicture = deferredPicture.await()
46+
47+
//Анализируем ответы
48+
if (
49+
responseFact.isSuccessful
50+
&& responseFact.body() != null
51+
52+
&& responsePicture.isSuccessful
53+
&& responsePicture.body() != null
54+
&& (responsePicture.body() as Picture).url.isNotEmpty()
55+
) {
56+
Log.e("CatsVm", "requests success!!!")
57+
val fact = responseFact.body() as Fact
58+
val picture = responsePicture.body() as Picture
59+
result = Success(CatsModel(fact.text, picture.url))
60+
} else {
61+
throw Exception(
62+
if (responseFact.body() == null || responsePicture.body() == null) {
63+
"Incorrect data from server"
64+
}
65+
else {
66+
if (!responseFact.isSuccessful && responsePicture.isSuccessful) {
67+
responseFact.message()
68+
}
69+
else if (responseFact.isSuccessful && !responsePicture.isSuccessful) {
70+
responsePicture.message()
71+
}
72+
else {
73+
responseFact.message() + " " + responsePicture.message()
74+
}
75+
})
76+
}
77+
}
78+
//Обрабатываем определённые ошибки
79+
catch (e: SocketTimeoutException) {
80+
Log.e("CatsVm", "Error: $e")
81+
result = Error("Не удалось получить ответ от сервера")
82+
}
83+
84+
changeUI(result)
85+
}
86+
}
87+
88+
private fun changeUI(result: Result) {
89+
when (result) {
90+
is Error -> {
91+
_showToast.postValue(result.message)
92+
}
93+
is Success<*> -> {
94+
when (result.data) {
95+
is CatsModel -> _catsData.postValue(result.data)
96+
}
97+
}
98+
}
99+
}
100+
101+
class CatsVmProviderFactory(private val diContainer: DiContainer): ViewModelProvider.Factory {
102+
override fun <T : ViewModel> create(modelClass: Class<T>): T =
103+
CatsVm(diContainer.service, diContainer.servicePicture) as T
104+
}
105+
}
Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,36 @@
11
package otus.homework.coroutines
22

3-
import androidx.appcompat.app.AppCompatActivity
43
import android.os.Bundle
4+
import androidx.activity.viewModels
5+
import androidx.appcompat.app.AppCompatActivity
56

67
class MainActivity : AppCompatActivity() {
78

8-
lateinit var catsPresenter: CatsPresenter
9-
109
private val diContainer = DiContainer()
1110

11+
private val catsVM: CatsVm by viewModels {
12+
CatsVm.CatsVmProviderFactory(diContainer)
13+
}
14+
1215
override fun onCreate(savedInstanceState: Bundle?) {
1316
super.onCreate(savedInstanceState)
1417

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

18-
catsPresenter = CatsPresenter(diContainer.service, diContainer.servicePicture)
19-
view.presenter = catsPresenter
20-
catsPresenter.attachView(view)
21-
catsPresenter.onInitComplete()
22-
}
21+
view.vm = catsVM
22+
23+
catsVM.showToast.observe(this) { text ->
24+
text.takeIf { it.isNotEmpty() }?.let {
25+
view.showToast(it)
26+
catsVM.resetToast()
27+
}
28+
}
2329

24-
override fun onStop() {
25-
if (isFinishing) {
26-
catsPresenter.detachView()
30+
catsVM.catsData.observe(this) { catsModel ->
31+
catsModel?.let {
32+
view.populate(it)
33+
}
2734
}
28-
catsPresenter.cancelRequests()
29-
super.onStop()
3035
}
3136
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package otus.homework.coroutines
2+
3+
sealed class Result
4+
data class Error(val message: String) : Result()
5+
data class Success<T>(val data: T): Result()
6+

0 commit comments

Comments
 (0)