您当前的位置: 首页 >  android

Kevin-Dev

暂无认证

  • 3浏览

    0关注

    544博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Android 项目必备(三)--> 基类 BaseActivity & BaseFragment

Kevin-Dev 发布时间:2017-09-07 17:13:51 ,浏览量:3

在这里插入图片描述

文章目录
  • 前言
  • 介绍
    • 1. Activity 基类
      • BaseActivity.java
      • 通过 ActivityLifecycleCallbacks 实现基类操作
    • 2. Fragment 基类
      • BaseFragment.java
      • 通过FragmentManager.FragmentLifecycleCallbacks实现

前言

在实际的 Android 产品研发中,一般的我们在写 Activity 的时候都会继承于一个基类 BaseActivity,该 BaseActivity是所有的 Activity 的基类。在该基类中我们主要用于重写一些共有的逻辑。好处是显而易见的对于一些 Activity 的共有逻辑我们不必要在每个 Activity 中都重新写一遍,只需要在基类 Activity 中写一遍就好了。

使用场景:

  • 多个子类有公有的方法,并且逻辑基本相同时;
  • 重要、复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现;
  • 重构时,模板方法模式是一个经常使用的模式,把相同的代码抽取到父类中,然后通过钩子函数约束其行为。
介绍 1. Activity 基类 BaseActivity.java
public abstract class BaseActivity extends AppCompatActivity implements IBaseActivity {

    @BindColor(R.color.colorPrimary)
    int mColor;
    @Inject
    @Nullable
    protected P mPresenter;

    protected abstract int getContentLayout();//返回页面布局id
    protected abstract void initView(Bundle savedInstanceState);//做视图相关的初始化工作
    protected abstract void initData(Bundle savedInstanceState);//做数据相关的初始化工作
    protected abstract void initEvent();//做监听事件相关的初始化工作

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (getContentLayout() != 0) {
            setContentView(getContentLayout());
            ButterKnife.bind(this);
        }
        initBarColor();//初始化状态栏/导航栏颜色,需在设置了布局后再调用
        initView(savedInstanceState);
        initData(savedInstanceState);
        initEvent();
    }

    private void initBarColor() {
        ColorBar.newColorBuilder()
                .applyNav(true)
                .navColor(mColor).navDepth(0)
                .statusColor(mColor)
                .statusDepth(0)
                .build(this)
                .apply();
    }

    @Override
    public boolean isUseEventBus() {
        return false;
    }

    @Override
    public boolean isUseFragment() {
        return true;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mPresenter != null) {
            mPresenter.destroy();
            mPresenter = null;
        }
    }
}

BaseActivity 的作用如下:

  • 重写onCreate 这样具体的Activity就不需要重写onCreate()方法,而只需重写getContentLayout()、initView(Bundle savedInstanceState);、initData(Bundle savedInstanceState)、initEvent()并在其中进行相应的操作即可

  • 设置状态栏导航栏颜色 很多时候,我们需要对app顶部的状态栏以及底部的导航栏(含有虚拟按键的那一栏)进行颜色设置从而实现沉浸式效果。对于Andriod4.4、5.0版本,它们设置颜色的方式有区别,所以需要做兼容处理。

  • 销毁 Presenter 层对 View 层的引用 这里涉及 MVP 开发模式,不了解的可以先点这里。由于Activity经常需要销毁 Presenter 层对 View 层的引用,所以移至基类中实现。

  • 实现 IBaseActivity 接口 实现该接口,以便通过Application.ActivityLifecycleCallbacks完成部分"基类操作"。

通过 ActivityLifecycleCallbacks 实现基类操作

顾名思义— Activity 生命周期回调。

当注册了该回调用,每个 Activity 进入相关生命周期时都会触发相关回调。

所以我们可以通过 Application.registerActivityLifecycleCallbacks(callback) 方法注册回调,然后在 ActivityLifecycleCallbacks 里实现一些基类操作。

@Singleton
public class ActivityLifeCallback implements Application.ActivityLifecycleCallbacks {

    @Inject
    SimpleArrayMap mMapActivityLife;
    @Inject
    Provider mActivityLifeProvider;
    @Inject
    Lazy mFragmentLifeCallbackProvider;

    @Inject
    public ActivityLifeCallback() {
    }

