package com.doumee.lib_coremodel.base;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.Message;
import android.util.DisplayMetrics;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.Window;
import android.view.WindowManager;
import android.webkit.WebView;
import android.widget.PopupWindow;
import androidx.annotation.IdRes;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StyleRes;
import androidx.core.app.ActivityOptionsCompat;
import androidx.databinding.DataBindingUtil;
import androidx.databinding.ViewDataBinding;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelStoreOwner;
import com.doumee.lib_coremodel.R;
import com.doumee.lib_coremodel.base.livedata.ActionEvent;
import com.doumee.lib_coremodel.base.livedata.MessageEvent;
import com.doumee.lib_coremodel.base.livedata.StatusEvent;
import com.doumee.lib_coremodel.bean.event.ActionEventData;
import com.doumee.lib_coremodel.view.ToastView;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/**
* MVVMFrame 框架基于Google官方的 JetPack 构建,在使用MVVMFrame时,需遵循一些规范:
*
* 如果您继承使用了BaseFragment或其子类,你需要参照如下方式添加@AndroidEntryPoint注解
*
* @example Fragment
* //-------------------------
* @AndroidEntryPoint
* public class YourFragment extends BaseFragment {
*
* }
* //-------------------------
*
* @author Jenly
*/
public abstract class BaseFragment extends Fragment implements IView, BaseNavigator {
/**
* 请通过 {@link #getVM()}获取,后续版本 {@link #mViewModel}可能会私有化
*/
private VM mViewModel;
/**
* 请通过 {@link #getDB()}获取,后续版本 {@link #mBinding}可能会私有化
*/
private VDB mBinding;
/**
* 请通过 {@link #getRootView()} ()}获取,后续版本 {@link #mRootView}可能会私有化
*/
private View mRootView;
protected static final float DEFAULT_WIDTH_RATIO = 0.85f;
private Dialog mDialog;
private Dialog mProgressDialog;
@Override
public void onAttach(Context context) {
super.onAttach(context);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
mRootView = createRootView(inflater,container,savedInstanceState);
if(isBinding()){
mBinding = DataBindingUtil.bind(mRootView);
}
if(!EventBus.getDefault().isRegistered(this)){
EventBus.getDefault().register(this);
}
initViewModel();
return mRootView;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initView(savedInstanceState);
initData(savedInstanceState);
}
/**
* 创建 {@link #mRootView}
* @param inflater
* @param container
* @param savedInstanceState
* @return
*/
protected View createRootView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState){
return inflater.inflate(getLayoutId(),container,false);
}
/**
* 获取rootView
* @return {@link #mRootView}
*/
protected View getRootView(){
return mRootView;
}
public T findViewById(@IdRes int id) {
return getRootView().findViewById(id);
}
/**
* 初始化 {@link #mViewModel}
*/
private void initViewModel(){
mViewModel = createViewModel();
if(mViewModel != null){
getLifecycle().addObserver(mViewModel);
registerLoadingEvent();
}
}
private Class getVMClass(){
Class cls = getClass();
Class vmClass = null;
while (vmClass == null && cls!= null){
vmClass = getVMClass(cls);
cls = cls.getSuperclass();
}
if(vmClass == null){
vmClass = (Class) BaseViewModel.class;
}
return vmClass;
}
private Class getVMClass(Class cls){
Type type = cls.getGenericSuperclass();
if(type instanceof ParameterizedType){
Type[] types = ((ParameterizedType)type).getActualTypeArguments();
for(Type t : types){
if(t instanceof Class){
Class vmClass = (Class)t;
if(BaseViewModel.class.isAssignableFrom(vmClass)){
return vmClass;
}
}else if(t instanceof ParameterizedType){
Type rawType = ((ParameterizedType)t).getRawType();
if(rawType instanceof Class){
Class vmClass = (Class)rawType;
if(BaseViewModel.class.isAssignableFrom(vmClass)){
return vmClass;
}
}
}
}
}
return null;
}
@Subscribe
public void LogOutEvent(LogOutEvent event){
}
@Override
public void onDestroy() {
super.onDestroy();
if(EventBus.getDefault().isRegistered(this)){
EventBus.getDefault().unregister(this);
}
if(mViewModel != null){
getLifecycle().removeObserver(mViewModel);
mViewModel = null;
}
if(mBinding != null){
mBinding.unbind();
}
}
/**
* 注册状态监听
*/
protected void registerLoadingEvent(){
mViewModel.getLoadingEvent().observe(getViewLifecycleOwner(), new Observer() {
@Override
public void onChanged(@Nullable Boolean isLoading) {
if(isLoading){
showLoading();
}else{
hideLoading();
}
}
});
}
@Override
public void showLoading() {
showProgressDialog();
}
@Override
public void hideLoading() {
dismissProgressDialog();
}
public void normalConfig(){
registerNormal();
getVM().setLifecycleOwner(this);
}
/**
* 注册动作事件
*/
protected void registerActionEvent(ActionEvent.ActionObserver observer){
mViewModel.getActionEvent().observe(this, observer);
}
public void registerNormal(){
registerActionEvent(new ActionEvent.ActionObserver() {
@Override
public void onStatusChanged(ActionEventData data) {
switch (data.getAction()){
case ActionEvent.Action.FINISH:
finish();
break;
case ActionEvent.Action.START_ACTIVITY:
startActivity(data.getClassFromData(), data.getBundleFromData());
break;
case ActionEvent.Action.TOAST:
ToastView.show(getContext(), (String) data.getData().get("toast"));
//Toast.makeText(getContext(), data.getBundleFromData().getString("toast"), Toast.LENGTH_SHORT).show();
break;
default:
otherRegister(data);
break;
}
}
});
}
protected void otherRegister(ActionEventData data){
switch (data.getAction()){
case ActionEvent.Action.DO:
int type = (int) data.getData().get("type");
doRegister(type,data);
break;
default:
break;
}
}
protected void doRegister(int type,ActionEventData data){
}
/**
* 跳转页面
*
* @param clz 所跳转的目的Activity类
* @param bundle 跳转所携带的信息
*/
public void startActivity(Class> clz, Bundle bundle) {
Intent intent = new Intent(getContext(), clz);
if (bundle != null) {
intent.putExtras(bundle);
}
startActivity(intent);
}
/**
* 注册消息事件
*/
protected void registerMessageEvent(@NonNull MessageEvent.MessageObserver observer){
mViewModel.getMessageEvent().observe(getViewLifecycleOwner(),observer);
}
/**
* 注册单个消息事件,消息对象:{@link Message}
* @param observer
*/
protected void registerSingleLiveEvent(@NonNull Observer observer){
mViewModel.getSingleLiveEvent().observe(getViewLifecycleOwner(),observer);
}
/**
* 注册状态事件
* @param observer
*/
protected void registerStatusEvent(@NonNull StatusEvent.StatusObserver observer){
mViewModel.getStatusEvent().observe(getViewLifecycleOwner(),observer);
}
/**
* 是否使用DataBinding
* @return 默认为true 表示使用。如果为false,则不会初始化 {@link #mBinding}。
*/
@Override
public boolean isBinding(){
return true;
}
/**
* 创建ViewModel
* @return 默认为null,为null时,{@link #mViewModel}会默认根据当前Activity泛型 {@link VM}获得ViewModel
*/
@Override
public VM createViewModel(){
return obtainViewModel(getVMClass());
}
/**
* 获取 ViewModel
* @return {@link #mViewModel}
*/
public VM getVM(){
return mViewModel;
}
/**
* 获取 ViewDataBinding
* @return {@link #mBinding}
*/
public VDB getDB(){
return mBinding;
}
/**
* 通过 {@link #createViewModelProvider(ViewModelStoreOwner)}获得 ViewModel
* @param modelClass
* @param
* @return
*/
public T obtainViewModel(@NonNull Class modelClass){
return createViewModelProvider(this).get(modelClass);
}
/**
* @deprecated 请使用 {@link #obtainViewModel(Class)}
* @param modelClass
* @param
* @return
*/
@Deprecated
public T getViewModel(@NonNull Class modelClass){
return obtainViewModel(modelClass);
}
/**
* 创建 {@link ViewModelProvider}
* @param owner
* @return
*/
private ViewModelProvider createViewModelProvider(@NonNull ViewModelStoreOwner owner){
return new ViewModelProvider(owner);
}
//---------------------------------------
protected void finish(){
getActivity().finish();
}
protected Intent newIntent(Class> cls){
return new Intent(getContext(),cls);
}
protected Intent newIntent(Class> cls, int flags){
Intent intent = newIntent(cls);
intent.addFlags(flags);
return intent;
}
protected void startActivity(Class> cls){
startActivity(newIntent(cls));
}
protected void startActivity(Class> cls, int flags){
startActivity(newIntent(cls,flags));
}
protected void startActivity(Class> cls, @Nullable ActivityOptionsCompat optionsCompat){
startActivity(newIntent(cls),optionsCompat);
}
protected void startActivity(Class> cls, int flags, @Nullable ActivityOptionsCompat optionsCompat){
startActivity(newIntent(cls,flags),optionsCompat);
}
protected void startActivity(Intent intent, @Nullable ActivityOptionsCompat optionsCompat){
if(optionsCompat != null){
startActivity(intent,optionsCompat.toBundle());
}else{
startActivity(intent);
}
}
protected void startActivityFinish(Class> cls){
startActivity(cls);
finish();
}
protected void startActivityFinish(Class> cls, int flags){
startActivity(cls,flags);
finish();
}
protected void startActivityFinish(Class> cls, @Nullable ActivityOptionsCompat optionsCompat){
startActivity(cls,optionsCompat);
finish();
}
protected void startActivityFinish(Class> cls, int flags, @Nullable ActivityOptionsCompat optionsCompat){
startActivity(newIntent(cls,flags),optionsCompat);
}
protected void startActivityFinish(Intent intent, @Nullable ActivityOptionsCompat optionsCompat){
startActivity(intent,optionsCompat);
}
protected void startActivityForResult(Class> cls, int requestCode){
startActivityForResult(newIntent(cls),requestCode);
}
protected void startActivityForResult(Class> cls, int requestCode, @Nullable ActivityOptionsCompat optionsCompat){
Intent intent = newIntent(cls);
if(optionsCompat != null){
startActivityForResult(intent,requestCode,optionsCompat.toBundle());
}else{
startActivityForResult(intent,requestCode);
}
}
//---------------------------------------
protected View inflate(@LayoutRes int id){
return inflate(id,null);
}
protected View inflate(@LayoutRes int id, @Nullable ViewGroup root){
return LayoutInflater.from(getContext()).inflate(id,root);
}
protected View inflate(@LayoutRes int id, @Nullable ViewGroup root, boolean attachToRoot){
return LayoutInflater.from(getContext()).inflate(id,root,attachToRoot);
}
//---------------------------------------
protected void showDialogFragment(DialogFragment dialogFragment){
String tag = dialogFragment.getTag() !=null ? dialogFragment.getTag() : dialogFragment.getClass().getSimpleName();
showDialogFragment(dialogFragment,tag);
}
protected void showDialogFragment(DialogFragment dialogFragment, String tag) {
dialogFragment.show(getFragmentManager(),tag);
}
protected void showDialogFragment(DialogFragment dialogFragment, FragmentManager fragmentManager, String tag) {
dialogFragment.show(fragmentManager,tag);
}
private View.OnClickListener mOnDialogCancelClick = new View.OnClickListener() {
@Override
public void onClick(View v) {
dismissDialog();
}
};
protected Dialog getDialog(){
return this.mDialog;
}
protected Dialog getProgressDialog(){
return this.mProgressDialog;
}
protected View.OnClickListener getDialogCancelClick(){
return mOnDialogCancelClick;
}
protected void dismissDialog(){
dismissDialog(mDialog);
}
protected void dismissDialog(Dialog dialog){
if(dialog != null && dialog.isShowing()){
dialog.dismiss();
}
}
protected void dismissPopupWindow(PopupWindow popupWindow){
if(popupWindow!=null && popupWindow.isShowing()){
popupWindow.dismiss();
}
}
protected void dismissProgressDialog(){
dismissDialog(mProgressDialog);
}
protected void showProgressDialog(){
showProgressDialog(false);
}
protected void showProgressDialog(boolean isCancel){
showProgressDialog(R.layout.mvvmframe_progress_dialog,isCancel);
}
protected void showProgressDialog(@LayoutRes int resId){
showProgressDialog(resId,false);
}
protected void showProgressDialog(@LayoutRes int resId,boolean isCancel){
showProgressDialog(inflate(resId),isCancel);
}
protected void showProgressDialog(View v){
showProgressDialog(v,false);
}
protected void showProgressDialog(View v, boolean isCancel){
dismissProgressDialog();
mProgressDialog = BaseProgressDialog.newInstance(getContext());
mProgressDialog.setContentView(v);
mProgressDialog.setCanceledOnTouchOutside(isCancel);
mProgressDialog.show();
}
protected void showDialog(View contentView){
showDialog(contentView,DEFAULT_WIDTH_RATIO);
}
protected void showDialog(View contentView, boolean isCancel){
showDialog(getContext(),contentView,R.style.mvvmframe_dialog,DEFAULT_WIDTH_RATIO,isCancel);
}
protected void showDialog(View contentView, float widthRatio){
showDialog(getContext(),contentView,widthRatio);
}
protected void showDialog(View contentView, float widthRatio, boolean isCancel){
showDialog(getContext(),contentView,R.style.mvvmframe_dialog,widthRatio,isCancel);
}
protected void showDialog(Context context, View contentView, float widthRatio){
showDialog(context,contentView, R.style.mvvmframe_dialog,widthRatio);
}
protected void showDialog(Context context, View contentView, @StyleRes int resId, float widthRatio){
showDialog(context,contentView,resId,widthRatio,true);
}
protected void showDialog(Context context, View contentView, @StyleRes int resId, float widthRatio, final boolean isCancel){
dismissDialog();
mDialog = new Dialog(context,resId);
mDialog.setContentView(contentView);
mDialog.setCanceledOnTouchOutside(false);
mDialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
@Override
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
if(keyCode == KeyEvent.KEYCODE_BACK){
if(isCancel){
dismissDialog();
}
return true;
}
return false;
}
});
setDialogWindow(mDialog,widthRatio);
mDialog.show();
}
protected void setDialogWindow(Dialog dialog, float widthRatio){
setWindow(dialog.getWindow(),widthRatio);
}
protected void setWindow(Window window, float widthRatio){
WindowManager.LayoutParams lp = window.getAttributes();
lp.width = (int)(getWidthPixels() * widthRatio);
window.setAttributes(lp);
}
//---------------------------------------
protected DisplayMetrics getDisplayMetrics(){
return getResources().getDisplayMetrics();
}
protected int getWidthPixels(){
return getDisplayMetrics().widthPixels;
}
protected int getHeightPixels(){
return getDisplayMetrics().heightPixels;
}
public void destroyWebView(WebView webView){
if (webView != null) {
webView.clearCache(true);
webView.clearHistory();
webView.removeAllViews();
// 如果先调用destroy()方法,则会命中if (isDestroyed()) return;这一行代码,需要先onDetachedFromWindow(),再
// destory()
ViewParent parent = webView.getParent();
if (parent != null) {
((ViewGroup) parent).removeView(webView);
}
webView.stopLoading();
// 退出时调用此方法,移除绑定的服务,否则某些特定系统会报错
webView.getSettings().setJavaScriptEnabled(false);
webView.clearHistory();
webView.clearView();
webView.removeAllViews();
try {
webView.destroy();
} catch (Throwable ex) {
}
}
}
}