Android Jetpack之打造通用的BaseFragment

个人原创,转载请注明出处: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(private val brId: Int, modelClass: Class) : 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(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之打造通用的BaseFragment)