    @Override
    public void onActivityCreated(Activity activity, Bundle bundle) {
        if (activity instanceof IBaseActivity) {
            IActivityLife iActivityLife = mMapActivityLife.get(activity.toString());
            if (iActivityLife == null) {
                iActivityLife = mActivityLifeProvider.get();
                mMapActivityLife.put(activity.toString(), iActivityLife);
            }
            iActivityLife.onCreate(activity, bundle);
        }

        boolean isUseFragment = activity instanceof IBaseActivity ? ((IBaseActivity) activity).isUseFragment() : true;
        if (activity instanceof FragmentActivity && isUseFragment) {
            ((FragmentActivity) activity).getSupportFragmentManager().registerFragmentLifecycleCallbacks(mFragmentLifeCallbackProvider.get(), true);
        }
    }

    @Override
    public void onActivityStarted(Activity activity) {
        IActivityLife iActivityLife = mMapActivityLife.get(activity.toString());
        if (iActivityLife != null) {
            iActivityLife.onStart();
        }
    }

    @Override
    public void onActivityResumed(Activity activity) {
        IActivityLife iActivityLife = mMapActivityLife.get(activity.toString());
        if (iActivityLife != null) {
            iActivityLife.onResume();
        }
    }

    @Override
    public void onActivityPaused(Activity activity) {
        IActivityLife iActivityLife = mMapActivityLife.get(activity.toString());
        if (iActivityLife != null) {
            iActivityLife.onPause();
        }
    }

    @Override
    public void onActivityStopped(Activity activity) {
        IActivityLife iActivityLife = mMapActivityLife.get(activity.toString());
        if (iActivityLife != null) {
            iActivityLife.onStop();
        }
    }

    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
        IActivityLife iActivityLife = mMapActivityLife.get(activity.toString());
        if (iActivityLife != null) {
            iActivityLife.onSaveInstanceState(bundle);
        }
    }

    @Override
    public void onActivityDestroyed(Activity activity) {
        IActivityLife iActivityLife = mMapActivityLife.get(activity.toString());
        if (iActivityLife != null) {
            iActivityLife.onDestroy();
        }
        mMapActivityLife.remove(activity.toString());
    }

}

我把各生命周期具体要做的事情放到 ActivityLife 里执行了,下面贴上 ActivityLife 的代码:

public class ActivityLife implements IActivityLife {

    private Activity mActivity;
    private final PublishSubject mLifecycleSubject = PublishSubject.create();

    @Override
    public void onCreate(Activity activity, Bundle savedInstanceState) {
        mActivity = activity;

        mLifecycleSubject.onNext(ActivityEvent.CREATE);

        DevRing.activityStackManager().pushOneActivity(mActivity);

        if (((IBaseActivity) mActivity).isUseEventBus()) {
            DevRing.busManager().register(mActivity);
        }
    }

    @Override
    public void onStart() {
        mLifecycleSubject.onNext(ActivityEvent.START);
    }

    @Override
    public void onResume() {
        mLifecycleSubject.onNext(ActivityEvent.RESUME);
    }

    @Override
    public void onPause() {
        mLifecycleSubject.onNext(ActivityEvent.PAUSE);
    }

    @Override
    public void onStop() {
        mLifecycleSubject.onNext(ActivityEvent.STOP);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {

    }

    @Override
    public void onDestroy() {
        mLifecycleSubject.onNext(ActivityEvent.DESTROY);

        DevRing.activityStackManager().popOneActivity(mActivity);

        if (((IBaseActivity) mActivity).isUseEventBus()) {
            DevRing.busManager().unregister(mActivity);
        }
        mActivity = null;
    }
}

接下来,只要你的 Activity 实现了 IBaseActivity 接口,即可通过 ActivityLifecycleCallbacks 完成以下"基类操作":

  • 帮助控制网络请求的生命周期 通过PublishSubject的操作,在onPause()/onStop()/onDestroy()中发射终止事件,以便控制Retrofit网络请求在页面进入特定状态时终止。

  • EventBus的订阅/解除订阅 根据isUseEventBus()来决定是否进行EventBus的注册/注销。

  • Activity栈管理的入栈与出栈 以便后面可通过ActivityStackManager进行页面销毁工作。

  • FragmentLifecycleCallbacks的注册 根据isUseFragment()来决定是否注册FragmentLifecycleCallbacks。

IBaseActivity接口代码:

public interface IBaseActivity {
    /**
     * 该Activity是否订阅事件总线
     * @return true则自动进行注册/注销操作,false则不注册
     */
    boolean isUseEventBus();

