Is there a any functional difference in Kotlin between those?
class Foo {
companion object {
fun newInstance() = Foo()
}
}
// Create new instance somewhere else
val foo = Foo.newInstance()
and
class Foo {
}
// Create new instance somewhere else
val foo = Foo()
I think that the first approach is just adding more boilerplate code and taking more memory because of companion object. Am I right?
Note: I am in Android environment and Foo is actually an Fragment in my case, if it matters.
There is no advantage to the first block of code in most cases.
However, in the case of Android Fragments, there is a pattern that you never use the constructor directly to create a Fragment. This is because the Android framework needs to be able to instantiate your Fragment on your behalf when it is recreating the Fragment, and it will only do this by using the empty (zero arguments) constructor. Therefore, when you need to pass arguments to a new Fragment, instead of creating a constructor for that, you create a factory function that creates the fragment with the empty constructor and then passes the arguments by adding them to the Fragment's bundle.
When you don't need any arguments passed to your new Fragment in this way, there's no actual need for the factory function instead of a constructor. However, some people do it that way anyway for consistency. Whether you want to follow this pattern is totally up to you.
At the documentation there is no need to companion objects
https://developer.android.com/guide/fragments/create#kotlin
Related
I am trying to launch a fragment with object as a parameter in my Espresso test case and I am unable to do so.
val homeFragment= launchFragmentInContainer(themeResId = R.style.AppTheme_NoActionBar)
But I want to send an object to the HomeFragment class.
For eg:
val homeType:HomeType
I want to pass the homeType object to the below line of code, need help with how to do it.
val homeFragment= launchFragmentInContainer(themeResId = R.style.AppTheme_NoActionBar)
I have looked into documentation and stackoverflow link(added below) and I am not able to get the desired solution.
https://developer.android.com/guide/fragments/test
Best practice for instantiating a new Android Fragment
Please help me with this issue.
if you look at the launchFragmentInContainer function documentation, you can see that have parameter fragmentArgs of type Bundle. You can use it to pass arguments to fragment. I don't know how exactly your class HomeType looks like but remember that within Bundle you can pass only custom classes that implements java.io.Serializable or Parcelable.
https://developer.android.com/reference/kotlin/androidx/fragment/app/testing/package-summary#launchFragmentInContainer(android.os.Bundle,kotlin.Int,androidx.lifecycle.Lifecycle.State,androidx.fragment.app.FragmentFactory)
I recently started with the ViewModel and AndroidViewModel, I see there are different approach to initialise a viewModel instance, for me all works fine, I just want to know which one to use when? and where should I initialise the viewModel object? following all are the different approach to get the viewModel instance and works for me:
val myViewModel1 = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get(MyViewModel::class.java)
val myViewModel2 = ViewModelProvider.AndroidViewModelFactory(this.application).create(MyViewModel::class.java)
val myViewModel3 = ViewModelProvider(this).get(MyViewModel::class.java)
val myViewModel4: MyViewModel by viewModels()
val myViewModel5 by viewModels<MyViewModel>()
The easiest and most simple for me are 3rd, 4th and 5th, however I don't know what is the difference in all the five approaches, also please let me know if there any other way or optimal way to initialise my viewModel object, I do the initialisation on the global variable while declaring it, is it okay to initialise at the declaration time or it should be done inside some lifecycle method?
In case anyone looking for in depth answer, please check this, here we have the following way to create or get the viewModel object:
val myViewModel1 = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get(MyViewModel::class.java)
myViewModel2 = ViewModelProvider.AndroidViewModelFactory(this.application).create(MyViewModel::class.java)
val myViewModel3 = ViewModelProvider(this).get(MyViewModel::class.java)
val myViewModel4: MyViewModel by viewModels()
val myViewModel5 by viewModels<MyViewModel>()
All do the same thing, the only two key differences is:
The viewModel initialisation with lazy loading and without lazy loading.
The viewModel with multiple parameter and no parameters.
Lets see this wrt the lazy loading and without lazy loading, the first three are without the delegate by that means there is no lazy loading of that object, so it's the developer
responsibility to create the viewModel object only when activity is created or the fragment is attached to the activity, that means the first three approach(1, 2, 3) can't be
used at global scope, if used at global scope the variable must be
a var with lateint or null initialisation, and the
initialisation(approach 1, 2, 3) must happen in the onCreate or
onViewCreated(in case of fragment).
Therefor the best way to create the viewModel object is using the delegate by(4, 5), both are same with a bit different syntax, I choose 4 because of it's simplicity and readability.
val myViewModel4: MyViewModel by viewModels()
The by delegate gives the flexibility to lazy load the instance and you can define the viewModel at global scope and get ride off the boilerplate code, if you try to initialise the viewModel at global scope without the delegate the app will crash since the viewModel will try to initialise before the activity is created(it will not lazy load the viewModel instance).
Now let's see how to lazy load with multiple parameters, the 6th approach not mention in the question.
If you have multiple parameters in your view model and not using any dependency injection, you can use a ViewModelFactory implementation and then lazy load it:
val myViewModelWithParm: MyViewModel by viewModels { MyViewModelFactory(application, "param1", "param2") }
ViewModelFactory implementation:
class MyViewModelFactory(val application: Application, val param1: String, val param2: String) :
ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return MyViewModel(application, param1, param2) as T
}
}
Till this point we are clear on the delegate initialisation(4, 5), and how it is different with(1, 2, 3) now let's see the difference on the top 3 approach(1, 2, 3).
Let's first check 1 and 2.
val myViewModel1 = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get(MyViewModel::class.java)
myViewModel2 = ViewModelProvider.AndroidViewModelFactory(this.application).create(MyViewModel::class.java)
The key difference in them is one uses ViewModelProvider.NewInstanceFactory and other uses ViewModelProvider.AndroidViewModelFactory, so I checked the source code of both the classes and found that ViewModelProvider.AndroidViewModelFactory is actually the implementation of ViewModelProvider.NewInstanceFactory which override the create function that means both are doing the same stuff, preferable both approach should be chosen if we want multiple parameters however for that we have to override ViewModelProvider.NewInstanceFactory to create our own factory like it's done here
Now comes the third one:
val myViewModel3 = ViewModelProvider(this).get(MyViewModel::class.java)
This is the simple form of 1 and 2 when we don't have multiple parameters in our ViewModel and don't want to lazy load the object.
Note: I highly recommend the approach 4 or 5(both are same with different syntax), since this is the most suitable and optimal to write, if you don't have multiple arguments, in case you have multiple arguments you can use the approach 6 mentioned in the answer by implementing ViewModelProvider.Factory.
3 is the standard way to fetch (and create if necessary) a ViewModel with no constructor parameters. Internally, that's doing 1 to pass a factory that calls the empty constructor (NewInstanceFactory()).
An AndroidViewModel is a subclass of ViewModel that automatically passes in an application reference, in case you need access to things like the application context. So even if your AndroidViewModel has no parameters, the factory that creates it needs to pass in an application, which is what 2 is doing.
This is all taken care of for you by default using 3 - you only need to define and use a factory if your VM needs to be configured with some extra parameters.
4 and 5 are the same thing, just with the type specified in a different place (you only need one declaration and the other will be inferred). They're delegates from the KTX libraries, and they do the same thing as 3, but they're much more readable IMO - especially if you're mixing scopes, like using by viewModels to get a Fragment's own VM, and also by activityViewModels to get the Activity's VM to share data with that and other Fragments.
They're also lazy delegates (as far as I'm aware!) meaning the VM only gets instantiated when it's first accessed, which is generally going to happen later in the lifecycle (instead of when the object is first constructed). I'm not sure if there is a problem initialising the VM on construction, but all of the official examples I've seen seem to fetch it in onCreate (or thereabouts)
material-components-android-codelabs is a git repo of demo code for material components. In the 102-starter branch of this repo, in LoginFragment.kt, there's this bit of code
(actvity as NavigationHost).navigateTo(ProductGridFragment(),false)
In the import statements, nothing in there seems to indicate where activity comes from and using android studio to find any declaration goes to a function with the signature public final FragmentActivity getActivity(). How is activity set and brought into the scope of the fragment?
Kotlin allows you to get and set properties directly without calling the method. E.g. instead of calling getActivity, you can just use activity. So (actvity as NavigationHost) actually translates to (getActivity() as NavigationHost)
Check the Kotlin reference here. Quote from the linked documentation:
To use a property, simply refer to it by its name
getActivity() is a method on Fragment instances, and Kotlin allows you to access Java-style setters and getters as though they're properties:
// getters
val newThing = stuff.getThing()
val newThing = stuff.thing
// setters
stuff.setThing(newThing)
stuff.thing = newThing
// boolean setters
dog.setGood(true)
dog.isGood = true
// boolean getters
val goodBoy = dog.isGood()
val goodBoy = dog.isGood
note that the property versions look the same whether you're getting or setting, you're just reading and writing to a single "property". Under the hood, it's making the call to the relevant function.
Fragment has a function: final public FragmentActivity getActivity()
-> since you're in the scope of a fragment, and the function is in the fragment scope, too, you don't need any import
To be able to use this activity reference, your fragment needs to be attached to an activity. => This should happen somewhere around onAttatch().
Last tip: when you're in a lifecycle where you're sure you have a backing activity, you can use requireActivity() to avoid unnecessary null-checks
In one of the kotlin interviews, someone asked me the difference between it & this keywords.
I have a search on google but unable to find a proper answer for the question.
Can someone guide me what's the actual difference between these two?
I know this is very basic question, I am a novice in the kotlin.
it is only relevant inside a lambda with a single parameter. It is the default name for a single parameter and is a shorthand that allows you to omit naming the single parameter. A function that is declared this way might look like this:
(String) -> Unit
In a lambda, this is the receiver argument. It only works if the function is defined as having a receiver, like this:
String.() -> Unit
If the function declaration does not have a receiver, this has the same meaning it does outside the scope of the lambda. For an extension function, that’s the receiver of the extension function. Otherwise, it’s the class containing the function.
You need to know about Scope Functions:
The Kotlin standard library contains several functions whose sole
purpose is to execute a block of code within the context of an object.
When you call such a function on an object with a lambda expression
provided, it forms a temporary scope.
Inside this scope there is a Context object either as this or it
In Scope functions run, apply and with the scope is (temporarily) changed to the scope of the object you are calling this function on:
val str = "Hello"
str.run {
//Here this refers to str
}
In Scope functions let, also the scope is not changed (remains the same as caller scope) but your lambda will receive the context as it inside the lambda:
val str = "Hello"
str.let {
//Here it refers to str
}
You can check the links for more information.
Difference between it & this keywords can be explained by taking example of lambda method receivers (a.k.a higher order functions).
Let's say you've written a function or using a function which provides you callback as lambda method receiver. Something like this: () -> Unit
So, there are two possibilities how you want your callback to be:
Providing parameter to callback
Parameter by callback means you want to give your callback a parameter that caller can use on the time of invocation, also considered as it.
Whatever written above simply means: (Int) -> Unit. this functional method parameter can give you integer at the time of invocation.
Check out the snippet below:
fun someMethodWithCallback(callback: (Int) -> Unit) {
callback(0)
}
// On the time of consumption, the `Int` parameter by default exposed to callback as it parameter.
obj.someMethodWithCallback { it -> // Here it is the method parameter of callback that we passed, you can also rename it to any other named value
// it can be directly used as Int value if needed or you can rename it at receiver above
}
Note: You can provide multiple parameters to callback and then you won't be able to receive it, rather callback would provide you number of variables passed instead.
Providing object to callback
Another way to provide callback is by providing object itself as callback parameter. Which means that callback syntax slightly changes and gives you object itself as callback parameter this.
Whatever written above simply means: Int.() -> Unit. this functional method object can give you integer at the time of invocation.
Check out the snippet below:
fun someMethodWithCallback(callback: Int.() -> Unit) {
callback(0)
}
// On the time of consumption, the `Int` parameter by default exposed to callback as it parameter.
obj.someMethodWithCallback { this // Here this is the method object of callback that we passed, you can not rename it to anything else
// it can be used as Int value by referencing as this
}
Hope it make sense!
If this helps some one :
With scope like : run, apply, with, to call the methods of the object, we can call them directly as it has scope of the object. In another words run-block has "this" scope.
private fun methodWithRun() {
val dummy = Dummy()
dummy.run {
this.dummyFun()
this.dummyVar = "10"
}
}
While scope like : let, also, to call the methods of the object, we can call them using the "it" as it has scope of the class win which this method is written.
private fun methodWithLet() {
val dummy = Dummy()
dummy.let {
it.dummyFun()
it.dummyVar = "10";
}
}
I would like to go extreme fundamental with no fancy words. it keyword When you have one parameter you can call using it
keyword and it works so good with HOF, for instance,
private fun itKeyword(itKeyword:(String) -> Unit) {
itKeyword("")
}
fun callItFun() {
itKeyword {//it:String // this is high light over here like this
}
But if you try to do something like this:
private fun itKeyword(itKeyword:(String, Int) -> Unit) {
itKeyword("", 1)
}
fun callItFun() {
itKeyword {yourName, age -> //yourName, age is define by user
}
}
see? there is no it keyword define over here by compiler but instead we have to pass two parameters when we defined HOF but if we keep this empty, compiler will give us error Hey pass something dude, i don't what variable you are talking about there are two variables passed over here.
That means, when you have only one parameter you can call it by using it keyword.
this keyword
there are two scope or variables/properties global and local scope, when you have defined some variable as a global scope and you wanna call it in multiple methods/functions and at some place you have to use same type of another variable with the same name at local scope, in that case we will be using this keyword and why is that so?
private lateinit var mContext: Context
fun thisKeyword(mContext: Context) {
this.mContext = mContext
}
but what if we don't use this keyword and keep it like this:
private lateinit var mContext: Context
fun thisKeyword(mContext: Context) {
mContext = mContext
}
Compiler would say, mah man what have you done, didn't ring a bell in my head JK, Compiler would say, Val cannot be reassigned, wait what? we didn't init it as a val but if we see at global scope we have init it as var but guess what? compile is right. In Kotlin when pass something into functions parameter they act as a Val by default which means without this compiler was using local scope variables not global scope but when we use this keyword we tell compiler, with keyword this property over here before = is global scope this.mContext and after = is local one so this is the reason we use this keyword to refrains from variable conflict. i hope this helps, thankYou().
If you take a look at kotlin scope functions doc:
https://kotlinlang.org/docs/scope-functions.html
Some of them have "this" in their scopes and others use "it".
The difference is the following:
this: When you use scope functions that use "this", f.i. apply {} it changes the context of function's scope to the context of an object on which this function was called, e.g.:
//Outer context in outer scope
val alice = Person("Alice").apply {
//Person object's context in function's inner scope
this.age = 20 //"this" refers to the object's context
city = "London" //you can skip writing "this" because you are in the context of object
}
it: When you use functions that use "it", f.i. also {} it DOES NOT change the context of function's scope, so it remains the same as the context where the function was called, e.g.:
//Outer context in outer scope
val alice = Person("Alice").also {
//Same outer context in function's inner scope
it.age = 20 //"it" refers to the object's reference holder e.g. alice
it.city = "London" //you can not skip writing "it" because you are in outer context
}
NOTE:
The context and the scope are 2 different things.
In both cases the scope is changed so that if you declare a local variable within that scope it will not be visible from outer scope, and in 1 case the context changes and in the other one it remains the same and hence the usage of "this" and "it".
Interesting how difficult this answer is to find.
I've been using Dagger - Android for a while now and have my entire dependency graph set up. I'm using scopes, qualifiers, all that good stuff. I'm not a Dagger newbie anymore, but suffice to say I've been using it in a pretty standard way in my Android setup and everything has been going great.
For the first time, I'm realizing that I'd like to request new instances of a certain class in my graph myself, manually, and I want it to be a new instance every time.
What's the best way to go about doing that? I'm wondering if there's a way to leverage a non-#Singleton/non-scoped provider and call some sort of create() method myself, or if it's best to create a factory myself and make that factory a singleton/scoped instance and use my factory to get the new instance(s) when I need them? [I should mention this class will definitely not have an empty constructor so will need injected instances of other classes defined in my injection graph.]
(Also, it would probably help the most if answers were in the context of Android; i.e. I'm in, say, a ViewModel and need a new instance of some class defined in one of my Modules.)
Dagger will provide you a new instance as long as you don't scope the dependency.
To get a new instance of a dependency manually, you can inject Provider of it instead and use its get() method, it'll give you a new instance every time you call it.
Module part doesn't really change:
#Module
class AppModule {
#Provides
fun provideSomeObject(): SomeObject = SomeObject()
}
And in your class
class SomeClass {
// We don't inject the object anymore
// #Inject lateinit var myObject : SomeObject
// We'll inject it's provider
#Inject lateinit var myObject : Provider<SomeObject>
fun someMethod(){
// Here, instance1 and instance2 are NOT same objects
val instance1 = myObject.get()
val instance2 = myObject.get()
}
}
You can read more here.