Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 564 Vote(s) - 3.56 Average
  • 1
  • 2
  • 3
  • 4
  • 5
How to make sealed classes generic in kotlin?

#1
Is it possible to use the AsyncResult class below to prevent redefining InFlight, Error and InFlight in UserDataAppResult and CreateUserResult?


//TODO: use this to make the below classes generic?
sealed class AsyncResult{
object InFlight : AsyncResult()
data class Error(val errorMessage: String) : AsyncResult()
data class Loaded<out T>(val users: T) : AsyncResult()
}

sealed class UserDataAppResult : AppResult() {
object InFlight : UserDataAppResult()
data class Error(val errorMessage: String) : UserDataAppResult()
data class Loaded(val users: List<User>) : UserDataAppResult()
}

sealed class CreateUserResult : AppResult() {
object InFlight : CreateUserResult()
data class Error(val errorMessage: String) : CreateUserResult()
data class Loaded(val users: User) : CreateUserResult()
}

Is it possible for the above code to look like this?

sealed class AsyncResult{
class InFlight : AsyncResult()
data class Error(val errorMessage: String) : AsyncResult()
data class Loaded<out T>(val users: T) : AsyncResult()
}

sealed class UserDataAppResult : AsyncResult()
sealed class CreateUserResult : AppResult()

val activeUsers: Flowable<UserDataAppResult> = appDatabase.userDao().getActiveUsers(appSettings.currentLanguage.ordinal)
.map<UserDataAppResult> { UserDataAppResult.Loaded(it) }
.onErrorReturn { UserDataAppResult.Error(it.localizedMessage) }
.startWith(UserDataAppResult.InFlight)
.observeOn(AndroidSchedulers.mainThread())
.share()

fun createUser(): Flowable<CreateUserResult> {

val userId = UUID.randomUUID().toString()
val user = User()
user.id = userId
return appDatabase.userDao().insertAll(user)
.map <CreateUserResult> { CreateUserResult.Loaded(user) }
.onErrorReturn { CreateUserResult.Error(it.localizedMessage) }
.startWith(CreateUserResult.InFlight)
}

Currently UserDataAppResult.Error is not found which makes sense.
But is it possible to reuse the AppResult sealed class hierarchy and introduce new types.
Reply

#2
It's not possible in Kotlin. Every type you use must have an explicitly declared class somewhere. Classes are not created implicitly by the compiler even in the case when nested classes are declared in the superclass.

For your problem, I recommend you rewrite the code from combining two inheritance-based hierarchies to one of the two combining inheritance and composition, or just restructure the hierarchy in some way, for example (I suppose the exact instance of a result would be irrelevant to you in case when it's not `Loaded`):

sealed class AsyncResult {
object InFlight : AsyncResult()
data class Error(val errorMessage: String) : AsyncResult()
sealed class Loaded<out T>(val result: T) : AsyncResult() {
sealed class UserDataAppResult(users: List<User>) : Loaded<List<User>>(users)
sealed class CreateUserResult(user: User) : Loaded<User>(user)
}
}
Reply

#3
Via the Google Guidelines:

[To see links please register here]

```
sealed class Resource<T>(
val data: T? = null,
val message: String? = null
) {
class Success<T>(data: T) : Resource<T>(data)
class Loading<T>(data: T? = null, var refreshing: Boolean = false) : Resource<T>(data)
class Error<T>(data: T? = null, message: String) : Resource<T>(data, message)
}
```
Reply

#4
Inspired by solution from @kosh


-> ViewState:

sealed class ViewState<out T> {
object Loading : ViewState<Nothing>()
data class Error(val throwable: Throwable) : ViewState<Nothing>()
data class Success<T>(val item: T) : ViewState<T>()
}
-> inside ViewModel:


private val _homeVS = MutableLiveData<ViewState<HomeMode>>()
val homeVS: LiveData<ViewState<HomeMode>> get() = _homeVS

// start requesting API
_homeVS.value = ViewState.Loading
try {
val result = loadData()
_homeVS.value = ViewState.Success(result)
} catch (e: Exception) {
_homeVS.value = ViewState.Error(e)
}

Then you can use this generic in layout/View

-> View:

viewModel.homeVS.observe(viewLifecycleOwner, {state ->
when(state) {
is ViewState.Error -> showError(state.throwable)
is ViewState.Success -> onSuccess(state.item)
ViewState.Loading -> showLoading()
}
})

-> On layout we may need little mor tuning

sealed class ViewState<out T> {
object Loading : ViewState<Nothing>()
data class Error(val throwable: Throwable) : ViewState<Nothing>()
data class Success<T>(val item: T) : ViewState<T>()

fun toData(): T? = (this as? Success)?.item
}

toData provides data only onSuccess


<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text='@{vm.homeVS.toData() != null ? vm.homeVS.toData().param1 : ""}' />

<!--onLoading-->
<View
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility='@{vm.homeVS instanceof ViewState.Loading ? View.VISIBLE : View.GONE}' />

<!--onError-->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility='@{vm.homeVS instanceof ViewState.Error ? View.VISIBLE : View.GONE}' />

Surely with BindingAdapter, you can make it even better. Here just for illustrating solution.

Good luck,'.
Reply

#5
your `Object` can't have a generic type in Kotlin but this could be solved simply by following the example below:


sealed class ResponseState<out T> {
object Loading : ResponseState<Nothing>()
data class Error(val throwable: Throwable) : ResponseState<Nothing>()
data class Success<T>(val item: T) : ResponseState<T>()
}


writing:


val _state = MutableLiveData<ResponseState<MessageModle>>()


_state.postValue(ResponseState.Loading)

myNetworkCall { response, e
if (e != null) _state.postValue(ResponseState.Error(e))
else _state.postValue(ResponseState.Success(response))
}

reading:

state.observe(..., {state ->
when(state) {
Loading -> showLoading()
is Error -> showError(state.throwable)
is Success -> onSuccess(state.item)
}
}
Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through