    /**
     * 该Activity是否包含Fragment(是否注册FragmentLifecycleCallbacks)
     * @return
     * 返回false则不注册FragmentLifecycleCallbacks,也就是说{@link FragmentLifeCallback}中的操作不会进行
     */
    boolean isUseFragment();
}
2. Fragment 基类 BaseFragment.java
public abstract class BaseFragment extends Fragment implements IBaseFragment {

    protected Activity mActivity;
    //根布局视图
    private View mContentView;
    //视图是否已经初始化完毕
    private boolean isViewReady;
    //fragment是否处于可见状态
    private boolean isFragmentVisible;
    //是否已经初始化加载过
    protected boolean isLoaded;
    //用于butterknife解绑
    private Unbinder unbinder;
    @Inject
    @Nullable
    protected P mPresenter;

    protected abstract boolean isLazyLoad();//是否使用懒加载 (Fragment可见时才进行初始化操作(以下四个方法))
    protected abstract int getContentLayout();//返回页面布局id
    protected abstract void initView();//做视图相关的初始化工作
    protected abstract void initData();//做数据相关的初始化工作
    protected abstract void initEvent();//做监听事件相关的初始化工作

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        mActivity = (Activity) context;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        if (mContentView == null) {
            try {
                mContentView = inflater.inflate(getContentLayout(), container, false);
            } catch (Resources.NotFoundException e) {
                e.printStackTrace();
            }

            Preconditions.checkNotNull(mContentView, "根布局的id非法导致根布局为空,请检查后重试!");

            unbinder = ButterKnife.bind(this, mContentView);
        }
        return mContentView;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        //视图准备完毕
        isViewReady = true;
        if (!isLazyLoad() || isFragmentVisible) {
            init();
        }
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);

        isFragmentVisible = isVisibleToUser;
        //如果视图准备完毕且Fragment处于可见状态,则开始初始化操作
        if (isLazyLoad() && isViewReady && isFragmentVisible) {
            init();
        }
    }

    public void init() {
        if (!isLoaded) {
            isLoaded = true;
            initView();
            initData();
            initEvent();
        }
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        //ButterKnife解绑
        if (unbinder != null) unbinder.unbind();
        isViewReady = false;
        isLoaded = false;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mPresenter != null) {
            mPresenter.destroy();
            mPresenter = null;
        }
    }

    @Override
    public void onSaveState(Bundle bundleToSave) {

    }

    @Override
    public void onRestoreState(Bundle bundleToRestore) {

    }

    @Override
    public boolean isUseEventBus() {
        return false;
    }
}

BaseFragment的作用如下:

  • 延迟加载(懒加载) 如果Fragment与ViewPager结合使用的话,当加载当前Fragment时,上一页和下一页的Fragment都会预先进行加载,这样如果加载的内容很多,容易造成卡顿、速度慢。 延迟主要就是通过在setUserVisibleHint和onActivityCreated中做判断来实现的,当视图准备完毕且Fragment处于可见状态时,才开始进行初始化操作。重写isLazyLoad()方法即可决定是否开启懒加载功能。 然后具体的fragment只需重写getContentLayout()、initView()、initData()、initEvent()中进行相应的操作即可。 另外有一点需要注意,如果fragment并不是和Viewpager结合使用,而是通过FragmentManager的Transaction进行add/hide/show的话,那么在显示Fragment的时候,请显式地调用setUserVisibleHint(),如下:
//包含多个Fragment的Activity中的代码

//显示或隐藏Fragment,用于切换Fragment的展示
private void addOrShowFragment(FragmentTransaction transaction, BaseFragment fragment, String tag) {
    if (mCurrentFragment == fragment) return;

    if (!fragment.isAdded()) {
        transaction.hide(mCurrentFragment).add(R.id.fl_movie, fragment, tag).commit();
    } else {
        transaction.hide(mCurrentFragment).show(fragment).commit();
    }

    //不与ViewPager嵌套的话,需要显式调用setUserVisibleHint
    mCurrentFragment.setUserVisibleHint(false);
    mCurrentFragment = fragment;
    mCurrentFragment.setUserVisibleHint(true);
}
  • 销毁Presenter层对View层的引用 这里涉及MVP开发模式,不了解的可以先点 这里。由于Fragment经常需要销毁Presenter层对View层的引用,所以移至基类中实现。

  • 实现IBaseFragment接口。 实现该接口,以便通过FragmentManager.FragmentLifecycleCallbacks完成部分"基类操作",看完下面你就懂了。

通过FragmentManager.FragmentLifecycleCallbacks实现

