package com.android.app_base.base.view; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import androidx.annotation.IdRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.databinding.DataBindingUtil; import androidx.databinding.ViewDataBinding; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.lifecycle.Observer; import androidx.lifecycle.ViewModelProvider; import com.android.app_base.action.TitleBarAction; import com.android.app_base.base.StateViewEnum; import com.android.app_base.base.action.ClickAction; import com.android.app_base.base.viewmodel.BaseViewModel; import com.blankj.utilcode.util.ToastUtils; import com.gyf.immersionbar.ImmersionBar; import com.hjq.bar.TitleBar; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; /** * @author Ljj * @date 2023.03.02. 15:50 * @desc Fragment基类 */ public abstract class BaseFragment extends Fragment implements TitleBarAction, ClickAction { protected VDB binding; protected VM viewModel; protected int viewModelId; /** * 标题栏对象 */ protected TitleBar mTitleBar; /** * 状态栏沉浸 */ protected ImmersionBar mImmersionBar; /** * 根布局 */ protected View mRootView; /** * 该Fragment是否加载过数据 * */ protected boolean isLoaded; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); //页面参数初始化方法 initParam(); } @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { isLoaded = false; if (getLayoutId() > 0){ binding = initViewBinding(inflater, container); mRootView = binding.getRoot(); return mRootView; } return null; } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); //绑定 ViewDataBinding 和 ViewModel initViewDataBindingAndViewModel(); //初始化状态视图 initStateView(); //初始化沉浸式状态栏和 titleBar initStatusBar(); //页面view初始化方法 initView(); //页面事件监听的方法,用于ViewModel层转到View层的事件注册 initLiveDataObserve(); } @Override public void onResume() { super.onResume(); if (!isLoaded){ //页面数据初始化方法 initData(); isLoaded = true; } } @Override public void onDestroyView() { super.onDestroyView(); //解除Messenger注册 // Messenger.getDefault().unregister(viewModel); if(binding != null){ binding.unbind(); } mRootView = null; } /** * ViewDataBinding和 ViewModel的获取及相关绑定 */ private void initViewDataBindingAndViewModel() { viewModelId = getVariableId(); viewModel = initViewModel(); //关联ViewModel binding.setVariable(viewModelId, viewModel); //支持LiveData绑定xml,数据改变,UI自动会更新 binding.setLifecycleOwner(this); //让ViewModel拥有View的生命周期感应 getLifecycle().addObserver(viewModel); } /** * 初始化ViewBinding */ protected VDB initViewBinding(LayoutInflater inflater, @Nullable ViewGroup container) { return DataBindingUtil.inflate(inflater,getLayoutId(), container, false); } /** * 初始化ViewModel * @return 返回一个ViewModel */ private VM initViewModel() { Class vmClass; Type type = getClass().getGenericSuperclass(); if (type instanceof ParameterizedType){ vmClass = (Class) ((ParameterizedType) type).getActualTypeArguments()[1]; } else { //如果没有指定泛型参数,则默认使用BaseViewModel vmClass = (Class) BaseViewModel.class; } return new ViewModelProvider(this, (ViewModelProvider.Factory) ViewModelProvider.AndroidViewModelFactory.getInstance(requireActivity().getApplication())).get(vmClass); } /** * 对状态视图liveData进行观察监听 */ private void initStateView() { viewModel.getStateViewLiveData().observe(getViewLifecycleOwner(), new Observer() { @Override public void onChanged(StateViewEnum stateViewEnum) { switch (stateViewEnum) { case DIALOG_LOADING: dialogLoading(); break; case DIALOG_DISMISS: dialogDismiss(); break; case DATA_LOADING: dataLoading(); break; case DATA_ERROR: dataError(); break; case DATA_NULL: dataNull(); break; case NET_ERROR: netError(); break; case HIDE: hide(); break; default: break; } } }); viewModel.getMessageLivaData().observe(this, new Observer() { @Override public void onChanged(String message) { if (message != null){ ToastUtils.showShort(message); } } }); } /** * 缺省页等状态视图的更新 * 有需求的,在子类选择重写 */ protected void dialogLoading() { } protected void dialogDismiss() { } protected void dataLoading() { } protected void dataError() { } protected void dataNull() { } protected void netError() { } protected void hide() { } /** * 初始化沉浸式状态栏 */ protected void initStatusBar(){ if (isStatusBarImmersionEnabled()) { getImmersionBarConfig().init(); // 设置标题栏沉浸() if (getTitleBar() != null) { ImmersionBar.setTitleBar(this, getTitleBar()); getTitleBar().setOnTitleBarListener(this); } } } /** * 是否使用沉浸式状态栏,可以子类重写指定 */ protected boolean isStatusBarImmersionEnabled() { return false; } /** * 获取状态栏沉浸的配置对象 */ @NonNull public ImmersionBar getImmersionBarConfig() { if (mImmersionBar == null) { mImmersionBar = createStatusBarConfig(); } return mImmersionBar; } /** * 创建状态栏沉浸的配置对象 */ @NonNull protected ImmersionBar createStatusBarConfig() { return ImmersionBar.with(this) // 默认状态栏字体颜色为黑色 .statusBarDarkFont(isStatusBarDarkFont(),0.2f)//不写默认为亮色 .keyboardEnable(false);// 解决软键盘与底部输入框冲突问题,默认为false,还有一个重载方法,可以指定软键盘mode } /** * 获取状态栏字体颜色 */ protected boolean isStatusBarDarkFont() { // 返回真表示黑色字体 return true; } @Override @Nullable public TitleBar getTitleBar() { if (mTitleBar == null) { mTitleBar = obtainTitleBar((ViewGroup) getView()); } return mTitleBar; } /** * 获取根布局的id,由子类实现返回 * @return layout的id */ protected abstract int getLayoutId(); /** * 获取ViewModel的id,由子类实现返回 * @return BR中viewModel的id */ protected abstract int getVariableId(); /** * 初始化页面参数,例如从上一个activity传递过来的参数 */ protected abstract void initParam(); /** * 初始化页面view,例如一些view的隐藏或显示,以及点击逻辑等用户交互 */ protected abstract void initView(); /** * 初始化页面数据 */ protected abstract void initData(); /** * 初始化LiveData的监听 * 简单的数据展示可通过DataBinding直接双向绑定到xml中 */ protected abstract void initLiveDataObserve(); public FragmentActivity getSelfActivity() { return getActivity(); } @NonNull @Override public View getView() { return mRootView; } /** * 根据资源 id 获取一个 View 对象 */ public V findViewById(@IdRes int id) { return mRootView.findViewById(id); } }