前言
昨天看到郭神公众号里的一篇文章:使用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
如果这篇文章对您有帮助的话
可以扫码请我喝瓶饮料或咖啡(如果对什么比较感兴趣可以在备注里写出来)