Kotlin:使用在随播对象中创建的功能更新视图 [英] Kotlin : Update view using function created in companion object

查看:76
本文介绍了Kotlin:使用在随播对象中创建的功能更新视图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在活动中使用静态方法从服务类更新视图,因此当我在随播对象中创建方法时,现在将允许在随播对象中继承视图类

I want to update view from my service class using static method inside my activity so when i have create method in companion object it will now allow to inherit view class inside companion object

这是代码示例

class MainActivity : AppCompatActivity() {

companion object {
    private const val MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE: Int = 0x01

       fun updateUI(product: Product, activity: Context) {
          /*Error Line*/
          titleMain.text = product.title
       }
    }
}

服务等级

override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        MainActivity.updateUI(product,this)
}

我认为这不是正确的方法.还有其他解决方案吗?

I think this is not the correct way. Is there any other way to achieve the solution?

先谢谢.

推荐答案

我想在活动中使用静态方法从服务类更新视图,因此当我在随播对象中创建方法时,现在将允许在随播对象中继承视图类

I want to update view from my service class using static method inside my activity so when i have create method in companion object it will now allow to inherit view class inside companion object

那么您已经知道,伴随对象是静态的.静态方法,变量等无法访问非静态变量.

As you already are aware then, companion objects are static. Static methods, variables, etc, cannot access non-static variables.

这是一个例子:

class Something(var x: Int){
    // The companion object is static
    companion object{
        fun someFun(){
            x = 3;//Unresolved reference: x
        }
    }
}

在Kotlin中,找不到x. Java在解释它方面做得更好:

In Kotlin, x isn't found. Java does a slightly better job at explaining it:

private int x;//getter and setter
private static void someFun(){
    x = 3;//Non-static field cannot be referenced from static context
}

在Kotlin中也是如此,但是处理方式却有所不同.但是,这一点仍然适用:您不能从静态类,方法,字段或其他任何内容中访问非静态变量.

The same applies in Kotlin, but it handles it differently. The point, however, still applies: you cannot access non-static variables from a static class, method, field, or anything else.

要解决此问题,即使嵌套了静态对象,也不能从静态对象访问非静态字段titleMain.它必须是非静态的,您才能访问它.

To bring this back to your problem, you cannot access the non-static field titleMain from a static object, even if it's nested. It has to be non-static for you to access it.

在继续探讨可能的解决方案之前,我想解释一下为什么在活动方面根本不使用静态方法.

Before I go on to a possible solution, I want to explain why you shouldn't use static methods at all when it comes to activities.

为了访问活动中的非静态字段,您需要活动的静态实例.或对此事的看法.但是,其中的 全部 中都有上下文.上下文字段绝不能是静态的,如果尝试,IntelliJ/Android Studio会警告您.它可能导致内存泄漏,这将是最大的问题.它还使即时运行不可用,但是除非您实际使用它,否则这不是问题.请参阅此Stack Overflow帖子.

In order for you to access a non-static field in the activity, you need a static instance of the activity. Or a view for that matter. However, all of these have a Context in them. Context fields should never be static, and IntelliJ/Android Studio will warn you if you try. It can cause memory leaks, which would be the biggest problem here. It also makes instant run unusable, but that's not a problem unless you actually use it. See this Stack Overflow post.

现在,对于解决方案:使用回调.它比使用静态方法复杂,但不涉及内存泄漏

Now, for the solution: Use callbacks. It's more complicated than using static methods, but it doesn't involve memory leaks

您没有包含那么多代码,所以我大部分都是从头开始编写的.它仍然应该为您提供入门指南.

You didn't include that much code, so I've written most of it from scratch. It should still give you some pointers on getting started.

首先,您需要向服务添加一个接口,其中包含所有回调方法.它可以是一个,也可以是100.根据需要声明任意数量,可以包含或不包含返回值和参数.

First off, you'll need to add an interface to the service, containing all the callback methods. It could be one, or it could be 100. Declare as many as you need, with or without return values and arguments.

这是一个示例服务类.有评论解释一切.

Here is an example Service class. There are comments explaining what everything does.

class SomeService : Service(){
    private val binder = SomeServiceBinder()
    private var callback: SomeServiceCallback? = null

    // The rest of the service

    /**
     * In this method, you return the binder instance created earlier. It's necessary
     * for the connection to the Activity
     */
    override fun onBind(intent: Intent?): IBinder {
        // Do something here if necessary
        return binder;
    }

    /**
     * Method containing example use of callbacks
     */
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        // If a callback has been registered, call the callback
        // Could be done in a separate thread, after some action, before some action,
        // TL;DR: anywhere you'd like.
        callback?.updateUI(product)

        // The return value could of course be anything.
        return START_STICKY
    }

    /**
     * Register the callback, or null for removing it
     */
    fun registerCallback(callback: SomeServiceCallback?){
        this.callback = callback
    }

    /**
     * The binder. Contains a `getService` method, returning the active instance of the service.
     */
    inner class SomeServiceBinder : Binder() {
        fun getService() = this@SomeService
    }

    /**
     * Add methods to this as you need. They can have arguments, or not. They can have a return type, or not. It's up to you
     */
    interface SomeServiceCallback{
        fun updateUI(product: Product);
    }
}

最后,是活动.除了扩展一个Activity(在这里为AppCompatActivity)之外,它还实现了回调接口.

And finally, the activity. In addition to extending an Activity (here: AppCompatActivity), it also implements the callback interface.

此外,它实现了ServiceConnection. ServiceConnection也可以是内部类,也可以声明为字段.

In addition, it implements ServiceConnection. The ServiceConnection could also be an inner class, or declared as a field.

class SomeActivity : AppCompatActivity(), SomeService.SomeServiceCallback, ServiceConnection{
    /**
     * Stored externally to help with shutdown
     */
    lateinit var someServiceIntent: Intent

    override fun callbackForSomething(product: Product) {
        println("Service called activity!")
        runOnUiThread{
            titleMain.text = product.title;
        }
    }

    override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
        super.onCreate(savedInstanceState, persistentState)
        /**
         * The intent needs to be created here. if it's created outside, it might reference the context before it's
         * been initialized, which makes it throw an NPE
         */
        someServiceIntent = Intent(this, SomeService::class.java)
    }

    private fun connectToService(){

        startService(someServiceIntent)// This is the normal part. You need this to start the service
        // However, it doesn't register a ServiceConnection. In addition to that, you also need
        // to call bindService:
        bindService(someServiceIntent, this, Context.BIND_AUTO_CREATE)
    }

    private fun disconnect(){
        //Equivalently, on shutdown, there's an extra call
        // First stop the service
        stopService(someServiceIntent)
        // Then unbind it
        unbindService(this)
    }


    override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
        println("The service is connected")
        /**
         * This uses an unsafe cast since there is just one service and one service binder. If you have multiple,
         * use a when statement or something else to check the type
         */
        val binder = service as SomeService.SomeServiceBinder? ?: return
        binder.getService().registerCallback(this)
    }

    override fun onServiceDisconnected(name: ComponentName?) {
        TODO("Do something here if you want")
    }

}

这篇关于Kotlin:使用在随播对象中创建的功能更新视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