美文网首页Android应用开发那些事android收集Android
Android Jetpack之打造通用的BaseFragmen

Android Jetpack之打造通用的BaseFragmen

作者: 缺牙青蛙 | 来源:发表于2019-10-14 18:47 被阅读0次

    个人原创,转载请注明出处:https://www.jianshu.com/p/43d50a58ba65

    随着Jetpack组件的火爆,单Activity+多Fragment的架构开始被越来越多的采用。Fragment写多了,难免要写许多重复的代码,这时封装一个包含了大多数重复代码的BaseFragment能起到事半功倍的效果。下面给出一个结合Databinding、ViewModel、Lifecycle的BaseFragment:

    BaseFragment

    ...
    //两个泛型,TBinding代表databinding为fragment的layout文件生成的XXXBinding,TModel代表fragment对应的viewmodel。
    //比如MainFragment的layout是fragment_main.xml,viewmodel是MainViewModel,那对应的TBinding和TModel就分别是FragmentMainBinding和MainViewModel。
    //两个变量,brId是layout里viewmodel的variable变量名在BR类里对应生成的id,modelClass则是viewmodel对应的class文件
    //比如MainViewModel在fragment_main.xml里的variable为mainViewModel,那么brId和modelClass则分别为BR.mainViewModel与MainViewModel::class.java。
    abstract class BaseFragment<TBinding: ViewDataBinding, TModel: ViewModel>(private val brId: Int, modelClass: Class<TModel>) : Fragment() {
    
        protected lateinit var binding: TBinding //也可以用by lazy,放在onVreateView里初始化更方便
    
        protected val viewModel by lazy { ViewModelProviders.of(this).get(modelClass) }
    
        protected val activity by lazy { getActivity() as MainActivity } //让具体子Fragment持有Activity的引用,方便Fragment与Activity交互
    
        private var viewHolder: View? = null //缓存界面,便于栈内复用,这样栈内的fragment回到栈顶时不用再初始化界面
    
        override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
            if (viewHolder == null) {
                //TBinding的具体类型不确定,只能用DataBindingUtil.inflate(),而不能用XXXBinding.inflate()
                binding = DataBindingUtil.inflate(inflater, getLayoutId(), container, false)
                binding.lifecycleOwner = viewLifecycleOwner //绑定databinding的lifecycle
                initView(inflater, container, savedInstanceState)//初始化界面元素和成员变量
                binding.setVariable(brId, viewModel)//执行绑定,放在initView()之后,确保ViewModel里的数据已准备完毕
                viewHolder = binding.root//缓存界面
            }
            activity.currentFragment = this //currentFragment是Activity里的变量,用来持有显示的当前Fragment,便于Activity与Fragment交互
            return binding.root
        }
    
        /**
         * 获取具体子Fragment对应的layoutResId
         **/
        protected abstract fun getLayoutId(): Int 
    
        /**
         * 初始化界面元素和成员变量
         * */
        protected abstract fun initView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?)
    ...
    }
    

    注释十分详细,就不多解释了。里面还可以加入一些各Fragment均持有的变量或方法。下面贴一个具体的子Fragment代码:

    MainFragment

    ...
    
    class MainFragment : BaseFragment<FragmentMainBinding, MainViewModel>(BR.mainViewModel, MainViewModel::class.java) {
        ...
        override fun initView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?) {
            //初始化界面元素和成员变量
            ...
        }
    
        override fun getLayoutId(): Int {
            return R.layout.fragment_main //返回对应的layoutId
        }
    
        ...
    }
    

    initView()里也可以加入各Fragment对应的初始化代码。这里还可以直接用继承自BaseFragment的activity来完成与Activity的通信。

    相关文章

      网友评论

        本文标题:Android Jetpack之打造通用的BaseFragmen

        本文链接:https://www.haomeiwen.com/subject/ftirmctx.html