安利一个博客,想学算法的老铁觉得难的可以推荐一个好玩的博客,程序员小灰,通过漫画的形式讲解算法。微信公众号也叫:程序员小灰
这篇文章使用Kotlin实现的,老铁们对Kotlin语法不是很熟悉可以去看下这篇博客kotlin的基础语法或者去Kotlin官网学习
Fragment向Activity传值
平常我们开发中用的比较多的Fragment传值,可以用EventBus、Handler、接口(回调),广播,静态变量等等。平常开发中我们经常会遇到Fragment和Fragment之间相互通信,Google推荐我们通过共有的Activity进行值的交换,Fragment和Fragment之间不建议直接进行交互(降低耦合性)。
这里就写一下我们平常用的最多的使用接口回调来进行Fragment到Activity值的传递的方法
- 常规写法
接口回调在Android开发中应该用的很多,比如View.OnClickListener之类的。
private var onFragmentListener: OnFragmentListener? = null
// 定义接口
interface OnFragmentListener {
fun onFunction()
}
//提供设置接口方法
fun setOnFragmentListener(onFragmentListener: OnFragmentListener) {
this.onFragmentListener = onFragmentListener
}
//在Fragment中去调用接口中的方法
if (onFragmentListener != null) {
onFragmentListener?.onFunction()
}
//最终在Activity中实现OnFragmentListener 接口
TransValFragment.getInstance().setOnFragmentListener(onFragmentListenr)
private val onFragmentListenr = object :TransValFragment.OnFragmentListener{
override fun onFunction() {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
}
就这样Fragment到Activity的传值通过接口方式就这么简单的实现了,Handler和EventBus就不写了,感兴趣的老铁可以自己弄着玩一下,还是很简单。
2. 改进写法(腾讯课堂有公开课,讲解写法,Java的方式),这里我就使用Kotlin的方式,可以自己改成Java的方式,用什么语言全凭个人爱好吧。
我们的重点还是来说一下改进的写法
方法包括方法名、返回值、参数
一般我们有四种方法:无参无返回值、无参有返回值、有参无返回值、有参有返回值
具体的实现,我们新增一个FunctionManager管理类,用来管理这四种类型的方法,定义四种类型的Map容器用来装新增的方法,然后跟我们常规实现是一样的Activity实现,接收Fragment回调,Fragment调用方法。
接下来我们就开始定义这四种类型的方法
//首先定义一个基类,因为有我们的共有属性 方法名,定义成抽象类,子类都会实现有参的构造方法
abstract class Function(var functionName: String)
//定义无参无返回值方法
abstract class FunctionNoParamNoResult(functionName: String) : Function(functionName) {
abstract fun function()
}
//定义无参有返回值的方法
abstract class FunctionWithResultOnly<Result>(functionName: String) : Function(functionName) {
abstract fun function(): Result
}
FunctionsManager,用来管理所有的方法
// 这里就抽一个方法出来吧,其他的去github上下载
//其实通过看代码跟我们平时写的在Fragment中执行的方法没什么区别,只是做了封装
/**
* 添加无参无返回值的方法
*/
// 这里我们用Map集合去保存每个方法
fun addFunction(function: FunctionNoParamNoResult): FunctionsManager {
mFunctionNoParamNoResult[function.functionName] = function
return this
}
// 具体的执行方法,通过方法名去具体的Map集合中江方法取出来,然后执行
fun invokeFunc(funcName: String) {
if (TextUtils.isEmpty(funcName)) {
return
}
// 取出方法
val noParamNoResult = mFunctionNoParamNoResult[funcName]
if (noParamNoResult != null) {
// 执行方法
noParamNoResult.function()
} else {
LogUtils.d(TAG, "The method was not found==>$funcName")
throw FunctionException("The method was not found:$funcName")
}
}
这里偷个懒就写两种方式,其余的可以去github上看,具体的方法管理类也在上面,就懒得粘贴代码
Summarize工程 地址
github地址:Fragment通用方法的定义
具体的调用逻辑
- 跟常规实现一样,常规实现是将在Activity实现的接口对象传递给Fragment,我们这里是将接方法管理类的对象传递给Fragment,一般可以定义在基类(放在具体Fragment也可以,只是放在基类可以减少依附于同一个Activity的Fragment的设置FunctionManager的方法,方便管理,更容易理解)
protected lateinit var functionsManager: FunctionsManager
// 给方法管理类具体的赋值
fun setFunctionManager(functionsManager: FunctionsManager) {
this.functionsManager = functionsManager
}
- 绑定接口,放在BaseFragment中,也可以直接放在Activity中,没有什么区别, 常规的设置方式
TransValFragment.getInstance().setOnFragmentListener(onFragmentListenr)
// 我们这里如此设置,其实就是传递一个Fragment的tag给设置方法,这个方法放在Activity的生命周期方法中也是没有问题,tag可以用fragment.tag去获取
private fun bindInterface(context: Activity) {
when (context) {
is AndroidActivity -> {
androidActivity = context
// 绑定接口调用
androidActivity.addFunctionForFragment(tag)
}
}
}
- 我们具体的去看一下addFunctionForFragment这个添加方法
fun addFunctionForFragment(tag: String?) {
// 首先我们根据tag找到具体的Fragment,因为这里是将绑定方法放在BaseFragment中,其他的Fragment都是继承的BaseFragment,也可以将绑定方法放在具体的Fragment中或者Activity中,有兴趣可以去试试
val fragment: BaseFragment = supportFragmentManager.findFragmentByTag(tag) as BaseFragment
// 然后获取方法的管理类FunctionsManager
functionsManager = FunctionsManager.getInstance()
// 在BaseFragment基类中定义的设置方法管理类的方法,这里使用链式调用
fragment.setFunctionManager(
// 开始新增方法,只需要传递方法名就可以了
functionsManager.addFunction(object :
FunctionNoParamNoResult(TransValFragment.INTERFACE_NO) {
override fun function() {
LogUtils.d(TAG, "无参无返回值的方法被调用")
}
})
)
}
- Fragment中的调用,具体的代码可以去文末后面的github地址下载
// 就是这么简单就调用了方法
functionsManager.invokeFunc(INTERFACE_NO)
具体的执行结果
Activity向Fragment传值
Activity向Fragment传值这里就不怎么讲了,具体说下常见的两种吧,其他还有什么方式可以去网上看其他博客,网上很多。
- 通过setArguments(@Nullable Bundle args),就是通过Bundle进行传值,这个是Fragment中的方法。
val bundle = Bundle()
bundle.putString("", "")
transValFragment.arguments = bundle
- 公共方法调用,在Fragment中定义一个public的方法,然后在主Activity中调用
fun testM(value: Int) {
LogUtils.d(TAG, "让Activity调用,传递值给Fragment")
}
Google官方两个Fragment之间的值传递
Google终于良心发现了,O(∩_∩)O哈哈~。
Google在最新AndroidX的库中加入了Fragment直接传递值的方法,终于可以很简单的传递值了。
Google官方Fragment值传递
导入如下库
implementation ‘androidx.fragment:fragment:1.3.0-alpha04’
- 同一水平的两个Fragment之间的值传递
监听Fragment:
setFragmentResultListener的键值key: “resultKey”,在监听和传递值的fragment我们必须使用相同的key,这样监听的Fragment才能取得具体传递的值。
getParentFragmentManager().setFragmentResultListener("resultKey", this, new FragmentResultListener() {
@Override
public void onFragmentResult(@NonNull String requestKey, @NonNull Bundle result) {
Log.e(TAG, "requestKey: " + requestKey);
Log.e(TAG, "value: " + result.getString("valueKey", "defaultValue"));
}
});
传值Fragment:
view.findViewById(R.id.btValue).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Bundle bundle = new Bundle();
bundle.putString("valueKey", "我是来自于Fragment2的值,你赶紧接收");
getParentFragmentManager().setFragmentResult("resultKey", bundle);
}
});
- 父Fragment和子Fragment之间的值传递
监听Fragment:
监听我们需要使用getChildFragmentManager(),而不再是getParentFragmentManager()
getChildFragmentManager().setFragmentResultListener("requestKey", this, new FragmentResultListener() {
@Override
public void onFragmentResult(@NonNull String requestKey, @NonNull Bundle result) {
Log.e(TAG, "requestKey: " + requestKey);
Log.e(TAG, "value: " + result.getString("valueKey", "defaultValue"));
}
});
传值Fragment: 传值依然没有区别,仍然需要使用getParentFragmentManager()
view.findViewById(R.id.btChildValue).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Bundle bundle = new Bundle();
bundle.putString("valueKey", "我是从子Fragment传递到父Fragment的值");
getParentFragmentManager().setFragmentResult("requestKey", bundle);
}
});
到这里差不多就讲完了,后续如果还有再补充,有什么问题欢迎大家一起讨论,一起进步,哈哈。
github地址:Fragment通用方法的定义
这是我总结学习的工程,所有平时学习总结的东西都会放在这里,老铁们感兴趣可以去看看,包括上面的代码,现在才开始玩还没多少东西,后期会原来越多,O(∩_∩)O哈哈~Summarize工程 地址