同样顾名思义 — Fragment生命周期回调。

当注册了该回调用,每个Fragment进入相关生命周期时都会触发相关回调。

所以我们可以通过((FragmentActivity) activity).getSupportFragmentManager().registerFragmentLifecycleCallbacks(callback, true)方法注册回调,然后在FragmentLifecycleCallbacks里实现一些基类操作。

@Singleton
public class FragmentLifeCallback extends FragmentManager.FragmentLifecycleCallbacks {

    @Inject
    SimpleArrayMap mMapFragmentLife;
    @Inject
    Provider mFragmentLifeProvider;

    @Inject
    public FragmentLifeCallback() {
    }

    @Override
    public void onFragmentAttached(FragmentManager fm, Fragment f, Context context) {
        if (f instanceof IBaseFragment) {
            IFragmentLife iFragmentLife = mMapFragmentLife.get(f.toString());
            if (iFragmentLife == null || !iFragmentLife.isAdded()) {
                iFragmentLife = mFragmentLifeProvider.get();
                mMapFragmentLife.put(f.toString(), iFragmentLife);
//                RingLog.e("onCreate activity:" + activity.toString());
//                RingLog.e("onCreate iActivityLife:" + iActivityLife.toString());
            }
            iFragmentLife.onAttach(f, context);
        }
    }

    @Override
    public void onFragmentCreated(FragmentManager fm, Fragment f, Bundle savedInstanceState) {
        IFragmentLife iFragmentLife = mMapFragmentLife.get(f.toString());
        if (iFragmentLife != null) {
            iFragmentLife.onCreate(savedInstanceState);
        }
    }

    @Override
    public void onFragmentActivityCreated(FragmentManager fm, Fragment f, Bundle savedInstanceState) {
        IFragmentLife iFragmentLife = mMapFragmentLife.get(f.toString());
        if (iFragmentLife != null) {
            iFragmentLife.onActivityCreate(savedInstanceState);
        }
    }

    @Override
    public void onFragmentViewCreated(FragmentManager fm, Fragment f, View v, Bundle savedInstanceState) {
        IFragmentLife iFragmentLife = mMapFragmentLife.get(f.toString());
        if (iFragmentLife != null) {
            iFragmentLife.onCreateView(v,savedInstanceState);
        }
    }

    @Override
    public void onFragmentStarted(FragmentManager fm, Fragment f) {
        IFragmentLife iFragmentLife = mMapFragmentLife.get(f.toString());
        if (iFragmentLife != null) {
            iFragmentLife.onStart();
        }
    }

    @Override
    public void onFragmentResumed(FragmentManager fm, Fragment f) {
        IFragmentLife iFragmentLife = mMapFragmentLife.get(f.toString());
        if (iFragmentLife != null) {
            iFragmentLife.onResume();
        }
    }

    @Override
    public void onFragmentPaused(FragmentManager fm, Fragment f) {
        IFragmentLife iFragmentLife = mMapFragmentLife.get(f.toString());
        if (iFragmentLife != null) {
            iFragmentLife.onPause();
        }
    }

    @Override
    public void onFragmentStopped(FragmentManager fm, Fragment f) {
        IFragmentLife iFragmentLife = mMapFragmentLife.get(f.toString());
        if (iFragmentLife != null) {
            iFragmentLife.onStop();
        }
    }

    @Override
    public void onFragmentSaveInstanceState(FragmentManager fm, Fragment f, Bundle outState) {
        IFragmentLife iFragmentLife = mMapFragmentLife.get(f.toString());
        if (iFragmentLife != null) {
            iFragmentLife.onSaveInstanceState(outState);
        }
    }

    @Override
    public void onFragmentViewDestroyed(FragmentManager fm, Fragment f) {
        IFragmentLife iFragmentLife = mMapFragmentLife.get(f.toString());
        if (iFragmentLife != null) {
            iFragmentLife.onDestroyView();
        }
    }

    @Override
    public void onFragmentDestroyed(FragmentManager fm, Fragment f) {
        IFragmentLife iFragmentLife = mMapFragmentLife.get(f.toString());
        if (iFragmentLife != null) {
            iFragmentLife.onDestroy();
        }

        mMapFragmentLife.remove(f.toString());
    }

    @Override
    public void onFragmentDetached(FragmentManager fm, Fragment f) {
        IFragmentLife iFragmentLife = mMapFragmentLife.get(f.toString());
        if (iFragmentLife != null) {
            iFragmentLife.onDetach();
        }
    }
}

