I'm getting this error "com.example.viewmodelfactory.MainModelFactory cannot be cast to androidx.lifecycle.ViewModel " - kotlin

Anyone tell me how to pass a default value in ViewModelFactory from MainActivity. I'm getting error com.example.viewmodelfactory.MainModelFactory cannot be cast to androidx.lifecycle.ViewModel
class MainModelFactory (val counter: Int): ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return MainModelFactory(counter) as T
}
This is my ViewModelClass
class MainViewModel(val intiallizeCount: Int) :ViewModel () {
var count : Int = intiallizeCount
fun Increment()
{
count++
}
}
I'm passing the default count value in MainActivity
mainViewModel=ViewModelProvider(this, MainModelFactory(10)).get(MainViewModel:: class.java)

ViewModelProvider.Factory returns as a ViewModel object i.e.
return MainViewModel(counter) as T

Related

realTime List using callbackFlow from firestore

i'm facing hard times updating list of Orders in real time from firestore using stateflow !!
class RepositoryImp : Repository {
private fun Query.snapshotFlow(): Flow<QuerySnapshot> = callbackFlow {
val snapshott = addSnapshotListener { value, error ->
if (error != null) {
close()
return#addSnapshotListener
}
if (value != null)
trySend(value)
}
awaitClose {
snapshott.remove()
}
}
override fun getAllOrders() = flow<State<List<OrderModel>>> {
emit(State.loading())
val snapshot = ORDER_COLLECTION_REF.snapshotFlow()
.mapNotNull { it.toObjects(OrderModel::class.java) }
emit(State.success(snapshot)) // **HERE** !!!!!!
}.catch {
emit(State.failed(it.message.toString()))
}.flowOn(Dispatchers.IO)
}
i'm receiving the error from // emit(State.success(snapshot)) that says :
Type mismatch: inferred type is Flow<(Mutable)List<OrderModel!>> but List< OrderModel> was expected
sealed class State <T> {
class Loading <T> : State<T>()
data class Success <T> (val data: T) : State <T>()
data class Failed <T> (val message: String) : State <T>()
companion object {
fun <T> loading() = Loading <T>()
fun <T> success(data: T) = Success(data)
fun <T> failed(message: String) = Failed<T>(message)
}
}
My fun to LoadOrders :
private suspend fun loadOrders() {
viewModel.getAllOrders().collect { state ->
when (state) {
is State.Loading -> {
showToast("Loading")
}
is State.Success -> {
adapter.submitList(state.data)
}
is State.Failed -> showToast("Failed! ${state.message}")
}
}
}
Your snapshot variable is a Flow of lists, not a single List. If you want to just fetch the current list, you shouldn't use a flow for that. Instead use get().await().
override fun getAllOrders() = flow<State<List<OrderModel>>> {
emit(State.loading())
val snapshot = ORDER_COLLECTION_REF.get().await()
.let { it.toObjects(OrderModel::class.java) }
emit(State.success(snapshot))
}.catch {
emit(State.failed(it.message.toString()))
}.flowOn(Dispatchers.IO)
The flowOn call is actually unnecessary because we aren't doing anything blocking. await() is a suspend function.
Based on comments discussion below, supposing we want to show a loading state only before the first item, then show a series of success states, and we want to show an error and stop emitting once there's an error, we could do:
override fun getAllOrders() = flow<State<List<OrderModel>>> {
emit(State.loading())
val snapshots = ORDER_COLLECTION_REF.snapshotFlow()
.mapNotNull { State.success(it.toObjects(OrderModel::class.java)) }
emitAll(snapshots)
}.catch {
emit(State.failed(it.message.toString()))
}

ViewPager2 and FragmentStatePagerAdapter

I want to set the adapter of ViewPager2 to FragmentStatePagerAdapter but I get this error:
Type mismatch. Required: (RecyclerView.Adapter<RecyclerView.ViewHolder!>?..RecyclerView.Adapter<*>?) Found: ViewPager2Adapter
My ViewPagerAdapter class is
class ViewPager2Adapter(fm:FragmentManager) :FragmentStatePagerAdapter(fm) {
override fun getItem(position: Int): Fragment {
return when(position) {
0 -> {
MyScansListFragment()
}
1 -> {
PurchasedItemsFragment()
}
else -> {
Fragment()
}
}
}
override fun getCount(): Int {
return 2
}
override fun getItemPosition(`object`: Any): Int {
return POSITION_NONE
}}
And in the oncreateView() :
val viewPager2Adapter = ViewPager2Adapter(activity?.supportFragmentManager!!)
binding!!.viewPager.adapter = viewPager2Adapter
okay, let's change the code a little bit.
First of all, FragmentStatePagerAdapter has been deprecated.
FragmentStatePagerAdapter & FragmentPagerAdapter have been recently deprecated, and your code must look something like this. FragmentStatePagerAdapter and if you get your cursor over it and see details, there will be a statement "Deprecated Switch to androidx.viewpager2.widget.ViewPager2 and use androidx.viewpager2.adapter.FragmentStateAdapter instead."
try the following code.
class ViewPager2Adapter(private val listFragment: ArrayList<Fragment>,
fm: FragmentManager,
lifecycle: Lifecycle) : FragmentStateAdapter(fm, lifecycle) {
override fun getItemCount(): Int {
return listFragment.size
}
override fun createFragment(position: Int): Fragment {
return listFragment[position]
}
}
so, this is now kind of your universal viewpager adapter.
The next thing is we require fragments to be passed in here.
//I don't think you need Fragment() but since it's there in your list.
val fragmentList = listOf(MyScansListFragment(), PurchasedItemsFragment(),Fragment())
val viewPager2Adapter = ViewPager2Adapter(fragmentList, activity?.supportFragmentManager!!, lifecycle)
binding!!.viewPager.adapter = viewPager2Adapter

