安卓开发框架(MVP+主流框架+基类+工具类)--- 基类

来源:互联网 发布:php手游平台源码 编辑:程序博客网 时间:2024/05/18 22:41

《安卓开发框架》系列文章 >>>

前言

基类对于开发框架是必不可少的。在基类中一般可以进行以下操作
1.把一些频繁调用的代码封装起来。
2.提供抽象方法给子类实现,从而简化操作、得到更直接的数据。
使用好基类可以减少代码量,方便统一拓展,提高发开效率。


介绍

下面介绍demo中用到的基类,如Activity基类、Fragment基类、Adapter基类、Presenter基类。
基类的具体实现请根据自己的需求来定制,下面仅供参考

1. Activity基类

结构为: 具体Activity 继承–> ToolbarBaseActivity 继承–> BaseActivity 继承–> AbstractActivity

1.1 AbstractActivity

public abstract class AbstractActivity extends AppCompatActivity {    /**     * 设置布局     */    protected abstract void setContentLayout();    /**     * 初始化控件     */    protected abstract void initView();    /**     * 加载数据     */    protected abstract void obtainData();    /**     * 初始化监听     */    protected abstract void initEvent();}

AbstractActivity用于提供所有Activity都需要用到的抽象方法。

1.2 BaseActivity

ublic abstract class BaseActivity extends AbstractActivity implements IBaseActivity {    //"加载中"的弹窗    private ProgressDialog mProgressDialog;    //页面的堆栈管理    private ActivityStackManager mStackManager;    //状态栏导航栏颜色工具类    private UltimateBar ultimateBar;    //用于控制retrofit的生命周期,以便在destroy或其他状态时终止网络请求    public PublishSubject<LifeCycleEvent> lifecycleSubject = PublishSubject.create();    //该方法用于提供lifecycleSubject(相当于实现了IBaseView中的getLifeSubject抽象方法)。    //方便Presenter中直接通过IBaseView获取lifecycleSubject,而不用每次都作为参数传递过去    public PublishSubject<LifeCycleEvent> getLifeSubject() {        return lifecycleSubject;    }    //一般的rxjava使用场景下,控制Observable的生命周期    public <T> ObservableTransformer<T, T> controlLife(final LifeCycleEvent event) {        return  new ObservableTransformer<T, T>() {            @Override            public ObservableSource<T> apply(Observable<T> upstream) {                Observable<LifeCycleEvent> lifecycleObservable = lifecycleSubject.filter(new Predicate<LifeCycleEvent>() {                    @Override                    public boolean test(LifeCycleEvent lifeCycleEvent) throws Exception {                        //当生命周期为event状态时,发射事件                        return lifeCycleEvent.equals(event);                    }                }).take(1);                return upstream.takeUntil(lifecycleObservable);            }        };    }    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);//        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);//竖屏        init();        setContentLayout();//由具体的activity实现,设置内容布局ID        initBarColor();//初始化状态栏/导航栏颜色,需在设置了布局后再调用        initView();//由具体的activity实现,做视图相关的初始化        obtainData();//由具体的activity实现,做数据的初始化        initEvent();//由具体的activity实现,做事件监听的初始化    }    private void init() {        mStackManager = ActivityStackManager.getInstance();        mStackManager.pushOneActivity(this);    }    private void initBarColor() {        int color = getResourceColor(R.color.colorPrimary);        setBarColor(color, 0, color, 0);    }    public UltimateBar getUltimateBar() {        if (ultimateBar == null) {            ultimateBar = new UltimateBar(this);        }        return ultimateBar;    }    //设置状态栏、导航栏颜色,第二个参数控制透明度,布局内容不占据状态栏空间    public void setBarColor(int statusColor, int statusAlpha, int navColor, int navAlpha) {        getUltimateBar().setColorBar(statusColor, statusAlpha, navColor, navAlpha);    }    //单独设置状态栏的颜色,第二个参数控制透明度,布局内容不占据状态栏空间    public void setStatusBarColor(int color, int alpha) {        getUltimateBar().setColorStatusBar(color, alpha);    }    //设置状态栏、导航栏颜色(有DrawerLayout时可使用这种),第二个参数控制透明度,布局内容不占据状态栏空间    public void setBarColorForDrawer(int statusColor, int statusAlpha, int navColor, int navAlpha) {        getUltimateBar().setColorBarForDrawer(statusColor, statusAlpha, navColor, navAlpha);    }    //单独设置状态栏的颜色(有DrawerLayout时可使用这种),第二个参数控制透明度,布局内容不占据状态栏空间    public void setStatusBarColorForDrawer(int color, int alpha) {        getUltimateBar().setColorBarForDrawer(color, alpha);    }    //设置半透明的状态栏、导航栏颜色,第二个参数控制透明度,布局内容占据状态栏空间    public void setBarTranslucent(int statusColor, int statusAlpha, int navColor, int navAlpha) {        getUltimateBar().setTransparentBar(statusColor, statusAlpha, navColor, navAlpha);    }    //单独设置半透明的状态栏颜色,第二个参数控制透明度,布局内容不占据状态栏空间    public void setStatusBarTranslucent(int color, int alpha) {        getUltimateBar().setColorBarForDrawer(color, alpha);    }    //设置全透明的状态栏、导航栏颜色,布局内容占据状态栏空间,参数为是否也应用到    public void setTransparentBar(boolean applyNav) {        getUltimateBar().setImmersionBar(applyNav);    }    //隐藏状态栏、导航栏,布局内容占据状态栏导航栏空间,参数为是否也应用到导航栏上    public void hideBar(boolean applyNav) {        getUltimateBar().setHideBar(applyNav);    }    // 只有魅族(Flyme4+),小米(MIUI6+),android(6.0+)可以设置状态栏中图标、字体的颜色模式(深色模式/亮色模式)    public boolean setStatusBarMode(boolean isDark) {        Window window = getWindow();        return SystemTypeUtil.setStatusBarLightMode(window, isDark);    }    @Override    protected void onPause() {        lifecycleSubject.onNext(LifeCycleEvent.PAUSE);        super.onPause();    }    @Override    protected void onStop() {        lifecycleSubject.onNext(LifeCycleEvent.STOP);        super.onStop();    }    @Override    protected void onDestroy() {        mStackManager.popOneActivity(this);        super.onDestroy();        lifecycleSubject.onNext(LifeCycleEvent.DESTROY);    }    /**     * 显示圆形进度对话框     */    public void showLoadingDialog() {        if (mProgressDialog == null) {            mProgressDialog = new ProgressDialog(getContext());        }        mProgressDialog.showDialog();    }    /**     * 显示圆形进度对话框(不可关闭)     */    public void showNoCancelLoadingDialog() {        if (mProgressDialog == null) {            mProgressDialog = new ProgressDialog(getContext());        }        mProgressDialog.showDialog();        mProgressDialog.setCancelable(false);    }    /**     * 关闭进度对话框     */    public void dismissLoadingDialog() {        if (mProgressDialog == null) {            mProgressDialog = new ProgressDialog(getContext());        }        mProgressDialog.dismissDialog();    }    /**     * 获取页面的堆栈管理     */    public ActivityStackManager getActivityStackManager() {        return mStackManager;    }    @Override    public Context getContext() {        return this;    }    @Override    public int getResourceColor(@ColorRes int colorId) {        return ResourcesCompat.getColor(getResources(), colorId, null);    }    @Override    public String getResourceString(@StringRes int stringId) {        return getResources().getString(stringId);    }    @Override    public String getResourceString(@StringRes int id, Object... formatArgs) {        return getResources().getString(id, formatArgs);    }    @Override    public Drawable getResourceDrawable(@DrawableRes int id) {        return ResourcesCompat.getDrawable(getResources(), id, null);    }    @Override    public void onLowMemory() {        LogUtil.e("内存不足");        //清空图片内存缓存(包括Bitmap缓存和未解码图片的缓存)        FrescoUtil.clearMemoryCaches();        super.onLowMemory();    }    @Override    public boolean onKeyDown(int keyCode, KeyEvent event) {        switch (keyCode) {            case KeyEvent.KEYCODE_BACK:                if (mOnKeyClickListener != null) {//如果没有设置返回事件的监听,则默认finish页面。                    mOnKeyClickListener.clickBack();                } else {                    finish();                }                return true;            default:                return super.onKeyDown(keyCode, event);        }    }    OnKeyClickListener mOnKeyClickListener;    public void setOnKeyListener(OnKeyClickListener onKeyClickListener) {        this.mOnKeyClickListener = onKeyClickListener;    }    /**     * 按键的监听,供页面设置自定义的按键行为     */    public interface OnKeyClickListener {        /**         * 点击了返回键         */        void clickBack();        //可加入其它按键事件    }}

BaseActivity的作用如下:
1. 重写onCreate。这样具体的Activity就不需要重写onCreate()方法,而只需重写setContentLayout()、initView()、obtainData()、initEvent()并在其中进行相应的操作即可
2. 设置状态栏导航栏颜色。很多时候,我们需要对app顶部的状态栏以及底部的导航栏(含有虚拟按键的那一栏)进行颜色设置从而实现沉浸式效果。对于Andriod4.4、5.0版本,它们设置颜色的方式有区别,所以需要做兼容处理。demo中使用的是UltimateBar开源库,它内部已经做了兼容操作,并提供了几个方法来设置颜色,如不透明的、半透明的、全透明的、隐藏等。
3. 显示/隐藏loading对话框。通过提供的showLoadingDialog()/showNoCancelLoadingDialog()来弹出loading对话框,通过dismissLoadingDialog()来隐藏loading对话框。
显示loading对话框
4. Activity栈管理。在onCreate中将activity推入ActivityStackManager栈中,在onDestroy中将activity从ActivityStackManager弹出。这样就可以通过ActivityStackManager来退出某个activity或者退出应用(全部Activity)。
5. 提供Retrofit生命周期控制。 提供lifecycleSubject 以及 getLifeSubject(),在onPause()/onStop()/onDestroy()中发射终止事件,以便控制Retrofit网络请求在页面进入特定状态时终止。
6. 提供RxJava生命周期控制。提供controlLife()方法,用于一般的RxJava使用场景下控制Observable的生命周期。通过Observable.compose(this.<具体类型>controlLife(LifeCycleEvent.DESTROY))即可。
7. 内存不足时采取的措施。重写onLowMemory()并在其中加入内存不足时要采取的措施,比如清空图片内存缓存。
8. 提供资源获取方法。通过getResourceColor、getResourceString、getResourceDrawable、getContext方法便捷地获取相关资源。
9. 简化重写按键事件的操作。 具体的Activity通过setOnKeyListener传入OnKeyClickListener的具体实现即可。

1.3 ToolbarBaseActivity

public abstract class ToolbarBaseActivity extends BaseActivity {    LoadLayout mLoadLayout;//加载布局,可以显示各种状态的布局, 如加载中,加载成功, 加载失败, 无数据    @BindView(R.id.base_toolbar)    Toolbar mToolbar;    @BindView(R.id.tv_toolbar_right)    TextView mTvToolbarRight;//toolbar右侧的文字控件    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);    }    public void setContentView(int layoutResId) {        super.setContentView(R.layout.activity_base_toolbar);        addViewToContainer(layoutResId);        init();    }    //将布局加入到LoadLayout中    public void addViewToContainer(int layoutResId) {        mLoadLayout = (LoadLayout) findViewById(R.id.base_content_layout);        View view = getLayoutInflater().inflate(layoutResId, null);        mLoadLayout.removeAllViews();        mLoadLayout.addSuccessView(view);    }    public void init() {        ButterKnife.bind(this);//butterknife绑定        mToolbar.setTitle("");//必须再setSupportActionBar之前将标题置为空字符串,否则具体页面设置标题会无效        this.setSupportActionBar(mToolbar);        mToolbar.setNavigationOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                if (mOnKeyClickListener != null) {//如果没有设置返回事件的监听,则默认finish页面。                    mOnKeyClickListener.clickBack();                } else {                    finish();                }            }        });    }    /**     * 获取toolbar     */    public Toolbar getToolbar() {        return mToolbar;    }    /**     * 获取加载布局,从而设置各种加载状态     */    public LoadLayout getLoadLayout() {        return mLoadLayout;    }    @Override    protected void onStop() {        super.onStop();        if (mLoadLayout != null) {            mLoadLayout.closeAnim();        }    }}

由于本人开发中经常用到Toolbar控件,所以就加入了ToolbarBaseActivity。它的布局文件为R.layout.activity_base_toolbar,具体Activity的布局将添加到R.layout.activity_base_toolbar当中。

ToolbarBaseActivity的作用如下:
1. 包含Toolbar控件。 提供了getToolbar()方便对toolbar进行相关设置
2. ButterKnife绑定(初始化)。 调用了ButterKnife.bind(this);,具体的Activity无需再进行初始化。
3. 切换各种加载状态。 涉及到耗时请求(如网络请求)的项目,往往需要展示“加载中”、“加载成功”、“加载失败”、“无数据”这几种状态的布局。所以自定义了一个加载布局(LoadLayout),加入以上各个状态的视图,并提供切换加载状态的方法。使用步骤如下:
- 在LoadLayout中指定各个状态对应的布局文件

public class LoadLayout extends BaseLoadLayout {    //指定加载中的布局文件    private int mLoadingViewId = R.layout.layout_load_loading_view;    //指定加载失败的布局文件    private int mFailedViewId = R.layout.layout_load_failed_view;    //指定加载后无数据的布局文件    private int mNoDataViewId = R.layout.layout_load_null_data_view;    ...}
  • 具体的Activity继承基类后,通过ToolbarBaseActivity提供的setContentView()来设置布局,然后就可以调用setLayoutState来切换各种加载状态
public class CollectActivity extends ToolbarBaseActivity {    @Override    protected void setContentLayout() {        setContentView(R.layout.activity_collect);    }    @Override    protected void initView() {        //视图相关的初始化操作    }    @Override    protected void obtainData() {        //设置“加载中”状态时要做的事情        getLoadLayout().setOnLoadListener(new OnLoadListener() {            @Override            public void onLoad() {                //...比如开始请求网络数据            }        });        //设置页面为“加载中”状态        getLoadLayout().setLayoutState(State.LOADING);        //设置页面为“加载成功”状态(即显示的正常的布局R.layout.activity_collect)        getLoadLayout().setLayoutState(State.SUCCESS);        //设置页面为“加载失败”状态        getLoadLayout().setLayoutState(State.FAILED);        //设置页面为“加载后无数据”状态        getLoadLayout().setLayoutState(State.NO_DATA);    }    @Override    protected void initEvent() {        //监听事件相关的初始化操作    }}

效果可看demo运行图中的“加载中”和“无数据”状态:
切换加载状态

demo中还提供了一个DrawerbaseActivity,它继承ToolbarBaseActivity, 额外添加了侧滑抽屉(由DrawerLayout和NavigationView组成),有兴趣的朋友可以将demo中MovieActivity的基类改成DrawerbaseActivity即可看到具体效果。

2. Fragment基类

public abstract class BaseFragment extends Fragment implements IBaseFragment {    private static final String SAVED_STATE = "saved_state";    protected BaseActivity mActivity;    //加载布局,可用于设置各种加载状态,也是根布局视图    private LoadLayout mLoadLayout;    //根布局视图    private View mContentView;    //保存数据    private Bundle mSavedState;    //视图是否已经初始化完毕    private boolean isViewReady;    //fragment是否处于可见状态    private boolean isFragmentVisible;    //是否已经加载过    protected boolean isLoaded;    //用于butterknife解绑    private Unbinder unbinder;    //用于控制retrofit的生命周期,以便在destroy或其他状态时终止网络请求    public PublishSubject<LifeCycleEvent> lifecycleSubject = PublishSubject.create();    //该方法用于提供lifecycleSubject(相当于实现了IBaseView中的getLifeSubject抽象方法)。    //方便Presenter中直接通过IBaseView获取lifecycleSubject,而不用每次都作为参数传递过去    public PublishSubject<LifeCycleEvent> getLifeSubject() {        return lifecycleSubject;    }    //一般的rxjava使用场景下,控制Observable的生命周期    public <T> ObservableTransformer<T, T> controlLife(final LifeCycleEvent event) {        return  new ObservableTransformer<T, T>() {            @Override            public ObservableSource<T> apply(Observable<T> upstream) {                Observable<LifeCycleEvent> lifecycleObservable = lifecycleSubject.filter(new Predicate<LifeCycleEvent>() {                    @Override                    public boolean test(LifeCycleEvent lifeCycleEvent) throws Exception {                        //当生命周期为event状态时,发射事件                        return lifeCycleEvent.equals(event);                    }                }).take(1);                return upstream.takeUntil(lifecycleObservable);            }        };    }    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {        if (mContentView == null) {            try {                mContentView = inflater.inflate(R.layout.fragment_base, container, false);            } catch (Resources.NotFoundException e) {            }            if (mContentView == null) {                throw new NullPointerException("根布局的id非法导致根布局为空,请检查后重试!");            }            View view = inflater.inflate(setContentLayout(), null);            mLoadLayout = (LoadLayout) mContentView;            mLoadLayout.addSuccessView(view);            unbinder = ButterKnife.bind(this, mContentView);        }        return mContentView;    }    @Override    public void onActivityCreated(Bundle savedInstanceState) {        super.onActivityCreated(savedInstanceState);        //视图准备完毕        isViewReady = true;        //如果视图准备完毕且Fragment处于可见状态,则开始初始化操作        if (isViewReady && isFragmentVisible) onFragmentVisiable();        //如果之前有保存数据,则恢复数据        restoreStateFromArguments();    }    @Override    public void setUserVisibleHint(boolean isVisibleToUser) {        super.setUserVisibleHint(isVisibleToUser);        isFragmentVisible = isVisibleToUser;        //如果视图准备完毕且Fragment处于可见状态,则开始初始化操作        if (isViewReady && isFragmentVisible) onFragmentVisiable();    }    //设置并返回布局ID    protected abstract int setContentLayout();    //做视图相关的初始化    protected abstract void initView();    //来做数据的初始化    protected abstract void obtainData();    //做事件监听的初始化    protected abstract void initEvent();    public void onFragmentVisiable() {        if (!isLoaded) {            isLoaded = true;            initView();            obtainData();            initEvent();        }    }    @Override    public void onAttach(Context context) {        super.onAttach(context);        mActivity = (BaseActivity) context;    }    @Override    public void onStart() {        super.onStart();    }    @Override    public void onResume() {        super.onResume();    }    @Override    public void onPause() {        lifecycleSubject.onNext(LifeCycleEvent.PAUSE);        super.onPause();    }    @Override    public void onStop() {        lifecycleSubject.onNext(LifeCycleEvent.STOP);        super.onStop();    }    @Override    public void onDestroy() {        super.onDestroy();        lifecycleSubject.onNext(LifeCycleEvent.DESTROY);//        RefWatcher refWatcher = MyApplication.getRefWatcher(getActivity());//        if (refWatcher != null) refWatcher.watch(this);//内存泄露检测    }    /**     * 这个函数用于移除根视图     * 因为已经有过父布局的View是不能再次添加到另一个新的父布局上面的     */    @Override    public void onDestroyView() {        if (mContentView != null) {            ViewGroup parent = (ViewGroup) mContentView.getParent();            if (parent != null) {                parent.removeView(mContentView);            }        }        isViewReady = false;        //保存数据        saveStateToArguments();        super.onDestroyView();        //ButterKnife解绑        if (unbinder != null) unbinder.unbind();    }    @Override    public void onSaveInstanceState(Bundle outState) {        super.onSaveInstanceState(outState);        //保存数据        saveStateToArguments();    }    //获取加载布局,从而设置各种加载状态    public LoadLayout getLoadLayout() {        return mLoadLayout;    }    /**     * 该函数可以Find一个被定义在XML中的根视图上的控件     *     * @param id 资源id     * @return 这个id对应的控件     */    @CheckResult    public View findViewById(@IdRes int id) {        if (mContentView == null) {            throw new NullPointerException("请检查你的根布局id合法性或view不为空后再调用此方法!");        }        return mContentView.findViewById(id);    }    /**     * 可重写这个方法来恢复获取之前保存了的数据     */    protected void onRestoreState(@Nullable Bundle savedInstanceState) {    }    /**     * 可重写这个方法来保存数据,将要保存的数据放入bundle中     */    protected void onSaveState(@Nullable Bundle outState) {    }    /**     * 如果之前有保存数据,则恢复数据     * @return false表示第一次加载,true表示有保存的数据     */    private boolean restoreStateFromArguments() {        Bundle b = getArguments();        if (b != null) {            mSavedState = b.getBundle(SAVED_STATE);            if (mSavedState != null) {                restoreState();                return true;            }        }        return false;    }    private void restoreState() {        if (mSavedState != null) {            onRestoreState(mSavedState);        }    }    //保存数据    private void saveStateToArguments() {        if (getView() != null) {            mSavedState = saveState();        }        if (mSavedState != null) {            Bundle b = getArguments();            if (b != null) {                b.putBundle(SAVED_STATE, mSavedState);            }        }    }    private Bundle saveState() {        Bundle state = new Bundle();        onSaveState(state);        return state;    }    @Override    public int getResourceColor(@ColorRes int colorId, @Nullable Resources.Theme theme) {        return isAdded() ? ResourcesCompat.getColor(getResources(), colorId, null) : 0;    }    @Override    public String getResourceString(@StringRes int stringId) {        return isAdded() ? getResources().getString(stringId) : null;    }    @Override    public Drawable getResourceDrawable(@DrawableRes int id) {        return isAdded() ? ResourcesCompat.getDrawable(getResources(), id, null) : null;    }}

BaseFragment的作用如下:
1. 延迟加载(懒加载)。 如果Fragment与ViewPager结合使用的话,当加载当前Fragment时,上一页和下一页的Fragment都会预先进行加载,这样如果加载的内容很多,容易造成卡顿、速度慢。
延迟主要就是通过在setUserVisibleHint和onActivityCreated中做判断来实现的,当视图准备完毕且Fragment处于可见状态时,才开始进行初始化操作。具体的fragment只需重写setContentLayout()、initView()、obtainData()、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);}
  1. 保存/恢复数据。 fragment在保存和恢复数据方面,要比Activity复杂些,具体可以看这篇文章http://blog.csdn.net/donglynn/article/details/47065999
    在onSaveInstanceState和onDestroyView时保存数据,在onActivityCreated中恢复数据。
    具体的Fragment,则重写onSaveState方法将要保存的数据存入bundle,重写onRestoreState方法将之前保存的数据从bundle取出。如下:
  2. 提供Retrofit生命周期控制。 提供lifecycleSubject 以及 getLifeSubject(),在onPause()/onStop()/onDestroy()中发射终止事件,以便控制Retrofit网络请求在页面进入特定状态时终止。
  3. 提供RxJava生命周期控制。提供controlLife()方法,用于一般的RxJava使用场景下控制Observable的生命周期。通过Observable.compose(this.<具体类型>controlLife(LifeCycleEvent.DESTROY))即可。
  4. 提供资源获取方法。通过getResourceColor、getResourceString、getResourceDrawable方法便捷地获取相关资源。

3. Adapter基类

3.1 RecyclerBaseAdapter

public abstract class RecyclerBaseAdapter<T> extends RecyclerView.Adapter<ViewHolder> implements IRecyclerAdapter<T> {    private static final String TAG = RecyclerBaseAdapter.class.getSimpleName();    private List<T> mDataList;    private Context mContext;    protected RecyclerBaseAdapter(@NonNull Context context, @NonNull List<T> mDataList) {        if (context == null) {            throw new NullPointerException("context is not allow null!");        }        this.mDataList = mDataList;        this.mContext = context;    }    @Override    public void onBindViewHolder(final ViewHolder holder, int position) {        final int p = holder.getLayoutPosition();        bindDataForView(holder, (mDataList != null && !mDataList.isEmpty()) ? (mDataList.size() > p ? mDataList.get(p) : null) : null, p);    }    @Override    public int getItemCount() {        return mDataList != null ? mDataList.size() : 0;    }    protected abstract void bindDataForView(ViewHolder holder, T t, int position);    @Override    public Context getContext() {        return mContext;    }    @Override    public T getItem(@IntRange(from = 0) int position) {        if (position <= -1) {            return null;        }        return !CollectionUtil.isEmpty(mDataList) ? mDataList.get(position) : null;    }    @Override    public List<T> getDataList() {        return mDataList;    }    //从某个位置开始,插入一组数据    @Override    public void insertItems(@NonNull List<T> list, @IntRange(from = 0) int startIndex) {        if (mDataList == null) {            return;        }        if (list == null || list.isEmpty()) {            LogUtil.e(TAG, "插入的数据集为空或长度小于等于零, 请检查你的数据集!");            return;        }        if (this.mDataList.containsAll(list)) {            return;        }        notifyItemRangeInserted(startIndex, list.size());        mDataList.addAll(startIndex, list);        notifyItemRangeChanged(startIndex, getItemCount() - startIndex);    }    //从最底下插入一组数据    @Override    public void insertItems(@NonNull List<T> list) {        this.insertItems(list, mDataList.size());    }    //从某个位置开始,插入一个数据    @Override    public void insertItem(@NonNull T t, @IntRange(from = 0) int position) {        if (mDataList == null) {            return;        }        if (t == null) {            LogUtil.e(TAG, "插入的数据为空, 请检查你的数据!");            return;        }        notifyItemInserted(position);        mDataList.add(position, t);        notifyItemRangeChanged(position, getItemCount() - position);    }    //从最底下插入一个数据    @Override    public void insertItem(@NonNull T t) {        this.insertItem(t, mDataList.size());    }    //替换所有数据    @Override    public void replaceData(@NonNull List<T> list) {        if (mDataList == null) {            return;        }        if (list == null || list.isEmpty()) {            LogUtil.e(TAG, "插入的数据集为空或长度小于等于零, 请检查你的数据集!");            return;        }        mDataList = list;        notifyDataSetChanged();    }    //从某个位置开始,更新n个数据    @Override    public void updateItems(@IntRange(from = 0) int positionStart, @IntRange(from = 0) int itemCount) {        notifyItemRangeChanged(positionStart, itemCount);    }    //更新所有数据    @Override    public void updateAll() {        updateItems(0, mDataList.size());    }    //移除某个位置的数据    @Override    public void removeItem(@IntRange(from = 0) int position) {        if (CollectionUtil.isEmpty(mDataList) || position <= -1) {            return;        }        notifyItemRemoved(position);        mDataList.remove(position);        notifyItemRangeChanged(position, getItemCount() - position);    }    //移除所有数据    @Override    public void removeAll() {        if (CollectionUtil.isEmpty(mDataList)) {            return;        }        notifyItemRangeRemoved(0, getItemCount());        mDataList.clear();        notifyItemRangeChanged(0, getItemCount());    }}

RecyclerBaseAdapter的作用如下:
1. 重写onBindViewHolder并提供抽象方法。 由于列表项实体是不确定的,所以用到了泛型。
具体的Adapter继承该基类,通过泛型传入具体的实体类型,然后重写bindDataForView方法,即可更直接地得到实体数据。
2. 插入、删除、刷新列表项。 提供相关方法,方便子类快速调用。

3.2 LoadMoreBaseAdapter

如果你的RecyclerView需要有上拉加载更多的功能(添加Footer),那么可以继承LoadMoreBaseAdapter。
它继承RecyclerBaseAdapter,添加了Footer并提供了方法来设置footer的状态。

public abstract class LoadMoreBaseAdapter<T> extends RecyclerBaseAdapter<T> {    // 普通布局    private final int TYPE_ITEM = 1;    // 脚布局    private final int TYPE_FOOTER = 2;    // 当前加载状态,默认为加载完成    private int loadState = 2;    // 正在加载    public static final int LOADING = 1;    // 加载完成    public static final int LOADING_COMPLETE = 2;    // 加载到底了(全部数据加载完毕)    public static final int LOADING_END = 3;    public LoadMoreBaseAdapter(@NonNull Context context, @NonNull List<T> mDataList) {        super(context, mDataList);    }    @Override    public int getItemCount() {        return super.getItemCount() + 1;    }    @Override    public int getItemViewType(int position) {        // 最后一个item设置为FooterView        if (position + 1 == getItemCount()) {            return TYPE_FOOTER;        } else {            return TYPE_ITEM;        }    }    @Override    protected void bindDataForView(ViewHolder holder, T t, int position) {        if (holder.getItemViewType() == TYPE_FOOTER) {            ProgressBar pbLoading = holder.getView(R.id.pb_loading);            TextView tvLoading = holder.getView(R.id.tv_loading);            LinearLayout llEnd = holder.getView(R.id.ll_end);            switch (loadState) {                case LOADING: // 正在加载                    pbLoading.setVisibility(View.VISIBLE);                    tvLoading.setVisibility(View.VISIBLE);                    llEnd.setVisibility(View.GONE);                    break;                case LOADING_COMPLETE: // 加载完成                    pbLoading.setVisibility(View.INVISIBLE);                    tvLoading.setVisibility(View.INVISIBLE);                    llEnd.setVisibility(View.GONE);                    break;                case LOADING_END: // 加载到底                    pbLoading.setVisibility(View.GONE);                    tvLoading.setVisibility(View.GONE);                    llEnd.setVisibility(View.VISIBLE);                    break;                default:                    break;            }        } else {            bindDataForView_(holder, t, position);        }    }    @Override    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        //进行判断显示类型,来创建返回不同的View        if (viewType == TYPE_FOOTER) {            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_load_more_footer, parent, false);            return new ViewHolder(view);        } else {            return onCreateViewHolder_(parent, viewType);        }    }    @Override    public void onAttachedToRecyclerView(RecyclerView recyclerView) {        super.onAttachedToRecyclerView(recyclerView);        RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();        if (manager instanceof GridLayoutManager) {            final GridLayoutManager gridManager = ((GridLayoutManager) manager);            gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {                @Override                public int getSpanSize(int position) {                    // 如果当前是footer的位置,那么该item占据2个单元格,正常情况下占据1个单元格                    return getItemViewType(position) == TYPE_FOOTER ? gridManager.getSpanCount() : 1;                }            });        }    }    /**     * 设置上拉加载状态     *     * @param loadState 0.正在加载 1.加载完成 2.加载到底     */    public void setLoadState(int loadState) {        this.loadState = loadState;        notifyDataSetChanged();    }    protected abstract void bindDataForView_(ViewHolder holder, T t, int position);    protected abstract ViewHolder onCreateViewHolder_(ViewGroup parent, int viewType);}

当然,完整的上拉加载更多的流程还要配合列表的滚动监听来实现。完整的流程代码可以查看demo,效果图
上拉加载更多

4. Presenter基类

不了解MVP模式的可以先看《安卓开发框架(MVP+主流框架+基类+工具类)— MVP模式》

public abstract class BasePresenter<T extends IBaseView> {    protected T mIView;//方便子类直接通过该变量调用具体IView的方法    protected WeakReference<BaseActivity> mBaseViewActivity;//对Activity采用弱引用    public BasePresenter(T t, BaseActivity activity) {        mIView = t;        mBaseViewActivity = new WeakReference<>(activity);    }    public BasePresenter(BaseActivity activity) {        mBaseViewActivity = new WeakReference<>(activity);    }    public BasePresenter(T t) {        mIView = t;    }    public BasePresenter() {    }    /**     * 销毁对View层的引用,防止内存泄露,一般在activity和fragment销毁时调用     */    public void destroy() {        mIView = null;    }}

BasePresenter的作用:
1. 提供mIView方便子类调用。 由于IView类型不确定,所以使用了泛型,子类通过泛型传入具体的IView类型。
2. 避免内存泄漏。 对Activity采用弱引用,并提供destroy()方法给V层销毁时调用。


详细代码请看demo,地址:https://github.com/LJYcoder/DevBase
demo的内容流程,请看《安卓开发框架(MVP+主流框架+基类+工具类)— 开篇》

原创粉丝点击