When I use both Kotlin and Java in my project
In Java BaseActivity.class:
public abstract <T extends BaseViewModel> Class<T> bindViewModel();
And when I extend BaseActivity In Kotlin :
override fun <T : BaseViewModel<*, out IBaseView<*>>?> bindViewModel(): Class<T> {
return ArchViewModel::class.java
}
the Kotlin remind me the return is type inference faild
Type inference failed. Expected type mismatch:
required:Class<T>
found:Class<ArchViewModel>
How to fix this issue?
P.S. the ArchViewModel.class extends BaseViewModel
Type inference isn't failing. Your method signature says it can return Class<T> for any T (which extends BaseViewModel) you ask for, so it can be called e.g. as
activity.bindViewModel<SomeRandomModel>()
and must return a Class<SomeRandomModel>. Since ArchViewModel::class.java isn't a Class<SomeRandomModel>, the implementation is incorrect.
It's actually impossible to implement correctly whether in Kotlin or in Java. If return ArchViewModel.class compiles in Java, that's because you use the raw type BaseViewModel, so the compiler gives up on typechecking and doesn't report the error.
So you need to fix the method so it can be implemented. How, depends on what you actually want from it.
Alternately, you can "fix" it by casting return ArchViewModel::class.java as Class<T>. The compiler will correctly warn you that this cast is unsafe.
Related
This question is specific for extension function of Kotlin used in Android development.
So Kotlin provides us capability to add certain extension behavior in to a class to extend the based class behavior.
Example: (take from my current Android project, for viewAssertion in testing with Espresso)
fun Int.viewInteraction(): ViewInteraction {
return onView(CoreMatchers.allOf(ViewMatchers.withId(this), ViewMatchers.isDisplayed()))
}
In my usecase, I can use it like:
R.id.password_text.viewInteraction().perform(typeText(PASSWORD_PLAIN_TEXT), pressDone())
All good, except this extension function gives the extended behavior to all Int objects, not just the View IDs in Android, which is not good at all.
The question is if there is any way to give context for this Int, like in Android we have #IdRes in Android support annotation for such given case above?
You can't differentiate between an Int from the resources and a normal Int. It is the same class and you are adding an extension to all the classes of the Int type.
An alternative could be to create your own wrapper of Int:
class IntResource(val resource: Int) {
fun viewInteraction(): ViewInteraction {
return onView(CoreMatchers.allOf(ViewMatchers.withId(resource), ViewMatchers.isDisplayed()))
}
}
And then us it like this:
IntResource(R.id.password_text).viewInteraction().perform(typeText(PASSWORD_PLAIN_TEXT), pressDone())
I use kotlinx.serialization on Kotlin native project, I a defined Super class for my models and all of the models extends from it.
I defined a function to called toJSON() for serialize variables and fields inside model that all of class models have it.
#Serializable
open class Model {
fun toJSON(): String = JSON.stringify(this);
}
And I created a subclass
class Me : Model() {
var name:String = "Jack";
}
but when I invoke JSON.stringify(this), IDE get a Warning to me:
This declaration is experimental and its usage must be marked with '#kotlinx.serialization.ImplicitReflectionSerializer' or '#UseExperimental(kotlinx.serialization.ImplicitReflectionSerializer::class)'
I paid attention and I used #ImplicitReflectionSerializer annotation while not worked.
Where is my problem?
This is discussed here. It's the particular overload you're using which is still experimental. So your options are either to use the other overload (which takes in a serializer) or to use one of the annotations mentioned in the error message. If you look at the answer to the question I linked (and the comments following it), you'll see it talks about using #UseExperimental and where it should be used.
I would like to restrict on which constant value extension function can be called. For example function like:
#IdRes
fun <T : View> Int.find() = findViewById<T>(this)
If this was called on real id, it's fine:
R.id.someView.find<TextView>() // ok
But this should make compilation error:
42.find<TextView>() // should be compile error
Is annotating extension receiver supported in Kotlin?
As described in the documentation, you can use the following syntax:
fun #receiver:IdRes <T : View> Int.find() = ...
However, note that the Kotlin compiler is not aware of the semantics of the Android annotations, so their incorrect use is never a compilation error; it's at best a failed lint check.
I'm learning to code in Android with Kotlin, and have issues when casting between classes.
So I had these classes defined:
abstract class ListFragment : Fragment()
class NewListFragment : ListFragment()
and when I tried to use it when implementing a function that returns a Fragment, it throws ClassCastException. There was IDE warning about the failing cast too
override fun getItem(position: Int): Fragment {
return when(position){
0 -> NewListFragment() as Fragment
I don't know where I got wrong
Are you using the same Fragment class?
android.app.Fragment (deprecated as of Android P)
android.support.v4.app.Fragment
You seem to be casting to android.support.v4.app.Fragment, judging from the exception message. Are your imports in that file incorrect?
The warning in IntelliJ about an impossible cast only appears when it is truly impossible to cast to that specific type (that is, when their type hierarchies are completely different), which is why I think that this is likely the problem.
Additionally, you don't need to cast to a supertype. Such a conversion is already inferred, so you can remove the cast.
Why is it not possible to define generic binding conversion within android data binding library?
#BindingConversion
public static <T> T convertMyClass(MyClass<T> obj) {
return obj.get();
}
With this method I am getting can not find the setter for attribute 'android:text' with parameter type com.example.MyClass<java.lang.String> error. Defining explicit types works alright.
I was trying to find the way ObservableField<T> is getting converted but didn't succeed. Does anyone know how is this happening? Is there anything I'm doing wrong?
In two words: type erasure.
Generics are a double edged sword that cuts out some of the run time capability of the type system in exchange for compile time checks. You're telling the compiler to rewrite code to make these type conversions "just work." The trade-off is that it has to turn generic class references like "T" into just "Object". So the signature of your method after compilation is
Object convertMyClass(MyClass)
The data binding system is looking for a return type "String". And so doesn't even consider your method.
The data binding system could probably be made smarter, to be able to recognize your BindingConversion, but I wouldn't hold my breath for that feature.
Here is some bash which illustrates type erasure.
$ echo 'public class A{ public <T> T deRef(java.util.concurrent.atomic.AtomicReference<T> atom) {return atom.get();} }' >A.java
$ javac A.java
$ groovy -e 'println A.class.getMethod("deRef", java.util.concurrent.atomic.AtomicReference.class)'
public java.lang.Object A.deRef(java.util.concurrent.atomic.AtomicReference)
That last line of output is the method signature for the generic method.
A work-around would be to subclass MyClass with specific parameterized subclasses like so:
public class MyStringClass extends MyClass<String> {
#Override
public String get() {
return super.get();
}
#BindingConversion
public static String convertMyClass(MyStringClass obj) {
return obj.get();
}
}
Regarding ObservableField, it doesn't need the BindingConversion mechanism because the data-binding library references it in the java code, and therefore compile-time generics checking does the job of matching types up.