Call method from Kotlin class

2019-04-29 17:55发布

问题:

I have an util Kotlin class where I set toolbar title, hide or show toolbar depends on the fragment:

class MyToolbarUtils() {

    fun hideToolbar(activity: Activity) {
        (activity as MainActivity).supportActionBar!!.hide()
    }

    fun showToolbar(activity: Activity, tag: String) {
        setToolbarTitle(tag, activity)
        (activity as MainActivity).supportActionBar!!.show()
    }

    fun setToolbarTitle(tag: String, activity: Activity) {
        var title = ""
        when (tag) {
            "Main_fragment" -> title = activity.resources.getString(R.string.Main_screen)
            "Add_note" -> title = activity.resources.getString(R.string.Add_note)
        }
        activity.title = title
    }
}

how to call showToolbar(...) from Fragment? I just tried MyToolbarUtils.showToolbar(..) but it can not be possible

only one way I discover is:

val setToolbarTitle = MyToolbarUtils()
setToolbarTitle.showToolbar(activity, tag)

but there must be better way to do that..

回答1:

Convert your class into an object which is supposed to work similarly to java static methods.

You can get more info here: https://kotlinlang.org/docs/reference/object-declarations.html#object-declarations



回答2:

Sounds like MyToolbarUtils should be an object declaration instead of a class.

Another way would be to declare functions inside this class on the top level in a file (not inside any class) and just refer to them by their simple name.



回答3:

Others answered how to make your functions feel like static methods, but for this use case you have a more idiomatic option.

Extension functions in Kotlin replace static utility classes in Java:

Since all of your functions take an Activity as a parameter, why not use extension functions and make them extend the Activity or MainActivity class instead?

fun MainActivity.hideToolbar() {
    supportActionBar!!.hide()
}

fun MainActivity.showToolbar(tag: String) {
    setToolbarTitle(tag)
    supportActionBar!!.show()
}

fun Activity.setToolbarTitle(tag: String) {
    title = when (tag) {
        "Main_fragment" -> title = resources.getString(R.string.Main_screen)
        "Add_note" -> title = resources.getString(R.string.Add_note)
        else -> "" // or did you mean this to be an exception?
    }
}

Now they are all in context of your MainActivity or Activity classes (the this is now an instance of one of those), you don't have to go hunt for them in some other unrelated ActivityUtils class. Whenever you are inside the activity class you can simply:

showToolbar("Main_fragment")

or from somewhere else where you have a reference to an activity:

// you have a reference of MainActivity type
myMainActivity.showToolbar("Main_fragment")

// you have a reference you can cast to MainActivity type
(someActivity as MainActivity).showToolbar("Main_fragment")

// this function works with any Activity
someActivity.setToolbarTitle("Add_note")

Also note that I cleaned up the code a little and used when as an expression to set the title, and also the removal of var (it is rare when you need a var, so always think about how to work with val). And as an expression the when will need an else clause, so I made that the same as you default "" empty string.

Alternative as Class Methods:

Since all 3 methods all require an instance of MainActivity (based on their casting), why not just put them into MainActivity as member functions.

class MainActivity ... {
    ...

    fun hideToolbar() {
        supportActionBar!!.hide()
    }

    fun showToolbar(tag: String) {
        setToolbarTitle(tag)
        supportActionBar!!.show()
    }

    fun setToolbarTitle(tag: String) {
        title = when (tag) {
            "Main_fragment" -> title = resources.getString(R.string.Main_screen)
            "Add_note" -> title = resources.getString(R.string.Add_note)
            else -> "" // or did you mean this to be an exception?
        }
    }
}

And call them from any reference to MainActivity.

Alternative as Object Declaration:

Lastly as suggested by others and for completeness, here they are in a utility class acting similar to statics but instead methods on a singleton object declaration:

object MyToolbarUtils() {
    fun hideToolbar(activity: MainActivity) {
        activity.supportActionBar!!.hide()
    }

    fun showToolbar(activity: MainActivity, tag: String) {
        setToolbarTitle(activity, tag)
        activity.supportActionBar!!.show()
    }

    fun setToolbarTitle(activity: Activity, tag: String) {
        activity.title = when (tag) {
            "Main_fragment" -> title = resources.getString(R.string.Main_screen)
            "Add_note" -> title = resources.getString(R.string.Add_note)
            else -> "" // or did you mean this to be an exception?
        }
    }
}

But I think this is the worst and least Kotlin-like way to extend functionality of another class. Classes/Objects like SomethingUtils full of statics means that you probably should be writing extension functions instead.



回答4:

// Kotlin

@file:JvmName("DemoUtils")
package demo

class ClassInKotlin

fun methodInKotlin() {
}

// Java
new demo.ClassInKotlin();
demo.DemoUtils.methodInKotlin();

Try this. This should work.