Is it possible to use view binding in a static method? - android

My question is, if it is possible to use view binding in a static method:
class SomeFragment : FragmentBinding<SomeFragmentBinding>() {
companion object {
fun someRandomFunction() {
// Use view binding here
binding.textView.text = "Test"
}
}
}

binding is a non-static property of SomeFragment class, where as companion object are static. Static methods cannot access non-static properties, because each instance of the class would have their own instances of that non-static property.
So, you cannot access binding or any other non-static property inside companion object.

Related

Generics, companion object, and inheritance in kotlin

I'm working with ViewBindings on Android, with code generated by the compiler from the xml that must look like that
class ViewBinding {...}
class MyBinding : ViewBinding {
companion object {
fun inflate (...) {
...
}
}
}
To avoid copy/pasting code, I want to create a class, accepting a class child of ViewBinding as a generic type argument, and with a companion object having the method inflate.
class MyClass<T:ViewBinding having the method inflate in the companion object of the class> { ... }
What's the smartest way to do that ?
As it is, what you're trying to do is impossible. The type parameter restrictions apply on the type itself, not its companion object, which isn't actually related to the class (it gets compiled as a separate class with no relation with the original class). The Java equivalent, implementing a static method from an interface, also isn't possible.
What you could do however, is to use the companion itself as a type parameter, the companion implementing an interface with the inflate method:
interface ViewBindingCompanion {
fun inflate(): ViewBinding
}
class MyBinding : ViewBinding {
companion object : ViewBindingCompanion {
fun inflate(): ViewBinding {
...
}
}
}
class MyClass<T : ViewBindingCompanion>
And then:
MyClass<MyBinding.Companion>()
Leave a comment if I missed something.

Difference between object / private constructor / companion object in Kotlin?

