Hakob Astvacatryan
01/30/2020, 10:04 PMdave08
02/03/2020, 4:13 PMlateinit var
that's initialized when the viewmodel is injected in the Fragment... but that's a bit of a brittle way to do things?Olenyov Kirill
02/03/2020, 5:38 PMamar_1995
02/05/2020, 7:08 AMursus
02/06/2020, 7:00 PMOfir Bar
02/09/2020, 10:33 AMclass BasicDetailsViewModel (private val basicDetailsRepository: BasicDetailsRepository) : ViewModel() {
val mUserBasicDetailsPlaceHolderData = basicDetailsRepository.getBasicUserDetailsPlaceholderViaIdentityProvider()
private val mUserBasicDetailsRequestData: MutableLiveData<UserBasicDetailsRequest> = MutableLiveData()
/**
* Upon the user taps the continue button, we update [mUserBasicDetailsRequestData]
* with the data the user has input.
*/
fun onContinueClicked(firstName: String, lastName: String, phone: String, profileImageUrl: String) {
mUserBasicDetailsRequestData.value = UserBasicDetailsRequest(firstName, lastName, phone, profileImageUrl)
}
var updateUserRequest: LiveData<NetworkCall<User>> = mUserBasicDetailsRequestData.switchMap { data ->
liveData(<http://Dispatchers.IO|Dispatchers.IO>) {
emit(NetworkCall<User>(NetworkStatus.LOADING, null, ""))
val updatedUser = basicDetailsRepository.updateUserBasicDetails(data)
emit(updatedUser)
}
}
After the user input his basic data and taps the “continue” button in the UI, the following happens:
• The value “mUserBasicDetailsRequestData” in the ViewModel is changed with the data sent from the UI.
• The value “updateUserRequest” in the ViewModel is observing mUserBasicDetailsRequestData, and gets triggered using “switchMap” which I find somewhat confusing.
• “updateUserRequest”, upon triggered, updates our backend with the basic user data, and notify the UI that the backend has successfully received our user basic details.
In the UI, we then observe updateUserRequest:
mViewModel.updateUserRequest.observe(this, Observer<NetworkCall<UpdateExpertiseFieldsResponse>> { networkCall ->
when (networkCall.status) {
NetworkStatus.SUCCESS -> handleSuccess() //Hide loader & do something.
NetworkStatus.ERROR -> handleError(networkCall.message ?: getString(R.string.authentication_general_error)) //Hide loader & show error to the user.
NetworkStatus.LOADING -> showLoader() //Show loader.
}
})
I wonder, is there a special reason that we need this additional variable “updateUserRequest”?
Why do we need a “switchMap” here?
In my mind I would just do something like this, when the “continue” button is clicked.
fun onContinueClicked(firstName: String, lastName: String, phone: String, profileImageUrl: String) {
mUserBasicDetailsRequestData.value = UserBasicDetailsRequest(firstName, lastName, phone, profileImageUrl)
liveData(<http://Dispatchers.IO|Dispatchers.IO>) {
emit(NetworkCall<User>(NetworkStatus.LOADING, null, ""))
val updatedUser = basicDetailsRepository.updateUserBasicDetails(data)
emit(updatedUser)
}
}
This is of course just a simple example, and I asked it since we repeat this pattern a couple of times. Am I missing some important consideration I might not be aware of?amar_1995
02/11/2020, 1:04 PMjava.lang.IllegalStateException: Cannot invoke setValue on a background thread
override fun doWork(): Result {
println("Worker is Running >>>> ")
val database = DatabaseClient.getInstance(applicationContext)
val server = APIClient.retrofitServiceProvider<ArticleService>()
val articleRepo = ArticleRepo.getInstance(database, server, applicationContext)
GlobalScope.launch {
articleRepo.clearData()
val data = articleRepo.refreshData(1)
}
return Result.success()
}
Here, I am trying to clean database and then again making a server call which will fetch data from server and load it into local database.voben
02/11/2020, 9:28 PMoverride suspend fun doWork(): Result {
myFlow.onEach { }.launchIn(//What scope do we use here?)
}
Ofir Bar
02/12/2020, 8:43 AMandroid:screenOrientation="portrait"
Do I have any good reason to make a ViewModel for this Activity? I know that users can’t rotate the screen.
What I am asking, is that in this scenario, do the ViewModel have “higher survival rate” than the Activity?Ofir Bar
02/12/2020, 12:04 PMOfir Bar
02/12/2020, 6:13 PM/**
* A class wrapping every network response
*/
data class NetworkResponse<T>(@SerializedName("code") val code: Int,
@SerializedName("message") val message: String,
@SerializedName("data") val data: T)
However, I know, for sure, that whenever making a network request to our backend, some network responses will send back a NetworkResponse
with data
equals null
. So then T
cannot be inferred.
For example, when we Patch a User data, I receive code 200 OK, but data
object returned is null (no data returned back is expected).
Here is the network request using retrofit:
@PATCH("user")
suspend fun updateUserBasicDetails(@Body basicDetailsBasicDetailsRequest: UserBasicDetailsRequest) : NetworkResponse<WHAT_TO_DO_HERE?>
I am not sure what type to set for NetworkRequest in this case. I need to give some object to the NetworkResponse, but don’t want to just put something ugly and unrelated like “String?“.
What can be done?ursus
02/13/2020, 1:08 AMamar_1995
02/13/2020, 7:44 AMursus
02/13/2020, 11:19 AMSlackbot
02/14/2020, 10:23 PMursus
02/15/2020, 3:28 AMToast
or error, it will re-show the Toast after new view instance is created (after coming back from background, or on rotation), which might be confusing to the userOfir Bar
02/16/2020, 2:56 PMAhmed Ibrahim
02/16/2020, 3:31 PM// Variant 1
sealed class MyFeatureState {
object Loading : MyFeatureState()
data class Error(val throwable: Throwable) : MyFeatureState()
data class Items(val items: List<FeatureItem>): MyFeatureState()
}
vs
// Variant 2
data class MyFeatureState(val isLoading: Boolean = false, val error: Throwable? = null, val items = emptyList<FeatureItem>())
Which one would be the preferred way to go?BMG
02/19/2020, 9:51 AMclass SomeFragment(viewManager: SomeViewManager) : SomeViewInterface by viewManager {
}
Now I want to pass a View
to SomeViewManager
class. What is the best way to do it? Should I have a setter in SomeViewManger?
Ofir Bar
02/20/2020, 1:49 PMFirebaseAuth
and StorageReference
(Firebase Storage).
I can only get it from my MainActivity, like the below:
`MainActivity.kt`:
class UploadCertificationActivity : AppCompatActivity() {
private val mViewModel: UploadCertificationViewModel by viewModel()
private lateinit var mStorageReference : StorageReference
private lateinit var mFirebaseAuth : FirebaseAuth
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_profile_upload_certification)
mFirebaseAuth = FirebaseAuth.getInstance()
mStorageReference = FirebaseStorage.getInstance().getReference(mFirebaseAuth.currentUser!!.uid)
}
I’d love to hear how you pass that to your repository and manage that in your projects in general. Please assume I will use that same instance throughout the project.
Since right now, I am issues Firebase storage calls directly from my Activity.Joey
02/21/2020, 1:54 AMLarissa Maraes
02/27/2020, 10:55 AMIanmedeiros
02/28/2020, 3:50 PMIanmedeiros
03/03/2020, 10:17 PMursus
03/05/2020, 12:29 AMval newState = state.copy(
items = state.items.map {
if (it.id == id) {
it.copy(
text = newText
)
} else {
it
}
}
)
Ofir Bar
03/10/2020, 8:52 AMJoan Colmenero
03/10/2020, 6:00 PMOfir Bar
03/11/2020, 11:19 AMOfir Bar
03/11/2020, 11:21 AMOfir Bar
03/11/2020, 11:22 AMclass MyPublishedAdvertisementsViewModel(private val advertisementRepository : AdvertisementRepository) : ViewModel(){
var _myPublishedAdvertisements : MutableLiveData<NetworkCall<MyPublishedAdvertisementsResponse>> = MutableLiveData()
val myPublishedAdvertisements : LiveData< NetworkCall<MyPublishedAdvertisementsResponse> > = _myPublishedAdvertisements
// Called every time our UI is #onStarted
fun getFreshData(){
_myPublishedAdvertisements.value = liveData {
emit(NetworkCall<MyPublishedAdvertisementsResponse>(NetworkStatus.LOADING, null, ""))
val publishedAdvertisements = advertisementRepository.getMyPublishedAdvertisements()
emit(publishedAdvertisements)
}
}
}
Ofir Bar
03/11/2020, 11:22 AMclass MyPublishedAdvertisementsViewModel(private val advertisementRepository : AdvertisementRepository) : ViewModel(){
var _myPublishedAdvertisements : MutableLiveData<NetworkCall<MyPublishedAdvertisementsResponse>> = MutableLiveData()
val myPublishedAdvertisements : LiveData< NetworkCall<MyPublishedAdvertisementsResponse> > = _myPublishedAdvertisements
// Called every time our UI is #onStarted
fun getFreshData(){
_myPublishedAdvertisements.value = liveData {
emit(NetworkCall<MyPublishedAdvertisementsResponse>(NetworkStatus.LOADING, null, ""))
val publishedAdvertisements = advertisementRepository.getMyPublishedAdvertisements()
emit(publishedAdvertisements)
}
}
}
Kirill Prybylsky
03/11/2020, 11:24 AMOfir Bar
03/11/2020, 11:26 AMdata class NetworkCall<out T>(val status: NetworkStatus, val data: T?, val message: String?) {
companion object {
fun <T> success(data: T?): NetworkCall<T> {
return NetworkCall(NetworkStatus.SUCCESS, data, null)
}
fun <T> error(msg: String, data: T?): NetworkCall<T> {
return NetworkCall(NetworkStatus.ERROR, data, msg)
}
fun <T> loading(data: T?): NetworkCall<T> {
return NetworkCall(NetworkStatus.LOADING, data, null)
}
}
}
Kirill Prybylsky
03/11/2020, 11:27 AMOfir Bar
03/11/2020, 11:29 AMKirill Prybylsky
03/11/2020, 11:32 AMOfir Bar
03/11/2020, 11:35 AMKirill Prybylsky
03/11/2020, 11:40 AMOfir Bar
03/11/2020, 11:54 AM