-
Notifications
You must be signed in to change notification settings - Fork 239
ДЗ Coroutines #3
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
base: development
Are you sure you want to change the base?
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,42 @@ | ||
package otus.homework.coroutines | ||
|
||
import retrofit2.Call | ||
import retrofit2.Callback | ||
import android.util.Log | ||
import kotlinx.coroutines.* | ||
import retrofit2.Response | ||
import java.net.SocketTimeoutException | ||
import kotlin.coroutines.CoroutineContext | ||
|
||
class CatsPresenter( | ||
private val catsService: CatsService | ||
private val catsServiceFact: CatsService, | ||
private val catsServiceImage: CatsService | ||
) { | ||
|
||
private var _catsView: ICatsView? = null | ||
private val presenterScope = | ||
PresenterScope(Dispatchers.Main, CoroutineName("CatsCoroutine")) | ||
|
||
fun onInitComplete() { | ||
catsService.getCatFact().enqueue(object : Callback<Fact> { | ||
|
||
override fun onResponse(call: Call<Fact>, response: Response<Fact>) { | ||
if (response.isSuccessful && response.body() != null) { | ||
_catsView?.populate(response.body()!!) | ||
presenterScope.launch { | ||
withContext(Dispatchers.IO) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Не совсем понял зачем тебе тогда launch с |
||
try { | ||
val factResponse = catsServiceFact.getCatFact() | ||
val imageResponse = catsServiceImage.getCatImage() | ||
val factImage = FactImage(factResponse, imageResponse) | ||
_catsView?.populate(factImage) | ||
} catch (e: Exception) { | ||
when (e) { | ||
is SocketTimeoutException -> { | ||
_catsView?.showToast("Не удалось получить ответ от сервером") | ||
} | ||
else -> { | ||
_catsView?.showToast(e.message.toString()) | ||
CrashMonitor.trackWarning() | ||
e.printStackTrace() | ||
} | ||
} | ||
} | ||
} | ||
|
||
override fun onFailure(call: Call<Fact>, t: Throwable) { | ||
CrashMonitor.trackWarning() | ||
} | ||
}) | ||
} | ||
} | ||
|
||
fun attachView(catsView: ICatsView) { | ||
|
@@ -31,5 +45,14 @@ class CatsPresenter( | |
|
||
fun detachView() { | ||
_catsView = null | ||
presenterScope.cancel() | ||
} | ||
} | ||
|
||
class PresenterScope( | ||
private val dispatchers: CoroutineDispatcher, | ||
private val coroutineName: CoroutineName | ||
) : CoroutineScope { | ||
override val coroutineContext: CoroutineContext | ||
get() = dispatchers + coroutineName | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,15 @@ | ||
package otus.homework.coroutines | ||
|
||
import kotlinx.coroutines.Deferred | ||
import retrofit2.Call | ||
import retrofit2.Response | ||
import retrofit2.http.GET | ||
|
||
interface CatsService { | ||
|
||
@GET("random?animal_type=cat") | ||
fun getCatFact() : Call<Fact> | ||
suspend fun getCatFact() : Fact | ||
|
||
@GET("meow") | ||
suspend fun getCatImage() : Image | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package otus.homework.coroutines | ||
|
||
import android.util.Log | ||
import androidx.lifecycle.LiveData | ||
import androidx.lifecycle.MutableLiveData | ||
import androidx.lifecycle.ViewModel | ||
import androidx.lifecycle.viewModelScope | ||
import kotlinx.coroutines.CoroutineExceptionHandler | ||
import kotlinx.coroutines.SupervisorJob | ||
import kotlinx.coroutines.async | ||
import kotlinx.coroutines.launch | ||
import java.net.SocketTimeoutException | ||
|
||
class CatsViewModel( | ||
private val catsService: CatsService | ||
) : ViewModel() { | ||
private var _catsResponse = MutableLiveData<Result<FactImage>>() | ||
val catsResponse: LiveData<Result<FactImage>> | ||
get() = _catsResponse | ||
|
||
fun getCatFactImage() { | ||
viewModelScope.launch(CoroutineExceptionHandler { coroutineContext, throwable -> | ||
CrashMonitor.trackWarning() | ||
}) { | ||
try { | ||
val factResponseDeferred = async {catsService.getCatFact()} | ||
val imageResponseDeferred = async {catsService.getCatImage()} | ||
|
||
val factResponse = factResponseDeferred.await() | ||
val imageResponse = imageResponseDeferred.await() | ||
|
||
/** | ||
* antonkazakov: ... Используй async чтобы распараллелить | ||
* Вопрос: изначально я сделал без async чтобы они выполнялись полседовательно | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ты можешь сам это проверить на простейшем примере. Такие вещи лучше проверять самому чтобы не забывать и понимать. Пустого параметра не будет. У тебя корутина будет сасаспендена пока не выполнится |
||
* чтобы два результата использовать при создании объекта | ||
* FactImage(factResponse, imageResponse) | ||
* теперь при использовании async как это будет работать? | ||
* допустим получаем результат factResponse, imageResponse - неодновременно | ||
* FactImage(factResponse, imageResponse) будет создан из того что пришло первым, | ||
* а второй параметр "уйдет" пустым | ||
* или | ||
* родительская корутину (которая запускает launch) | ||
* "дождется" всех и только потом создаст FactImage(factResponse, imageResponse) ? | ||
*/ | ||
val factImage = FactImage(factResponse, imageResponse) | ||
_catsResponse.value = Result.Success(factImage) | ||
|
||
} catch (e: Exception) { | ||
when (e) { | ||
is SocketTimeoutException -> { | ||
_catsResponse.value = | ||
Result.Error("Не удалось получить ответ от сервером", e) | ||
} | ||
else -> { | ||
_catsResponse.value = Result.Error(e.message.toString(), e) | ||
e.printStackTrace() | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
sealed class Result<out T> { | ||
data class Success<out R>(val value: R) : Result<R>() | ||
data class Error( | ||
val message: String, | ||
val throwable: Throwable? | ||
) : Result<Nothing>() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package otus.homework.coroutines | ||
|
||
import androidx.lifecycle.ViewModel | ||
import androidx.lifecycle.ViewModelProvider | ||
|
||
class CatsViewModelFactory(private val catsService: CatsService): ViewModelProvider.NewInstanceFactory() { | ||
override fun <T : ViewModel?> create(modelClass: Class<T>): T = CatsViewModel(catsService) as T | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package otus.homework.coroutines | ||
|
||
import com.google.gson.annotations.SerializedName | ||
|
||
data class FactImage( | ||
val fact: Fact, | ||
val image: Image | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package otus.homework.coroutines | ||
|
||
import com.google.gson.annotations.SerializedName | ||
|
||
data class FactImageResponse( | ||
val fact: Fact? = null, | ||
val image: Image? = null, | ||
var isSuccessful: Boolean? = true, | ||
var errorMessage: String? = null | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package otus.homework.coroutines | ||
|
||
import com.google.gson.annotations.SerializedName | ||
|
||
data class Image( | ||
@field:SerializedName("file") | ||
val file: String | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
А зачем тебе два инстанса одного и того же стейтлесс класса?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
для того чтобы вызывать https://aws.random.cat/ который на другом ретрофит клиенте
private val retrofitImage by lazy {
Retrofit.Builder()
.baseUrl("https://aws.random.cat/")
.addConverterFactory(GsonConverterFactory.create())
.build()
}