Please don't blame me. Im just moving from Java to Kotlin. I'm trying to create a singleton as a regular java way with help of Singleton.getInstance().someMethod() and have found that in Kotlin there are several different things you can use:
Object (separate file) object Singleton
Companion object companion object Factory {}
Private constructor
class Singleton private constructor()
So can you please help me and explain where we can you what type?
Objects in Kotlin are like static classes in Java. They are usually used to construct the singleton pattern:
object Singleton
The equivalent in Java would be:
public static class Singleton{}
The companion object is used in cases (as your companion object name states) where you have to apply the Factory pattern or the static factory pattern.
Let's suppose we have this in Java:
public class Fragment(){
private Fragment(){}
public static Fragment newInstance(){
return new Fragment();
}
}
The equivalent of that in Kotlin would be:
class Fragment private constructor(){
companion object{
fun newInstance() = Fragment()
}
}
The companion object is also an object but through the word companion is just telling JVM that the one class in which this object is, has access to everything inside it.
Therefore if you try to call it from Java code, it would be something like this:
Fragment.Companion.newInstance()
The above example actually also fits for private constructor.
Basically, even in Java, when you don't need to access the constructor directly, just mark the constructor as private and use a static factory method.
Regarding your question, with the information provided above:
To achieve
Singleton.getInstance().someMethod()
with exactly this call, you have to do this:
class Singleton private constructor(){
companion object{
fun getInstance() = Singleton()
fun someMethod(){ /* Your implement here */}
}
}
However that's not too sophisticated in Kotlin style.
Just do:
object Singleton{
fun someMethod(){ /* Your method here */}
}
Then just call it:
Singleton.myMethod()
EDIT: Regarding your question of SharedPreferences I don't suggest to use an object for that. You need the constructor for the context and perhaps shared preferences mode. Therefore I would go with something like this (assuming that you are using dagger since you mentioned it in comment):
class SharedPreferencesHelper #Inject constructor(val context: Context, val mode: Int) // not sure about the mode type but check the docs {
private lateinit var sharedPreferences: SharedPreferences
private lateinit var sharedPreferencesEditor: SharedPreferences.Editor
init{
sharedPreferences = context.getSharedPreferences("filename", mode)
sharedPreferencesEditor = sharedPreferences.edit()
}
}
Then you just call it in any constructor you need it.
Or:
class SharedPreferencesHelper private constructor(){
private lateinit var sharedPreferences: SharedPreferences
private lateinit var sharedPreferencesEditor: SharedPreferences.Editor
companion object {
fun startSharedPrefs(context: Context, fileName: String, mode: Int) = SharedPreferencesHelper().apply{
sharedPreferences = context.getSharedPreferences(fileName, mode)
sharedPreferencesEditor = sharedPreferences.edit()
}
}
}
Then start it in a dagger module:
#Module
object SharedPrefsModule{
#Singleton
#Provides
fun provideSharedPreferences(application: Application) =
SharedPreferencesHelper.startSharedPrefs(application, "fileName", MODE_PRIVATE)
}
Then call the dependency wherever you need it
object Singleton
Thread safe singleton
Not an expression
Cannot be used on the right hand side of an assignment statement.
Object declaration's initialization is thread-safe and done at first access
Can have supertypes
Object declarations can't be local (i.e. be nested directly inside a function)
Can be nested into other object declarations or non-inner classes
companion object Factory {}
Members of the companion object can be called by using simply the class name (hosting companion) as the qualifier
The name of the companion object can be omitted
Members of companion objects look like static members in other languages, at runtime those are still instance members of real objects
A companion object is initialized when the corresponding class is loaded (resolved), matching the semantics of a Java static initializer
class Singleton private constructor()
I don't think you need that for singleton in kotlin as kotlin already provides good singleton option out of the box, however as stated by other SO user here private constructor is serving the same purpose in kotlin as in, for example, java - to prevent instantiation. As a second thought, if you think of creating utils like classes in kotlin, please better consider using extension functions.
PS.: it should be pretty obvious so I'll mention it - 99% of the above is brutally copy-pasted from https://kotlinlang.org/docs/reference/object-declarations.html - may be it has better chances to be more searchable here:)
If you need a singleton - a class that only has got one instance - you can declare the class in the usual way, but use the object keyword instead of class.
If you need a function or a property to be tied to a class rather than to instances of it (similar to #staticmethod in Python), you can declare it inside a companion object.
Private constructors are used to prevent creating instances of a class when there are no instance fields or methods, such as the Math class, or when a method is called to obtain an instance of a class.

Generic Static Constant

It's hard to explain but I basically want to be able to have an interface which my subclasses need to implement, which mandates a static constant. How would I achieve this in Kotlin?
I have the following class/interface:
interface BaseFragmentInterface {
val TAG: String
}
class BaseFragment: Fragment() {
/* this, of course, doesn't compile right now: */
companion object: BaseFragmentInterface {}
func<T: BaseFragment> push(fragment: T) {
/* Here I want to access TAG */
Log.d(T.TAG, "Push Fragment")
}
}
My subclasses need to be required to implement the interface. And my base companion object would need to be somehow abstract.
Any idea how to achieve this?
Let me precise few things.
My subclasses need to be required to implement the interface.
There's no way to achieve this, you can't force a subclass' companion object to implement your interface since the companion object of a class is not related to the companion object of its superclass.
And my base companion object would need to be somehow abstract.
Since the companion object is an object, it can't be abstract, because an object can't be abstract too.
Said that, you have two options to still achieve your desired behavior:
Use TAG as a non-static final property inside BaseFragment:
abstract class BaseFragment : Fragment() {
protected abstract val TAG: String
fun <T : BaseFragment> push(fragment: T) {
/* Here I want to access TAG */
Log.d(TAG, "Push Fragment")
}
}
class FragmentImpl : BaseFragment() {
override val TAG: String = "fragment-impl"
}
Use companion objects to hold the tag, make the type T of push() as reified and access the TAG property inside the companion object of T using the reflection.

Interface as property in Kotlin

In some Fragments and other classes (in Java) I have a public interface ISomeActions with functions that I then call from some other parts in that class, to denote actions. So, I have a ISomeListener listener that I set in the constructor, or right after I create an object of SomeClass. How can I achieve this in Kotlin?
Example:
public class SomeClass{
public ISomeListener listener;
public interface ISomeListener{
public void doSomething();
}
void actuallyDoSomething(){
listener.doSomething();
}
}
I think I can use a lateinit var listener : SomeListener, but I don't know if that would be adequate. The member is an Interface, and not an implementation of that Interface in case it's called after the Activity finishes.
1) Constructor
class MyClass(private val myInterface: MyInterface) { ... }
This way myInterface is immutable. You can be sure that this will never be null.
2) After object creation - null
class MyClass(var myInterface: MyInterface? = null) { ... }
Now myInterface is mutable and can be null at any time. You can safety access it via myInterface?.someMethod() (is myInterface is null call won't be invoked). To access and assign listener use myClassInstance.myInterface = myInterfaceInstance.
Because of default param you can create your class with or without constructor param:
val myClass1 = MyClass()
val myClass2 = MyClass(interfaceInstanceOrNull)
3) After object creation - lateinit
class MyClass(myInterface: MyInterface? = null) {
lateinit var _myInterface: MyInterface
init {
if (myInterface != null) { _myInterface = myInterface }
}
}
In my opinion the worst solution. lateinit is designed for injecting field after creation, for DI frameworks like dagger. If you try call method on myInterface if it is not init yet UninitializedPropertyAccessException will be thrown. You can check if property is initlialized like this:
if (::_myProperty.isInitialized) { _myProperty.doSth() }
In my opinion you should use the first or the second approach. As I understand you cannot always init object with instance of MyInterface, so the second one seems legit for your puroposes.

Static like methods in Android application with kotlin

I am trying to add a "static" method to my MyApplication class in kotlin
I have added (as a property) the variable :
private var context: Context? = null
in method:
override fun onCreate()
I added:
context = applicationContext
then I add a companion object like this
companion object {
#JvmStatic fun getMyApplicationContext(): Context?
{
return MyApplication().context
}
}
when I call this method from other parts of the application like
MyApplication.getMyApplicationContext() it always returns null. I have gleaned all this from several sources but I am not sure if it is anywhere near correct or not.
It sounds like you want a global application context object. Now casting aside my dislike for global variables, I think you are pretty close.
I think you just need to add the variable into the MyApplication classes companion object and use that directly. You only need the #JvmField annotation if you're going to access the field from Java.
class MyApplication {
companion object {
#JvmField
var context: Context? = null
// Not really needed since we can access the variable directly.
#JvmStatic fun getMyApplicationContext(): Context? {
return context
}
}
override fun onCreate() {
...
MyApplication.context = appContext
}
}

Categories

Resources