I have a class that extends another, but in this class I do not want to call the super constructor.
How can I solve it?
Here is a snipet of my code
class SubarticlePagerAdapter(fragmentManager: FragmentManager, context: Context, var selectedArticleName: String) : ArticlePagerAdapter(fragmentManager, context) {
var subarticleDao: ArticleDao
var itemCount = 0
init {
ApplicationHelper().getApplication(context).appComponent.inject(this)
subarticleDao = ApplicationHelper().getApplication(context).subarticleDaoSession.articleDao
initBundles(context)
}
override fun initBundles(context: Context?) {
}
}
My problem, when this constructor is called, parent class constructor run first, and initBundles() will be called from there, but at that time subarticleDao and selectedArticleName are not set and I get exception.
TL;DR
I'd advise you to move the code from the init block to the initBundles function and use your variables there after initialization. Then there would be no need to avoid calling the superclasses constructor.
Extensive Answer
I think you should think about what you want to do with your design. Working around the idioms of a language is not very often a good idea or a sign of good design - at least when kotlin is your language :)
What you did with your code (overriding a - possibly abstract - method, initBundles from your superclass is pretty much the template method pattern. So it seems to me the purpose of initBundles is to let subclasses customize parts of the initialization... What basically is what you do in your init block.
EDIT: As Paul pointed out in the comments, you can't use the member selectedArticleName before your base classes initialization has finished. So if the base class calls initBundles during its initialization, then properties in the subclass won't be initialized as also stated at Paul's link.
Since in the snippet you don't use selectedArticleName, you could just move your initialization stuff to the initBundles function and init your subarticleDao there.
However, if you need to use your subclasses properties at that point, I'd really advise you to rethink your design. There should be several ways to solve this, but to decide what would suits your requirements best one would need further insight into the intentions you have with your design.
Related
I have a singleton class as follows
object SharedPrefTask {
fun doSomeWork() {
....
....
}}
I am using the method doSomeWork in 2 ways.
Approach 1
private var prefTask: SharedPrefTask = SharedPrefTask
prefTask.doSomeWork()
Approach 2
SharedPrefTask.doSomeWork()
Which is the correct approach here?
Both are technically correct and will have the same outcome. When you use your first approach prefTask: SharedPrefTask = SharedPrefTask all you're really doing is making a variable that references the object. So if you were to call prefTask.doSomeWork() it would be the exact same as calling SharedPrefTask.doSomeWork().
Knowing this, it seems like it would be best to just go with your second approach since it is more clear and uses less code.
I'm trying to create a fake class for my repository to test a view model.
As far as I understood, the key element here is to create two classes with a common interface so both classes would contain the same methods.
The problem is I get a Type mismatch when trying to initialize an object.
I tried to do the same in a simplified manner:
class fakeClass1 : fakeInterface {
override fun getAllData(): String {
return ""
}}}
class fakeClass2 : fakeInterface {
override fun getAllData(): String {
return ""
}}
interface fakeInterface {
fun getAllData(): String}
val fakeClass: fakeClass1 = fakeClass2()
But that didn't work either.
What am I missing?
Ok, I figured it out.
I was wrong to think that those two classes should be interchangeable.
I solved it by making the ViewModel take the common interface in its constructor instead of the actual repository class. This allows the ViewModel to take any class which implement this interface as it's repository.
I think you worked it out, but just so you're clear (this is an important, fundamental thing!)
val fakeClass: fakeClass1 = fakeClass2()
This is defining a variable called fakeClass that refers to an object with the fakeClass1 type. Then you assign an object with the fakeClass2 type.
But a fakeClass2 is not a fakeClass1, neither is a superclass of the other, so you can't treat one as the other. Your example is simple, but imagine you added coolFunction() to fakeClass1 - they'd now happen to have different structures, and trying to call that method on an object that doesn't have it would cause a crash.
The only thing those classes have in common, is that they both have the fakeInterface type - they are fakeInterfaces, and that guarantees they implement the stuff in that interface (your getAllData function in this case). So if you treat them both as that type instead:
val fakeClass: fakeInterface = fakeClass2()
you can use either one, because they're both fakeInterfaces (similar to how Ints and Doubles are different but they're both Numbers). Because fakeClass is now a fakeInterface, you can only access the functions and properties that a fakeInterface has - you can't call coolFunction() even if you happened to pass in a fakeClass1, because fakeInterface doesn't have that.
(You could cast the variable to fakeClass1, basically saying "oh by the way this object is actually this type as well", but at that point the type system can't guarantee you're correct unless you're explicitly checking fakeClass is fakeClass1, and it'll warn you if that's the case)
The Java tutorials are pretty good and they'll give you an overview about how the types each form a kind of "contract" you work with
I am great fan of Kotlin and how it allows us to write better code. One of the best features is interface implementation delegation which looks like this:
class A(val someObject:SomeInterface) : SomeInterface by someObject
someObject has to be singleton (object), has to be created using constructor after keyword by (but then you cannot reference to it, or maybe someone has idea how to do it?) or has to be provided in constructor.
In Android messy and bad world we are discouraged to use constructors in fragments and activites due to configuration changes. But how about this:
class MyFragment(val someObject:SomeInterface = SomeObjectImpl()):Fragment,SomeInterface by someObject
I tried to change configuration and event I allowed system to kill my appliction and still, everything is looking ok, my object is creating again and again with my fragment. Is this valid, or am I missing something?
Happy Kotlin everyone!
This is valid. The reason you're discouraged from overloading fragment constructors is that Android can recreate them, and it will use the default one: MyFragment()
But the way Kotlin implements default parameter values behind the scenes is by creating additional constructors. You can decompile your class and see it contains two constructors now, one receiving someObject, and another empty.
From the JVM perspective the empty constructor would look like this:
public A() {
this(new SomeObjectImpl());
}
Calling it will populate your fragment with new instances of implemented classes.
ScreenDef is a class, I add a function setDevice for the class, which one is correct between Code A and Code B? why?
I think that Code B is correct, right?
Code C
data class ScreenDef(
val brightness: Int
): DeviceDef
class ScreenHelper(val mContext: Context) {
fun setScreen(aScreenDef: ScreenDef){
}
}
Code A
fun ScreenDef.setDevice(mContext: Context) {
ScreenHelper(mContext).setScreen(this)
}
Code B
fun ScreenDef.setDevice(mContext: Context) {
ScreenHelper(mContext).setScreen(it)
}
You should use this. it is referred as shorthand if there is only one parameter in lambdas.
context?.let {
it.resources.getInt(R.int.anyint) // just for example
}
In above snippet, it is the shorthand for lamda parameter(in case of only one parameter).
context?.let { cxt -> // here we have manually defined a parameter
cxt.resources.getInt(R.int.anyint) // just for an example
}
In this snippet, instead of it we have created cxt that is exactly same as it.
Actually you are taking the concept of Extension function wrong.
You are creating a data class ScreenDef and want to create an extension function to it, why? If you really want to have a member function just create a normal class and have a function in it.
Extension function should be created when target class is not maintained by you. For example: Activity, Fragments are not maintained by you and if you want to add a custom function, you have to extend them and do it. So to prevent it extension function comes into picture and they are really handy that's why we love it.
You can rather argue, whats wrong with creating extension function for a class created by us. It may or might not be true. It actually depends.
Let's take an example, suppose we have developed a library to draw simple symbols on canvas and there are several function we have created. It turned out to be so good that people are using it, we decided to created advanced version, that can draw more complex symbols that requires using our already developed simple lib. So when we extend the classes of simple lib we might need some functionality to improve some thing etc. in that case if we have imported our simple lib as dependency then its good to create extension function otherwise we would have to create one more child of that class and create desired function. If we have import our lib as source code, we can just go to the source fine and create a function inside it.
I hope it helps.
In the last year I've become a mobile developer and a functional programming admirer.
In each of the mobile arenas there are components with lifecycle methods that make up the meat of the app. The following will use Android and Kotlin as examples, but the same applies to iOS and Swift.
In Android, there are Activity's with lifecycle methods like onCreate(). You might also define a function, onButtonClicked(), which will do exactly what the name describes.
For the purposes of the question, let's say there's a variable defined in onCreate() that is used in a button click handler onButtonClickedPrintMessageLength() (This is usually the case - onCreate() is essentially Activity's setup method).
The example class would look like this:
class ExampleActivity: Activity() {
var savedStateMessage: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
savedStateMessage = "Hello World!"
}
fun onButtonClickedPrintMessageLength() {
System.out.println(savedStateMessage?.length)
}
}
Notice the declaration of savedStateMessage as a String? (nullable string) and the use of ?. (null safe call). These are required because the compiler cant guarantee that onCreate() will be called before onButtonClickedPrintMessageLength(). As developers though, we know that onCreate will always be called first* **.
My question is how can I tell the compiler about the guaranteed order of these methods and eliminate the null checking behavior?
* I suppose it's possible to new up our ExampleActivity and call onButtonClickedPrintMessageLength() directly, thus sidestepping the Android framework and lifecycle methods, but the compiler/JVM would likely run into an error before anything interesting happened.
** The guarantee that onCreate is called first is provided by the Android framework, which is an external source of truth and might break/function differently in the future. Seeing that all Android apps are based on this source of truth though, I believe it's safe to trust.
Although this won't answer your actual question, in Kotlin you can use lateinit to tell the compiler that you'll initialize a var at a later point in time:
lateinit var savedStateMessage: String
You'll get a very specific UninitializedPropertyAccessException if you try to use this variable before initializing it. This feature is useful in use cases like JUnit, where you'd usually initialize variables in #Before-annotated method, and Android Activitys, where you don't have access to the constructor and initialize stuff in onCreate().
As mentioned in another answer, lateinit is available as an option to defer initialization to a later point in a guaranteed lifecycle. An alternative is to use a delegate:
var savedStateMessage: String by Delegates.notNull()
Which is equivalent, in that it will report an error if you access the variable before initializing it.
In Swift this is where you would use an implicitly-unwrapped Optional:
class Example: CustomStringConvertible {
var savedStateMessage: String! // implicitly-unwrapped Optional<String>
var description: String { return savedStateMessage }
init() {
savedStateMessage = "Hello World!"
}
}
print(Example()) // => "Hello World!\n"
By using the operator ! at the end of String in the second line of the example you are promising that the variable will be set before it can be used. This is accomplished in the init method of the example. It's still an Optional but code can treat it as a String since it will be automatically unwrapped before each use. You must take care that the variable is never set to nil when it might be accessed or a runtime exception may be generated.