两个Fragment之间的值传递

安利一个博客,想学算法的老铁觉得难的可以推荐一个好玩的博客,程序员小灰,通过漫画的形式讲解算法。微信公众号也叫:程序员小灰

这篇文章使用Kotlin实现的,老铁们对Kotlin语法不是很熟悉可以去看下这篇博客kotlin的基础语法或者去Kotlin官网学习

Fragment向Activity传值

平常我们开发中用的比较多的Fragment传值,可以用EventBus、Handler、接口(回调),广播,静态变量等等。平常开发中我们经常会遇到Fragment和Fragment之间相互通信,Google推荐我们通过共有的Activity进行值的交换,Fragment和Fragment之间不建议直接进行交互(降低耦合性)。

这里就写一下我们平常用的最多的使用接口回调来进行Fragment到Activity值的传递的方法

  1. 常规写法
    接口回调在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(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通用方法的定义

具体的调用逻辑

  1. 跟常规实现一样,常规实现是将在Activity实现的接口对象传递给Fragment,我们这里是将接方法管理类的对象传递给Fragment,一般可以定义在基类(放在具体Fragment也可以,只是放在基类可以减少依附于同一个Activity的Fragment的设置FunctionManager的方法,方便管理,更容易理解)
protected lateinit var functionsManager: FunctionsManager
// 给方法管理类具体的赋值
fun setFunctionManager(functionsManager: FunctionsManager) {
        this.functionsManager = functionsManager
}
  1. 绑定接口,放在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)
            }
        }
    }
  1. 我们具体的去看一下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, "无参无返回值的方法被调用")
                }
            })
        )
    }
  1. Fragment中的调用,具体的代码可以去文末后面的github地址下载
// 就是这么简单就调用了方法
functionsManager.invokeFunc(INTERFACE_NO)

具体的执行结果
运行结果

Activity向Fragment传值

Activity向Fragment传值这里就不怎么讲了,具体说下常见的两种吧,其他还有什么方式可以去网上看其他博客,网上很多。

  1. 通过setArguments(@Nullable Bundle args),就是通过Bundle进行传值,这个是Fragment中的方法。
val bundle = Bundle()
bundle.putString("", "")
 transValFragment.arguments = bundle
  1. 公共方法调用,在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’

  1. 同一水平的两个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);
            }
        });
  1. 父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工程 地址

你可能感兴趣的:(Android学习总结,android,kotlin)