写一个逻辑清晰的startActivityForResult(),拒绝来回扒拉代码

54 篇文章 2 订阅
46 篇文章 1 订阅

前言

昨天看到郭神公众号里的一篇文章:使用Fragment优雅地处理onActivityResult,调用的截图是这样的

嗯,java语法太长了,我就顺便把我之前封装的Kotlin版贡献出来吧,写法巨简单,如下图:

怎么样,是不是简单多了

ps:更优解在这里:以回调形式使用startActivityForResult方法,并解决Activity被回收的问题_lt的博客-CSDN博客

源码

import android.app.Activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.support.v4.app.Fragment
import com.lt.androidkj.utils.extend.ContextConstant

/**
 * 创    建:  lt
 * 保存callback并执行startActivityForResult方法的Fragment
 */
class ResultCallbackFragment : Fragment() {
    var mCallback: ((Intent?) -> Unit)? = null
    var intent: Intent? = null
    var result_ok = true

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        retainInstance = true//当设备旋转时,fragment会随托管activity一起销毁并重建。为true可保留fragment
    }

    override fun onAttach(context: Context?) {
        super.onAttach(context)
        startActivityForResult(intent, ContextConstant.START_ACTIVITY_FOR_RESULT_REQUEST_CODE)
        intent = null
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        activity?.supportFragmentManager
                ?.beginTransaction()
                ?.remove(this)
                ?.commitAllowingStateLoss()
        if (resultCode == Activity.RESULT_OK && requestCode == ContextConstant.START_ACTIVITY_FOR_RESULT_REQUEST_CODE)
            mCallback?.invoke(data)
        else if (!result_ok && requestCode == ContextConstant.START_ACTIVITY_FOR_RESULT_REQUEST_CODE)
            mCallback?.invoke(data)
        mCallback = null
    }

    fun setCallbackAndIntent(callback: (Intent?) -> Unit, intent: Intent, result_ok: Boolean): ResultCallbackFragment {
        mCallback = callback
        this.intent = intent
        this.result_ok = result_ok
        return this
    }
}

object ContextConstant {
    const val START_ACTIVITY_FOR_RESULT_REQUEST_CODE = 965//startActivityForResult方法所使用到的requestCode
    const val TAG = "ResultCallbackFragment"//startActivityForResult方法所使用到的查找fragment用的tag
}

/**
 * 使用callback的方式来执行startActivityForResult方法,就不用来回查找代码了,提高了可读性
 * 注意事项:会额外耗费一些资源(相当于new一个View)
 *
 * @param intent 跳转的intent
 * @param result_ok 是否去判断result_ok,如果是false,就不判断
 * @param callback 成功的回调
 */
fun FragmentActivity.startActivityForResult(intent: Intent, result_ok: Boolean = true, callback: (Intent?) -> Unit) = supportFragmentManager
        .beginTransaction()
        .add(ResultCallbackFragment().setCallbackAndIntent(callback, intent, result_ok), ContextConstant.TAG)
        .commitAllowingStateLoss()//commit()和该方法的区别就是,这个方法不会去可以检查状态,而commit会检查状态(mStateSaved状态),如果状态不对则会抛异常

fun Fragment.startActivityForResult(intent: Intent, result_ok: Boolean = true, callback: (Intent?) -> Unit) = activity!!.startActivityForResult(intent, result_ok, callback)

inline fun <reified A : Activity> FragmentActivity.startActivityForResult(initIntent: (intent: Intent) -> Unit = {}, result_ok: Boolean = true, noinline callback: (Intent?) -> Unit) = startActivityForResult(Intent(this, A::class.java).apply(initIntent), result_ok, callback)

inline fun <reified A : Activity> Fragment.startActivityForResult(initIntent: (intent: Intent) -> Unit = {}, result_ok: Boolean = true, noinline callback: (Intent?) -> Unit) = activity!!.startActivityForResult<A>(initIntent, result_ok, callback)

直接复制然后粘到一个.kt文件里即可

其实上面这段代码我是分了三部分写的,但是为了好复制直接放到一个文件内了(也能用,不过我不喜欢大杂烩)

第一部分是一个用来存放回调和转发回调的Fragment

第二部分是一些常量

第三部分就是封装好的用来调用的扩展方法

使用

我一共封装了四个方法,总的来说是两种,一种直接传Intent(上面两个),用来适配隐式意图,调用方法如下:

    // 裁剪图片的隐式意图
    val intent = Intent("com.android.camera.action.CROP")
    intent... 中间设置各种参数省略
    startActivityForResult(intent) {
        如果回调成功会走这里,it是一个Intent?  //也就是可空的Intent
    }

然后下面两个方法是用来适配显式意图的,调用比上面方便(其实上面也可以调用显式意图)

//直接启动,不传多余的参数
startActivityForResult<WebViewActivity> {
    //回调位置,it是一个Intent?  //也就是可空的Intent 
}

//直接启动,需要给intent传参数的时候
startActivityForResult<WebViewActivity>({
    //it是一个Intent对象,可以在这里给intent设置参数
    it.putExtra("id",1)
}) {
    //回调位置,it是一个Intent?  //也就是可空的Intent
}

原理

一句话:通过给Activity添加一个空View的Fragment,然后Activity把startActivityForResult()托管给这个Fragment,回调成功后通过回调的方式来简化逻辑和代码,从此写startActivityForResult()就不用来回扒拉代码了

详细:首先获取Fragment,然后通过TAG添加到Activity中,设置Intent和CallBack,然后在Fragment的onAttach()方法(Fragment和Activity建立连接成功)的时候Fragment调用startActivityForResult(),然后等onActivityResult()触发的时候判断是否去回调CallBack,在把自身从Activity中移除,然后完成流程

其实这个并不能说是Activity调用了startActivityForResult(),而是Activity托管给Fragment来调用,只是把时机和结果返回给Activity了

对Kotlin或KMP感兴趣的同学可以进Q群 101786950

如果这篇文章对您有帮助的话

可以扫码请我喝瓶饮料或咖啡(如果对什么比较感兴趣可以在备注里写出来)

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值