关于android:Kotlin-通过Intent将函数作为参数传递

Kotlin - passing function as parameter via Intent

我在kotlin扩展文件中具有此功能以传递方法,但是它不起作用。请解释一下它的正确制作方法,请尝试以下操作:

1
2
3
4
5
6
7
8
9
fun showErrorClientScreen(context: Context, action : () -> Unit) {
    val intent = Intent(context, RestClientErrorActivity::class.java)

    val bundle = Bundle()
    bundle.putSerializable(UPDATE_CLIENT_ERROR, ErrorClientListener {  action })
    intent.putExtra(UPDATE_CLIENT_ERROR_BUNDLE, bundle)

    context.startActivity(intent)
}

使用Java接口

1
2
3
4
5
public interface ErrorClientListener extends Serializable {

    void tryAgainFunction();

}

和我需要监听的活动单击按钮,然后重试发送请求:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class RestClientErrorActivity: BaseActivity(), View.OnClickListener {

    private lateinit var errorClientListener: ErrorClientListener

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_rest_client_error)

        try {
            val bundle = intent.getBundleExtra(UPDATE_CLIENT_ERROR_BUNDLE)
            errorClientListener = bundle?.getSerializable(UPDATE_CLIENT_ERROR) as ErrorClientListener
        } catch (e: Exception) {
            e.message
        }
    }

    override fun onClick(v: View?) {
        when (v?.id) {
            R.id.ib_update -> errorClientListener.tryAgainFunction()
        }
    }

}


在活动之间打包interfaces是很奇怪的,绝对是不可取的。它可能未在Activity AActivity B之间进行序列化的原因之一是因为该对象是在Activity A中创建的,被视为匿名类创建,并且Activity A保留了对该对象的引用,因此阻止了该对象的出现。序列化。这很好,因为您可以在接口回调中创建对对象的引用,而这些引用又将通过实例化该类的引用来保留。因此,垃圾收集器将无法在这些对象上运行收集并释放空间。导致大量内存泄漏。

解决问题的另一种方法可能是使用干净的体系结构和Singleton类模式,这两个活动都可以访问它们,并且仅通过说一次Activity A

实例化一次

1
2
3
4
5
6
7
8
9
10
11
12
class SingletonErrorHandler private constructor(){
    var isError = false

    fun doOnError() {
        // do non view related stuff
        // like a network call or something          
    }

    companion object {
        val instance by lazy { SingletonErrorHandler() }
    }
}

您可以在活动中定义

1
2
3
4
5
6
7
8
9
class ActivityA : AppCompatActivity() {
    fun onError() {
        SingletonErrorHandler.instance.isError = true
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.a_activity)
    }
}

活动B

1
2
3
4
5
6
7
8
9
10
class ActivityB : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.b_activity)

        val errorHandler = SingletonErrorHandler.instance
        if(errorHandler.isError)
             errorHandler.doOnError()
    }
}


您可以编写工厂方法来启动活动,例如android studio为片段创建生成工厂方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    class RestClientErrorActivity : AppCompatActivity() {

    companion object {
        private var completion: (() -> Unit)? = null
        fun start(context: Context, completion: (() -> Unit)?) {
            RestClientErrorActivity.completion = completion
            val bundle = Bundle()
    intent.putExtra(UPDATE_CLIENT_ERROR_BUNDLE, bundle)
     context.startActivity(intent)
        }
    }

    private lateinit var retryButton: Button

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        retryButton = findViewById(R.id.btn_retry)
    }

    fun onRetryClick(view: View) {
        finish()
        completion?.invoke()
    }
}

注意:完成不是强制性的。所以我将其设置为可为空。如果您在不使用工厂方法的情况下启动活动,应用程序将不会崩溃。


我有同样的问题。如HawkPriest的答案中所述,您的对象不可序列化,因为它是一个匿名类。解决此问题的另一种方法是简单地实现一个实现您的接口的非匿名类。这是我的代码:

接口

1
2
3
interface MyInterface : Serializable {
    fun instruction()
}

Class

1
2
3
4
5
class MyClass : MyInterface {
    override fun instruction() {
        // does something
    }
}

通话活动

1
2
3
4
val myObject = MyClass()
val intent = Intent(context, MyActivity::class.java).putExtra("Tag", myObject)

context.startActivity(intent)

活动

1
2
3
4
5
override fun onCreate(savedInstanceState: Bundle?) {
    val myObject = intent.getSerializableExtra("Tag") as MyInterface

    myObject.instruction()
}

关于注释中提到的"本机资源",您可以使instruction接受参数或将其传递给MyObject

P.S。 Singleton解决方案存在的问题:

  • Singleton不符合进行垃圾收集的资格,这意味着它不再需要就可以继续生存。 (对此不是100%的肯定,但这就是我从此答案中得到的内容)
  • 使用单例将意味着您不能为活动提供"多种用途"。如果使用了一个接口,则它将能够使用该接口的多个不同实现。如果不考虑您提出的解决方案,则在您的单例中不使用接口体系结构的情况下,单例将无法提供此功能。