Kotlin-通过Intent将函数作为参数传递

时间:2018-06-20 12:29:58

标签: android android-intent serialization kotlin

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

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接口

public interface ErrorClientListener extends Serializable {

    void tryAgainFunction();

}

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

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()
        }
    }

}

3 个答案:

答案 0 :(得分:1)

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

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

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() }
    }
}

在您可以定义的活动中

class ActivityA : AppCompatActivity() {
    fun onError() {
        SingletonErrorHandler.instance.isError = true
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.a_activity)
    }
}

活动B

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()
    }
}

答案 1 :(得分:0)

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

界面

class MyClass : MyInterface {
    override fun instruction() {
        // does something
    }
}

课程

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

context.startActivity(intent)

通话活动

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

    myObject.instruction()
}

活动

instruction

关于评论中提到的“本机资源”,您可以使MyObject接受参数或将其传递给val projection = arrayOf( MediaStore.Images.Media.DISPLAY_NAME, MediaStore.MediaColumns.RELATIVE_PATH ) val path = "Pictures/$folderName" val name = fileName val selection = MediaStore.Files.FileColumns.RELATIVE_PATH + " like ? and "+ MediaStore.Files.FileColumns.DISPLAY_NAME + " like ?" val selectionargs = arrayOf("%" + path + "%", "%" + name + "%") val cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, selection, selectionargs, null); val indexDisplayName = cursor?.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME) if(cursor!!.count > 0){ // file is exist } // or you can see displayName while (cursor!!.moveToNext()) { val displayName = indexDisplayName?.let { cursor.getString(it) } }

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

  1. Singleton不符合进行垃圾收集的资格,这意味着它在不再需要时仍然存在。 (对此不是100%的肯定,但这就是我从this answer得到的东西)
  2. 使用单例将意味着您不能为活动提供“多种用途”。如果使用了一个接口,则它将能够使用该接口的多个不同实现。考虑到我提出的解决方案,如果不在您的单例中使用接口体系结构,那么单例将无法提供这种功能。

答案 2 :(得分:0)

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

    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()
    }
}

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