How to create an instance of a class by passing the type

I want to be able to say make an instance of this class and give a type then the code can instantiate a new instance of that class.
fun maker(type: Class<Animal>): Animal {
if(type == Class<Dog>) {
return Dog()
}
else if (type == Class<Cat>) {}
...
}
What is a good way to do this?
If they all have zero-argument constructors, you can do:
fun maker(type: Class<Animal>): Animal {
return type.newInstance()
}
You can make it return the type that was passed in for a little more versatility:
fun <T: Animal> maker(type: Class<T>): T {
return type.newInstance()
}
Correct version following your example (not sure if best approach overall):
fun <T: Animal> maker(type: Class<T>): T? {
return when (type) {
Cat::class.java -> Cat() as T
Dog::class.java -> Dog() as T
else -> null
}
}
And then to create objects:
val a = maker(Cat::class.java)
val b = maker(Dog::class.java)
(Updated) I am not an expert in Kotlin but you can do something like this :
import kotlin.reflect.KClass
import kotlin.reflect.full.createInstance
class A {
fun greet() {
println("Hello A");
}
}
class B{
fun greet() {
println("Hello B");
}
}
fun <T : Any> maker(clazz: KClass<T>): T {
return clazz.createInstance();
}
val aObj = maker<A>(A::class);
aObj.greet();
val bObj = maker<B>(B::class);
bObj.greet();
Output:
Hello A
Hello B
I hope now it makes sense you just need to pass the class to the method and it returns an object.
As you will be using Animal as a parent class so you can replace Any => Animal
fun <T : Animal> maker(clazz: KClass<T>): T {
return clazz.createInstance();
}
If the function can be inline you can also use reified type
inline fun<reified T: Animal> make() = T::class.createInstance()
...
val dog = make<Dog>()
Please notice that to use createInstance() the class must have no-arg constructor or IllegalArgumentException will be thrown

Parcelable in Kotlin

When I auto Parcelable my class parcel.readString() and parcel.readString() are underlined red even though my variables are in String format . Here is my code
import android.os.Parcel
import android.os.Parcelable
class adel constructor(var lel : String, var skl: String) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString(),
parcel.readString()
) {}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(lel)
parcel.writeString(skl)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<adel> {
override fun createFromParcel(parcel: Parcel): adel {
return adel(parcel)
}
override fun newArray(size: Int): Array<adel?> {
return arrayOfNulls(size)
}
}
}
Since you are in Kotlin, you can skip the implementation and instead install a nice feature. Just add this in build.gradle:
androidExtensions {
experimental = true
}
Then in you class:
import kotlinx.android.parcel.Parcelize
#Parcelize
data class Adel(var lel : String, var skl: String) : Parcelable
And you are done. Note that you will have a lint error. Just ignore it.
parcel.readString()
is nullable, replace with
parcel.readString().orEmpty()

Square brackets after function call

In the PagingWithNetworkSample, in the RedditActivity.kt on the line 68 is a function that contains another function call followed by square brackets and the class type (line 78):
private fun getViewModel(): SubRedditViewModel {
return ViewModelProviders.of(this, object : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
val repoTypeParam = intent.getIntExtra(KEY_REPOSITORY_TYPE, 0)
val repoType = RedditPostRepository.Type.values()[repoTypeParam]
val repo = ServiceLocator.instance(this#RedditActivity)
.getRepository(repoType)
#Suppress("UNCHECKED_CAST")
return SubRedditViewModel(repo) as T
}
})[SubRedditViewModel::class.java]
}
What does this exactly do? Automatically cast to that type? (it's not an array/list to suppose it calls get)
Can you bring an example where this is useful?
That code might look strange, but it's really just a way of calling get(). This would be just as valid, but slightly more verbose:
private fun getViewModel(): SubRedditViewModel {
return ViewModelProviders.of(this, object : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
// ...
}
}).get(SubRedditViewModel::class.java)
}