Android studio Kotlin OnClickListerner function - android-studio

When I implemented the member in the class for the on click listener as shown below:
class QuizQuestionsActivity : AppCompatActivity(), View.OnClickListener {
I was given the option of implementing it as:
override fun onClick(p0: View?) {
I need it to be
override fun onClick(v: View?) {
can someone explain the difference and why I am not getting the option of v: View

Kotlin provide default parameter with alphabets and digits you can simply change it with your variable name like --
override fun onClick(v: View?) { }
override fun onClick(view: View?) { }
override fun onClick(myView: View?) { }
It's quit good and it's meaningful variable name that remember as long time. where P0 and P1 named variable is not like good to remember.
Hope You can understand what I mean to say.

Both of those functions are the same, it's just a different name for the View variable. Kotlin parameters are listed with the parameter name first, then the class name.
If you want p0 to be v instead, just change the parameter name to be v.

Related

In what situation are listener parameters mandatory?

I wrote two different listeners for my button:
myButton.setOnClickListener{myOnClick()}
myButton.setOnKeyListener{myOnKeyListener()}
The first one is OK for the compiler. But second one gives an error. It says Expected 3 parameters of types View!, Int, KeyEvent!
Considering that these are the listeners in the View class:
public interface OnClickListener {
void onClick(View v);
}
public interface OnKeyListener {
boolean onKey(View v, int keyCode, KeyEvent event);
}
Any idea about why is asking me for the parameters in one situation but not in the other?
It's because of OnClickListener.onClick takes only one parameter but OnKeyListener.onKey takes three. In Kotlin you don't need to specify single lambda's parameter and you can access it with the implicit name it. But when lambda expects more parameters you cannot access them with it anymore. That's why you have to explicitly give them names.

Android Studio IDE Code Completion Suggestions

I'm trying to expose some APIs for developers via an interface. However, due to modularity in functions, I've broken a list of functions into several interfaces. Instead of doing:
interface IAllFeatures {
fun A() {}
fun AA() {}
fun B() {}
fun BB() {}
fun C() {}
fun CC() {}
}
interface SampleInterface : IAllFeatures {
}
I have it separated as:
interface IA {
fun A() {}
fun AA() {}
}
interface IB {
fun B() {}
fun BB() {}
}
interface IC {
fun C() {}
fun CC() {}
}
interface SampleInterface : IA, IB, IC {
}
In the first implementation, IAllFeatures displays all the functions in bold text in the code completion popup. However, in the second implementation, SampleInterface displays all functions in non-bold text and is no longer given priority in the list of code completion suggestions. Is there a way to have the best of both worlds, separating interface categories while giving developers clear code completion suggestions?
The whole point of the bold text is to show which methods are overriden/declared newly. If they are not overriden but inherited, they will not be bold. Unfortunately, the fix is, essentially, to use the first solution. You could override each method to call the super if you want, but that's pretty hacky.

How to make a local extension method avaiable in a function with receiver?

I found an interesting thing, but I couldn't do it. Is there any way to make the local extension method available in a function with receiver.
val list = ArrayList<Any>();
fun <T> Array<T>.bind(context: MutableList<in T>, block: Array<T>.() -> Unit) {
fun Array<T>.save() {
context.addAll(this);
}
block();
}
arrayOf(1, 2, 3).bind(list) {
save(); //todo: how to bind extension in execution scope
};
I know there is an alternative way by introducing another type for the receiver, but I want to avoid it. for example:
interface Savable {
fun save();
}
fun <T> Array<T>.bind(context: MutableList<in T>, block: Savable.() -> Unit) {
val proxy = object : Savable {
override fun save() {
context += this#bind;
}
};
proxy.block();
}
There is no such feature yet, and I think in near future it won't be added either. You should just use your second version. Don't care about adding an wrapper class. The idea of avoiding introducing a wrapper class is actually, as long as you are using JVM backend, just nonsense, because by using local function you are actually adding a local class.
This is the equivalent Java code of your kotlin function, after fixing as you have suggested, with the assumption that your bind function lives in file bind.kt:
public final class BindKt {
public static <T> void bind(T[] receiver, List<? super T> context, Function1<T> block) {
class Local { // the name of local class is unimportant, as it's generated by compiler. It should looks like "package.name.BindKt$bind$X" where X is a number.
public void save(T[] receiver) {
context.addAll(receiver);
}
}
block.invoke(this); // this won't compile. Neither will yours.
}
}
As you can see save is NOT compiled to a static method, which means, if your block somehow ever called that save, an instance of Local must be fist created. So, no matter what you do, as long as you used a local function, there is basically no point in avoiding introduing a wrapper class. Your second solution is good, and just use it. It's both elegant and efficient enough.
If you really don't want add a class/object creation, move these extension functions to a package scope, and let clients import them.

Parameter specified as non-null is null when using Mokito anyObject() on Kotlin function

My code as below, refering to the solution in https://stackoverflow.com/a/30308199/3286489
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.MockitoAnnotations
import org.mockito.Mockito.*
class SimpleClassTest {
private fun <T> anyObject(): T {
Mockito.anyObject<T>()
return uninitialized()
}
private fun <T> uninitialized(): T = null as T
lateinit var simpleObject: SimpleClass
#Mock lateinit var injectedObject: InjectedClass
#Before
fun setUp() {
MockitoAnnotations.initMocks(this)
}
#Test
fun testSimpleFunction() {
simpleObject = SimpleClass(injectedObject)
verify(injectedObject).settingDependentObject(anyObject())
}
}
I still have the below error
java.lang.IllegalArgumentException: Parameter specified as non-null is null: method my.package.InjectedClass.settingDependentObject, parameter dependentObject
Did I miss anything?
UPDATED
Below is the code tested (simplest form and working)
class SimpleClass(val injectedClass: InjectedClass) {
fun simpleFunction() {
injectedClass.settingDependentObject(DependentClass(Response.Builder().build()))
}
}
open class DependentClass(response: Response) {
}
open class InjectedClass() {
lateinit var dependentObject: DependentClass
fun settingDependentObject(dependentObject: DependentClass) {
this.dependentObject = dependentObject
}
}
By default Kotlin classes and members are final. Mockito cannot mock final classes or methods.
Thus when you write:
verify(injectedObject).settingDependentObject(anyObject())
the real implementation is called which requires non null argument.
To fix that either open your class and method or, even better, change SimpleClass to accept an interface as its constructor argument and mock the interface instead.
There is a project specifically to help deal with Kotlin "closed by default" in unit testing with Mockito. For JUNIT, you can use the kotlin-testrunner which is an easy way to make any Kotlin test automatically open up classes for testing as they are loaded by the classloader. Usage is simple, just add one annotation of #RunWith(KotlinTestRunner::class), for example:
#RunWith(KotlinTestRunner::class)
class MyKotlinTestclass {
#Test
fun test() {
...
}
}
This is thoroughly covered in the article Never say final: mocking Kotlin classes in unit tests
This covers your use case in an automatic way by allowing all classes to be mocked that otherwise would not be allowed.
I ran into the same issue with Mockito when using RETURNS_DEEP_STUBS. It seems like nulls are still returned for nested objects, even when using the kotlin-allopen plugin.
Please check out and comment on this issue on Mockito if you're having the same problem.
You can use this function instead
inline fun <reified T : Any> any(): T = Mockito.any(T::class.java) ?: T::class.java.newInstance()

Type parameters - get concrete type from type T : IMyInterface

Suppose I have a List<IMyInterface>...
I have three classes which implement IMyInterface: MyClass1, MyClass2, and MyClass3
I have a readonly Dictionary:
private static readonly Dictionary<Type, Type> DeclarationTypes = new Dictionary<Type, Type>
{
{ typeof(MyClass1), typeof(FunnyClass1) },
{ typeof(MyClass2), typeof(FunnyClass2) },
{ typeof(MyClass3), typeof(FunnyClass3) },
};
I have another interface, IFunnyInteface<T> where T : IMyInterface
I have a method:
public static IFunnyInterface<T> ConvertToFunnyClass<T>(this T node) where T : IMyInterface
{
if (DeclarationTypes.ContainsKey(node.GetType())) {
IFunnyInterface<T> otherClassInstance = (FunnyInterface<T>) Activator.CreateInstance(DeclarationTypes[node.GetType()], node);
return otherClassInstance;
}
return null;
}
I'm trying to call the constructor of FunnyClasses and insert as parameter my MyClass object. I don't want to know which object it is: I just want to instantiate some FunnyClass with MyClass as a parameter.
What happens when I call ConvertToFunnyClass, T is of type IMyInterface, and when I try to cast it to FunnyInterface<T>, it says I can't convert FunnyClass1, for instance, to FunnyInterface<IMyInterface>
My current workaround (not a beautiful one), is this:
public static dynamic ConvertToFunnyClass<T>(this T node) where T : IMyInterface
{
if (DeclarationTypes.ContainsKey(node.GetType())) {
var otherClassInstance = (FunnyInterface<T>) Activator.CreateInstance(DeclarationTypes[node.GetType()], node);
return otherClassInstance;
}
return null;
}
And I don't like it because the return type is dynamic, so when I access it from somewhere else, I have no idea what type it is, and I lose intellisense, and stuff. I don't know about any performance implications either.
Any clues?
Thanks in Advance!
Resolution
As I'm using C# 4.0, I could stop casting errors using covariance (output positions only), and so I changed my IFunnyInterface to
IFunnyInteface<out T> where T : IMyInterface
Thank you all for the replies.
Essentially, your problem is that you are trying to convert FunnyInterface<T> to FunnyInterface<IMyInterface>. As has been mentioned several times (one example is here, more information here), this is not valid in most circumstances. Only in .NET 4, when the generic type is an interface or delegate, and the type parameter has been explicitly declared as variant with in or out, can you perform this conversion.
Is FunnyInterface actually an interface?
thecoop answer points you exactly to why you can't do it.
A cleaner solution to the problem (besides using dynamic) would be a base non-Generics Interface:
public interface IFunnyInterfaceBase
{
}
public interface IFunnyInteface<T> : IFunnyInterfaceBase
where T : IMyInterface
{
}
And you need to move methods signature you use in that code from IFunnyInteface to IFunnyInterfaceBase.
This way you would be able to write something like this:
MyClass2 c2 = new MyClass2();
IFunnyInterfaceBase funnyInstance = c2.ConvertToFunnyClass();
The Exception you said you got in your code is not due to the extension method signature itself (the method is fine)..it is originated by the type of your lvalue (the type of the variable you use to store its return value)!
Obviously this solution applies only if you can modify IFunnyInterface source code!

Resources