I am learning Kotlin. As per I learnt, extension functions provides the ability to extend a class with new functionality without having to inherit from the class. I am creating extension function for okhttp3.RequestBody. But I am not able to get method in my activity.
Here is my extension function:
fun RequestBody.createPlainRequestBody(message: String): RequestBody = RequestBody.create(MediaType.parse("text/plain"), message)
while calling function as below I am getting unresolved function
RequestBody.createPlainRequestBody()
while I am creating extension function for toast I am getting perfect result as below:
fun Context.showToast(message: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
by calling:
this#MainActivity.showToast("Upload successfully")
Can any one guide for how to resolve this?
Extension functions can be applied to instances of a particular class, but you're trying to call it on a class, as if it were a static method. Moreover, your extension function expects an argument and you're not providing any.
What you need in your case is a simple function that creates a RequestBody as you're not acting on any particular instance of RequestBody.
Under the hood an extension function is simply a static method where the first argument is the receiver object and any other argument is shifted by one. Your showToast extension function is equivalent to the following Java snippet:
public static void showToast(Context receiver, String message) {
Toast.makeText(receiver, message, ...).show();
}
That's why you can call Kotlin extension functions from Java.
Unfortunately, you cannot do this in OkHttp version 3, however, you
will able to do this in OkHttp4 which is being rewritten completely in
Kotlin, so all the classes will be compatible with Koltin.
You have to extends to its companion object. (You need to make sure that class has a companion object associated with it)
fun RequestBody.Companion.createPlainRequestBody(message: String): RequestBody {
return RequestBody.create(MediaType.parse("text/plain"), message)
}
And after that, you will be able to call it directly from its class.
RequestBody.createPlainRequestBody("message")
Or
RequestBody.Companion.createPlainRequestBody("message")
A companion object is a normal object that associated with or belongs to the class it's similar to static object in Java. In Kotlin, it's called companion object.
Related
This is the project I'm trying to understand. I'm trying to understand what goes after what in this project. What confuses me, is that getFeatures() call in ViewModel. It seems that it calls an abstract function in the interface which is implemented in the file DefaultMapsRepository. I don't understand how it works. I thought that call should be of function from DefaultMapsRepository class where getFeatures() is implemented. So, as I understand, getFeatures() call in ViewModel calls the not implemented method from the interface and then that interface somehow finds the implementation of it and that override fun getFeatures() code runs its body. Correct me if I'm wrong. But If I create another implementation of getFeatures() how would that interface choose which implementation to use? I heard somewhere that interface of repository makes code easier to test but it's hard to understand how if I don't know how this all code works. I sometimes like to test how code works in the console to make code look simpler but I can't replicate the same situation because I'm not able to run the code if I add something to fun main() constructor. I think such structure of a project is used a lot and I want to understand it very well.
A different way of explaining it that might help. Suppose you have this interface and class.
interface Pet {
fun sayName()
}
class Dog(val name: String): Pet {
override fun sayName() {
println(name)
}
}
If some function asks for a Pet, you can pass it an instance of anything that implements the Pet interface.
fun sayPetName(pet: Pet) {
pet.sayName()
}
From the function's point of view, it doesn't have to know what class was passed to it. It just knows that whatever was passed to it is an instance of a Pet, and must therefore have a non-abstract sayName() function.
Even though the function sayName() is abstract inside the definition of the interface, it would be impossible to create an instance of a class where there is an abstract function. There's no such thing as an abstract function in an instance of a class. You can define abstract classes that have abstract functions, but you cannot create instances of them.
You could pass a Dog instance to this function since it qualifies as a Pet. When the function calls pet.sayName(), it is up to the instance of Dog to respond. The function itself doesn't have to know anything about what class type was passed to it.
In the same way, if you have an instance of a Pet that was passed to your constructor, your class can use the sayName() function on it. If you pass the class a Dog instance, even though the class is storing it in a property that is marked Pet and the class doesn't know it has a Dog, if it calls sayName() on it, the Dog instance will use its implementation of sayName().
class SomeClass(val pet: Pet) {
fun sayThePetName() {
pet.sayName()
}
}
If a Dog were passed to the constructor of the above class, it does not get "downgraded" into a Pet interface that has an abstract function. It's still a Dog instance even if that specific type is not exposed to the class in this scope. The code inside the class doesn't know or care that it's a Dog. It just knows it has a reference to some actual class instance that has the functions defined by the Pet interface.
An interface is just a contract. If CoolInterface has a property someValue: Int and a method doThing(): Boolean, then anything that implements that interface is guaranteed to have that property and that method.
The MapsViewModel class takes a MapsRepository parameter, and MapsRepository is just an interface with one function:
suspend fun getFeatures(): Resource<FeaturesResponse>
You can pass in anything that implements that interface, which DefaultMapsRepository does:
class DefaultMapsRepository #Inject constructor(
...
) : MapsRepository {
Since it implements that interface, it needs to implement that getFeatures function, which it does:
// override is the keyword that shows you're not just declaring a new function,
// it's implementing something abstract in a superclass/interface (or overriding
// an open function)
override suspend fun getFeatures(): Resource<FeaturesResponse> {
// bla bla
}
So you can pass in anything at all as your repository, so long as it implements MapsRepository, meaning you need some implementation of that getFeatures function. It doesn't "decide" a version to use, it calls it on whatever you pass in. So you can test it with whatever mock class or object you like
val mockRepo = object : MapsRepository {
override suspend fun getFeatures(): Resource<FeaturesResponse> {
return Resource.Error("oh snap")
}
}
val viewModel = MapsViewModel(mockRepo, whateverTheOtherThingIs)
// calls getFeatures() on the repo
viewModel.getFeatures()
If none of that makes any sense, you should read up on what interfaces and polymorphism are!
I have ever used Java to programming in android, but a few weeks ago I started to learn kotlin, when I use Java I tried to use object oriented approach and use the less possible static objects or instances, so when I see some materials in internet about some implementations of consume web services in kotlin I see something like this:
/*call of method from activity*/
val message = WebServiceTask.getWebservice(getString(R.string.url_service))
/*Class to do the call to webservice*/
class WebServiceTask {
companion object {
fun getWebService(url: String): WebServiceResponse {
val call =
RetrofitInstance.getRetrofit(url).create(ApiService::class.java).getList()
.execute()
val webServiceResponse = call.body() as WebServiceResponse
return user
}
}
}
/*Class to get Retrofit instance*/
class RetrofitInstance {
companion object{
fun getRetrofit(url: String): Retrofit {
return Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
}
}
Like you see i use companion object in two classes and according to i read companion object is equivalent to static instance in java, so my question is:
is this code following object oriented programming?, this aproach is recommended?, in case that answer is no and which is the best implementation for this code in object oriented
Yes, companion object is Kotlin's equivalent of static members in Java. Everything that applies to static, applies to companion object as well.
The use of companion object depends on how it interacts with the state of class's object.
If you are using some methods which are totally Pure functions Or Some final values which you need to provide access to outside the class itself, in that case using companion object makes total sense.
It is recommended for the above conditions because it does not interfere with the state of the class's object.
So, for the given code snippet it is a valid use of companion object.
Observe that methods inside companion object do not interact with something which is not passed to them as parameters. Everything that you see is created/initialized or used inside the methods only, Just the result it gets out.
Note:
However, if your companion object members(values or functions) interfere with the state of the object, it will cause leaks, which will lead you to troubles you have never faced before.
Yes, it is equivalent to static. No, it is not recommended, as it leads to problems with mocking for testing, for example.
I have a pretty short question about an extension function that would help clear some of my code. Basically I have some transformations on the hashCode of a class name and I want an extension function to do the transformations.
Example:
Getting the name hashCode: StateA::class.java.name.hashCode() where StateA is a simple class.
I want to the extension function like:
fun Class<*>.transformName(): String {
var hashString = this.javaClass.name.hashCode()
//Do my stuff on that hashString
return hashString
}
But this doesn't seem to work. When I apply the extension function with StateA.transformName(), the function gives me an error with Unresolved Reference.
I tried various things like applying the function to StateA::class or having the hashString equal to this::class.java.name.hashCode() but nothing works. Any tips?
You can't really achieve the StateA.transformName() syntax, as StateA just on its own refers to the companion object inside that class. So to get that syntax, you'd need to have a companion object inside every class that you want to use this extension on.
What you can do in a very general way is get the KClass that describes your class first. This gives you an object (the KClass instance) that you can then call an extension on:
fun KClass<*>.transformName() {
val clazz: Class<*> = this.java
clazz.name.hashCode()
}
StateA::class.transformName()
Another approach, which is less verbose on the call site could be a generic function like this, where the reified keyword allows you to access the concrete class that was used as the generic type parameter inside the function:
inline fun <reified T> transformName() {
val clazz: Class<*> = T::class.java
clazz.name.hashCode()
}
transformName<StateA>()
I'm setting up extension function for Timber. I want to have kind of function to send log to my server.
The problem for me is Dagger. I have instance of RestService class in dagger and I'm using it in my whole app.
But to use it I need inject somewhere this RestService. I can't do it in constructor because I haven't it.
I want to have something like this:
fun Timber.serverLogDebug(log: String) {
restService.log(log)
}
Is it probably at all? It will be convenience for me to use my mechanism like simple Timber.d().
Alternatively I can call
restService.log(log)
in every place. But I have to have this instance everywhere.
In the file where you define the extension function, also define a "singleton" object to hold your restService instance, create a setter for it, and reference it from the logger function.
private object ServiceHolder {
var restService: RestService
}
fun Timber.setRestService(restService: RestService) {
ServiceHolder.restService = restService
}
fun Timber.serverLogDebug(log: String) {
ServiceHolder.restService.log(log)
}
Now you can "statically inject" your service instance by calling Timber.setRestService where you plant your Timber DebugTree.
Note: If you want to log to the server every time you log (or every time you log an event of a specific level), you might be better off creating a custom Timber.Tree.
I have just started messing around with the Kotlin programming language, which is pretty much cooler than Java. I have some doubts related to static methods and fields:
Q1: Official document says
Kotlin can also generate static methods for functions defined in named
objects or companion objects if you annotate those functions as
#JvmStatic.
But if you see below I can access bar() method as a static method, which works without using #JvmStatic annotation. But on official doc its throwing error -> Kotlin static method.
Class C{
companion object{
#JvmStatic
fun foo() { }
fun bar();
}
}
fun main(args: Array<String>) {
C.foo();
C.bar(); //this line works fine
}
Q2: Do I really need #JvmStatic and #JvmField to make things static?
As you can see with companion object, things are working as expected.
You can access members of a companion object as C.bar() in Kotlin, but not in Java. Without #JvmStatic, you would need to use C.Companion.bar() in Java, just as said in the docs.
Note that, without #JvmStatic, the function is compiled to an instance (non-static) method that is called on C.Companion in Java (and Kotlin simply shortens it to a call on C, but it's the same under the hood), so yes, you need either #JvmStatic and #JvmField to make a declaration in a companion object compile into a static member.
Basically, #JvmStatic and #JvmField are tools for Java interoperation that help with creating Java-friendly APIs, and if you don't need to call the Kotlin members from Java (e.g. they are internal to your Kotlin project, or you are developing a library that is unlikely to be used with Java), you can leave them as they are.
Yep, you do need #JvmStatic. The problem with your code that you call it in Kotlin while in documentation code was called in Java.
To be more precise, this code won't compile:
public void main(String[] args) {
C.foo(); // Ok
C.bar(); // Not ok
}
Kotlin knows about function in companion object so you can call it on class directly, while Java doesn't know anything about it. So you annotate any function with #JvmStatic and it becomes visible from Java code as static method.
And just to clarfiy - purpose of #JvmStatic is interop with Java code. If you write your application in Kotlin only you don't need #JvmStatic at all.
The documentation ("page 2") refers to the case where you call the function from Java, not Kotlin.
When you only use Kotlin, there is no need for the annotation. Instead use the way you declared your bar() method. So you can call C.bar()