我把各生命周期具体要做的事情放到FragmentLife里执行了,下面贴上FragmentLife的代码:

public class FragmentLife implements IFragmentLife {

    private static final String SAVED_STATE = "saved_state";
    private final PublishSubject mLifecycleSubject = PublishSubject.create();

    private Fragment mFragment;
    private View mContentView;
    private Bundle mSavedState;//用于保存/恢复数据

    @Override
    public void onAttach(Fragment fragment, Context context) {
        mFragment = fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        mLifecycleSubject.onNext(FragmentEvent.CREATE);
        if (((IBaseFragment) mFragment).isUseEventBus()) {
            DevRing.busManager().register(mFragment);
        }
    }

    @Override
    public void onCreateView(View view, Bundle savedInstanceState) {
        mLifecycleSubject.onNext(FragmentEvent.CREATE_VIEW);
        mContentView = view;
    }

    @Override
    public void onActivityCreate(Bundle savedInstanceState) {
        restoreStateFromArguments();
    }

    @Override
    public void onStart() {
        mLifecycleSubject.onNext(FragmentEvent.START);
    }

    @Override
    public void onResume() {
        mLifecycleSubject.onNext(FragmentEvent.RESUME);
    }

    @Override
    public void onPause() {
        mLifecycleSubject.onNext(FragmentEvent.PAUSE);
    }

    @Override
    public void onStop() {
        mLifecycleSubject.onNext(FragmentEvent.STOP);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        saveStateToArguments();
    }

    @Override
    public void onDestroyView() {
        mLifecycleSubject.onNext(FragmentEvent.DESTROY_VIEW);

        if (mContentView != null) {
            ViewGroup parent = (ViewGroup) mContentView.getParent();
            if (parent != null) {
                parent.removeView(mContentView);
            }
        }

        saveStateToArguments();
    }

    @Override
    public void onDestroy() {
        mLifecycleSubject.onNext(FragmentEvent.DESTROY);

        if (((IBaseFragment) mFragment).isUseEventBus()) {
            DevRing.busManager().unregister(mFragment);
        }
        mContentView = null;
        mFragment = null;
    }

    @Override
    public void onDetach() {
        mLifecycleSubject.onNext(FragmentEvent.DETACH);
    }

    @Override
    public boolean isAdded() {
        return mFragment != null && mFragment.isAdded();
    }

    private void saveStateToArguments() {
        if (mFragment.getView() != null) {
            Bundle state = new Bundle();
            ((IBaseFragment) mFragment).onSaveState(state);
            mSavedState = state;
        }
        if (mSavedState != null) {
            Bundle b = mFragment.getArguments();
            if (b != null) {
                b.putBundle(SAVED_STATE, mSavedState);
            }
        }
    }

    private void restoreStateFromArguments() {
        Bundle b = mFragment.getArguments();
        if (b != null) {
            mSavedState = b.getBundle(SAVED_STATE);
            if (mSavedState != null) {
                ((IBaseFragment) mFragment).onRestoreState(mSavedState);
            }
        }
    }
}

接下来,只要你的Fragment实现了IBaseFragment接口(如果你的Activity实现了IBaseActivity,那还要确保isUseFragment()方法返回true),即可通过FragmentLifecycleCallbacks实现以下“基类操作”:

1. 帮助控制网络请求的生命周期 通过PublishSubject的操作,在onPause()/onStop()/onDestroy()中发射终止事件,以便控制Retrofit网络请求在页面进入特定状态时终止。

2. EventBus的订阅/解除订阅 根据isUseEventBus()来决定是否进行EventBus的注册/注销。

3. 数据的保存与恢复 fragment在保存和恢复数据方面,要比Activity复杂些,具体可以看这篇文章 。 具体Fragment通过实现onSaveState(Bundle bundleToSave)进行数据保存以及onRestoreState(Bundle bundleToRestore);进行数据恢复即可。

IBaseFragment接口代码:

public interface IBaseFragment {
    /**
     * 需要保存数据时,将数据写进bundleToSave
     */
    void onSaveState(Bundle bundleToSave);

    /**
     * 从bundleToRestore中获取你保存金曲的数据
     */
    void onRestoreState(Bundle bundleToRestore);

    /**
     * 该Fragment是否订阅事件总线
     * @return true则自动进行注册/注销操作,false则不注册
     */
    boolean isUseEventBus();
}
关注
打赏
1658837700
查看更多评论
立即登录/注册

微信扫码登录

0.0600s