Android常见基类封装

作者: 冰鉴IT | 来源:发表于2017-10-11 14:41 被阅读506次

    前段时间一直在忙找工作的事,好久没有写博客了,最近在学习一个实战项目http://coding.imooc.com/class/evaluation/100.html,讲到了基类的封装,故在此记录一下。主要涉及到Activity,Fragment和RecyclerView的适配器的封装。

    一、Activity基类的封装

    由于都有详细的注释,并且代码简单,就不再解释了,文中使用了ButterKnife。

    public abstract class Activity extends AppCompatActivity {
        protected Unbinder mUnbinder;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            //在界面初始化之前初始化窗口
            initWindows();
            if (initArgs(getIntent().getExtras())) {
                int layoutId = getContentLayoutId();
                setContentView(layoutId);
                initWidget();
                initData();
            } else {
                finish();
            }
        }
    
        /**
         * 初始化窗口
         */
        protected void initWindows(){
    
        }
        /**
         * 初始化参数
         * @param bundle 需要初始化的参数
         * @return 如果参数正确返回true,错误返回false
         */
        protected boolean initArgs(Bundle bundle) {
            return true;
        }
    
        /**
         * 获得当前界面的资源文件Id
         * @return 界面的资源文件Id
         */
        protected abstract int getContentLayoutId();
    
        /**
         * 初始化控件
         */
        protected void initWidget() {
            mUnbinder = ButterKnife.bind(this);
        }
    
        /**
         * 初始化数据
         */
        protected void initData() {
    
        }
    
        @Override
        public boolean onSupportNavigateUp() {
            //当点击界面导航返回时,finish当前界面
            finish();
            return super.onSupportNavigateUp();
        }
    
        @Override
        public void onBackPressed() {
            //获得当前Activity的所有Fragment
            @SuppressWarnings("RestrictedApi")
            List<Fragment> fragmentList = getSupportFragmentManager().getFragments();
            if (fragmentList != null && fragmentList.size() > 0){
                for (Fragment fragment : fragmentList) {
                    //是否是我们自定义的Fragment
                    if (fragment instanceof cn.codekong.common.app.Fragment){
                        if (((cn.codekong.common.app.Fragment)fragment).onBackPressed()){
                            //Fragment处理了返回事件
                            return;
                        }
                    }
                }
            }
            super.onBackPressed();
            finish();
        }
    }
    

    二、Fragment基类的封装

    public abstract class Fragment extends android.support.v4.app.Fragment {
        protected View mRoot;
        protected Unbinder mRootUnbinder;
        @Override
        public void onAttach(Context context) {
            super.onAttach(context);
            initArgs(getArguments());
        }
    
        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            if (mRoot == null){
                int layoutId = getContentLayoutId();
                //初始化当前的根布局,但是不在创建时就添加到container里面
                View root = inflater.inflate(layoutId, container, false);
                initWidget(root);
                mRoot = root;
            }else {
                if (mRoot.getParent() != null){
                    //把当前的根布局从其父控件中移除
                    ((ViewGroup)mRoot.getParent()).removeView(mRoot);
                }
            }
            return mRoot;
        }
    
        @Override
        public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
            //当View创建完成后初始化数据
            initData();
        }
    
        /**
         * 初始化参数
         * @param bundle 需要初始化的参数
         */
        protected void initArgs(Bundle bundle) {
        }
    
        /**
         * 获得当前界面的资源文件Id
         *
         * @return 资源文件Id
         */
        protected abstract int getContentLayoutId();
    
        /**
         * 初始化控件
         */
        protected void initWidget(View root) {
            mRootUnbinder = ButterKnife.bind(this, root);
        }
    
        /**
         * 初始化数据
         */
        protected void initData() {
    
        }
    
        /**
         * 返回按键触发时调用
         * @return 返回true代表自己处理返回逻辑,Activity不用处理
         * 返回false代表没有处理逻辑,交由Activity处理
         */
        public boolean onBackPressed(){
            return false;
        }
    }
    

    三、RecyclerView适配器基类的封装

    public abstract class RecyclerAdapter<Data> extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder<Data>>
            implements View.OnClickListener, View.OnLongClickListener, AdapetrCallback<Data> {
        private final List<Data> mDataList;
        private AdapterListener<Data> mAdapterListener;
    
        /**
         * 构造函数
         */
        public RecyclerAdapter() {
            this(null);
        }
    
        public RecyclerAdapter(AdapterListener<Data> listener) {
            this(new ArrayList<Data>(), listener);
        }
    
        public RecyclerAdapter(List<Data> dataList, AdapterListener<Data> listener) {
            this.mDataList = dataList;
            this.mAdapterListener = listener;
        }
    
    
        /**
         * 创建一个ViewHolder
         *
         * @param parent   RecyclerView
         * @param viewType 界面的类型,约定为xml布局的Id
         * @return
         */
        @Override
        public ViewHolder<Data> onCreateViewHolder(ViewGroup parent, int viewType) {
            //将xml布局初始化为View
            LayoutInflater inflater = LayoutInflater.from(parent.getContext());
            View root = inflater.inflate(viewType, parent, false);
            ViewHolder<Data> holder = onCreateViewHolder(root, viewType);
            //设置View的Tag将View和Holder进行关联
            root.setTag(R.id.tag_recycler_holder, holder);
            //设置事件点击
            root.setOnClickListener(this);
            root.setOnLongClickListener(this);
            //进行界面注解绑定
            holder.mUnbinder = ButterKnife.bind(holder, root);
            //绑定callback
            holder.mCallback = this;
            return holder;
        }
    
    
        /**
         * 获得一个新的ViewHolder
         *
         * @param root     根布局
         * @param viewType 布局类型,其实就是xml的Id
         * @return ViewHolder
         */
        protected abstract ViewHolder<Data> onCreateViewHolder(View root, int viewType);
    
        /**
         * 复写默认的布局类型返回
         *
         * @param position 坐标
         * @return 重写后返回的是xml文件的Id
         */
        @Override
        public int getItemViewType(int position) {
            return getItemViewType(position, mDataList.get(position));
        }
    
        /**
         * 得到布局的类型
         *
         * @param position 坐标
         * @param data     当前的数据
         * @return xml文件的Id, 用于创建ViewHolder
         */
        @LayoutRes
        protected abstract int getItemViewType(int position, Data data);
    
        /**
         * 绑定数据到Holder上
         *
         * @param holder   ViewHolder
         * @param position 坐标
         */
        @Override
        public void onBindViewHolder(ViewHolder<Data> holder, int position) {
            //获得需要绑定的数据
            Data data = mDataList.get(position);
            //触发绑定方法
            holder.bind(data);
        }
    
        /**
         * 得到当前集合的数据量
         *
         * @return
         */
        @Override
        public int getItemCount() {
            return mDataList.size();
        }
    
        /**
         * 插入一条数据并通知插入更新
         *
         * @param data
         */
        public void add(Data data) {
            mDataList.add(data);
            notifyItemInserted(mDataList.size() - 1);
        }
    
        /**
         * 插入多条数据,并通知这一段集合更新
         *
         * @param dataList
         */
        public void add(Data... dataList) {
            if (dataList != null && dataList.length > 0) {
                int startPos = mDataList.size();
                Collections.addAll(mDataList, dataList);
                notifyItemRangeInserted(startPos, dataList.length);
            }
        }
    
        /**
         * 插入多条数据,并通知这一段集合更新
         *
         * @param dataList
         */
        public void add(Collection<Data> dataList) {
            if (dataList != null && dataList.size() > 0) {
                int startPos = mDataList.size();
                mDataList.addAll(dataList);
                notifyItemRangeInserted(startPos, dataList.size());
            }
        }
    
        /**
         * 删除操作
         */
        public void clear() {
            mDataList.clear();
            notifyDataSetChanged();
        }
    
        /**
         * 替换为一个新的集合,其中包括清空
         *
         * @param dataList
         */
        public void replace(Collection<Data> dataList) {
            mDataList.clear();
            if (dataList == null || dataList.size() == 0) {
                return;
            }
            mDataList.addAll(dataList);
            notifyDataSetChanged();
        }
    
        @Override
        public void onClick(View v) {
            ViewHolder viewHolder = (ViewHolder) v.getTag(R.id.tag_recycler_holder);
            if (mAdapterListener != null) {
                //得到ViewHolder当前对应的适配器中的坐标
                int pos = viewHolder.getAdapterPosition();
                //回调方法
                mAdapterListener.onItemClick(viewHolder, mDataList.get(pos));
            }
        }
    
        @Override
        public boolean onLongClick(View v) {
            ViewHolder viewHolder = (ViewHolder) v.getTag(R.id.tag_recycler_holder);
            if (mAdapterListener != null) {
                //得到ViewHolder当前对应的适配器中的坐标
                int pos = viewHolder.getAdapterPosition();
                //回调方法
                mAdapterListener.onItemLongClick(viewHolder, mDataList.get(pos));
                return true;
            }
            return false;
        }
    
        /**
         * 设置监听器
         *
         * @param adapterListener
         */
        public void setAdapterListener(AdapterListener<Data> adapterListener) {
            this.mAdapterListener = adapterListener;
        }
    
        /**
         * 自定义监听器
         *
         * @param <Data> 泛型
         */
        public interface AdapterListener<Data> {
            //当Item点击时出发
            void onItemClick(RecyclerAdapter.ViewHolder holder, Data data);
    
            //当Item长按时触发
            void onItemLongClick(RecyclerAdapter.ViewHolder holder, Data data);
        }
    
        /**
         * 自定义的ViewHolder
         *
         * @param <Data> 泛型类型
         */
        public static abstract class ViewHolder<Data> extends RecyclerView.ViewHolder {
            protected Data mData;
            private Unbinder mUnbinder;
            private AdapetrCallback<Data> mCallback;
    
            public ViewHolder(View itemView) {
                super(itemView);
            }
    
            /**
             * 用于绑定数据
             *
             * @param data 需要绑定的数据
             */
            void bind(Data data) {
                this.mData = data;
                onBind(data);
            }
    
            /**
             * 当数据绑定时进行回调,必须复写
             *
             * @param data 需要绑定的数据
             */
            protected abstract void onBind(Data data);
    
            /**
             * holder自己对自己的Data进行更新
             *
             * @param data 需要更新的数据
             */
            public void updateData(Data data) {
                if (mCallback != null) {
                    mCallback.update(data, this);
                }
            }
        }
    }
    
    public interface AdapetrCallback<Data> {
        void update(Data data, RecyclerAdapter.ViewHolder<Data> holder);
    }
    

    四、后记

    基类的封装可以有效地提高代码的复用性,减少代码了,希望上面的分享可以帮助到需要的人。

    相关文章

      网友评论

      • e1ea6eabaa40:一般般
        e1ea6eabaa40: @冰鉴IT 原来这样,对于入门的人来说是很有用的!
        冰鉴IT: @橘子里的橙子 正在学Android,还在慢慢学习,可能写得不够好
      • 78983551cc90:有点太水
        冰鉴IT: @设计师吴彦祖 我已经自愿从首页投稿移除了
      • 78983551cc90:这种文章不配出现在首页
        冰鉴IT: @设计师吴彦祖 我没有投首页,是被编辑推荐到首页的,莫名其妙,不好意思啊
      • 6593521d888e:很专业,虽然我看不懂

      本文标题:Android常见基类封装

      本文链接:https://www.haomeiwen.com/subject/lmdwyxtx.html