美文网首页
仿B站Android客户端系列(一)项目环境搭建

仿B站Android客户端系列(一)项目环境搭建

作者: Misery_Dx | 来源:发表于2017-12-04 11:02 被阅读0次

    前言

    挖了很久的坑来填。。(゚▽゚)/
    上接👉👉👉仿B站Android客户端系列(启动篇)

    项目架构

    项目的基础框架是在学习的时候不断积累出来的,这个项目主要骨架也是MVP架构+Rxjava+Retrofit+Dagger,这也是技术论坛讨论最多的几个第三方库,下面就来具体说说。

    RxJava2

    RxJava这两年太火了,导致我没办法不用它。。。。。诶呀这么说太不好了,当然前提是它真的好用,能解决很多问题,优化很多代码,主要是用在处理异步操作。它的操作符十分强大,举个栗子:一个页面由多个请求的数据拼凑而成,如果不同请求相互依赖就需要写额外的逻辑来控制,而如果有RxJava的话一个zip操作符就解决了。随着代码逻辑越来越复杂,它体现的作用就越来越大,而且学习Rx的异步、链式调用思想也是很有帮助的。

    Retrofit2+Gson+Okhttp3

    这套网络请求组合拳可以说是十分实用了,相信大部分开发者都会选择它们,而且还完美契合上面的RxJava。

    Dagger2+Butterknife

    依赖注入的两把“利刃”,这俩也是优化代码的神器。Dagger2在刚入门的时候感觉非常难以理解,大多数文章都在说用法和注解的意义,然后一个demo甩脸,让人不明所以。但其实把dagger当做一个帮助我们去管理对象初始化的工具,再去学习用法会好懂一些。本项目里主要用Dagger2结合Retrofit来管理Api和结合泛型对Presenter的注入。

    黄油刀没什么好说的,主要用到的功能就是绑定控件id,处理点击事件。用起来很舒服。

    Fresco

    当下强大的图片加载库无非就是Glide、Picasso、Fresco,这里三个库可以说是各有千秋,但是看过对比分析的文章后显而易见Fresco的B格最高,功能最为强大。再加上工作中Glide用的比较多,这里抱着多接触新技术的目的就选择了Fresco。

    Fresco相对其他图片框来说没那么无脑,会复杂一点,从使用包括settings都是这样。如果使用默认设置会出现意料之外的问题。例如如果mBitmapMemoryCacheParamsSupplier使用默认不做设置的话,那么浏览图片列表时内存根本刹不住车。

    其他

    1.Fragmentation

    非常实用的Fragment管理库,这个库把Fragment的大多数常见坑都填平了,用这个可以轻松实现并管理单Activity+多Fragment或是多模块Activity+多Fragment。作者还提供了页面组合的栗子,十分良心。

    之前再用的时候觉得唯一的缺点就是Activity和Fragment必须继承库中提供的基类,这样大大降低了可扩展性(当有优先级更高的第三方基类需继承时,就会出现问题,目前良好的设计是通过接口+代理模式的方法实现),但是最近1.0版本中作者已经解决了这个问题。

    推荐一下Fragmentation这个库,作者维护很勤,良心。

    2.Multitype

    Multitype这个也安利下,这是一个封装RecyclerView.Adapter用于实现多类型复杂列表的库,通过作者巧妙地设计可以轻松实现多类型列表。这里是使用的一个栗子:

            mAdapter = new MultiTypeAdapter();
            //注册Class Type和ViewBinder
            mAdapter.register(ImageBean.class, new ImageBinder());
            mAdapter.register(TextBean.class, new TextBinder());
            mAdapter.register(VideoBean.class, new VideoBinder());
            mRecyclerView.setAdapter(mAdapter);
            //设置数据
            Items<Object> items = new Items<>();
            items.add(new ImageBean(R.drawable.image1));
            items.add(new ImageBean(R.drawable.image2));
            items.add(new TextBean("text1"));
            items.add(new TextBean("text2"));
            items.add(new TextBean("text3"));
            items.add(new VideoBean(url));
            mAdapter.setItems(items);
            mAdapter.notifyDataSetChanged();
    

    我们所需要做的工作是注册这个type的数据类型和其对应的binder,将具体的布局实现交由viewBinder,结合布局管理器LayoutManager和ItemDecoration可以很酷炫的实现多类型布局。其中binder里方法的名字与Recycler.Adapter别无二致,功能也大相径庭,如下所示:

    public abstract class ItemViewBinder<T, VH extends ViewHolder> {
    
        ......
    
        @NonNull
        protected abstract VH onCreateViewHolder(
            @NonNull LayoutInflater inflater, @NonNull ViewGroup parent);
    
        protected abstract void onBindViewHolder(@NonNull VH holder, @NonNull T item);
    
        protected final int getPosition(@NonNull final ViewHolder holder) {
            return holder.getAdapterPosition();
        }
    
        @NonNull
        protected final MultiTypeAdapter getAdapter() {
            return adapter;
        }
    }
    

    可以说这样设计代码易读性非常高,而且用起来很灵活,可扩展性高。

    3.ActivityLifecycleCallbacks

    这不是一个类库,是一个偏结构型的设计。上面再讲Fragmentation时说道Activity和Fragment继承的缺点,优秀的类库设计一般会避免这种问题出现,比如通过接口的方式侧面解决问题。

    我在看了这篇讲了ActivityLifecycleCallbacks的文章后也开始使用这种方式构建项目里面的基类。

    public final class ActivityLifecycleManager implements Application.ActivityLifecycleCallbacks {
    ......
        @Override
        public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
            boolean isIBaseActivity = activity instanceof IBaseActivity;
            boolean isIBaseMvpActivity = activity instanceof IBaseMvpActivity;
    
            //IBaseActivity 项目中的 Activity 都应实现 IBaseActivity
            if (isIBaseActivity) {
                IBaseActivity iActivity = (IBaseActivity) activity;
                //加载布局
                activity.setContentView(LayoutInflater.from(activity).inflate(iActivity.getLayoutId(), null));
                //创建变量保存实体
                ActivityBean bean = new ActivityBean();
                //绑定布局
                Unbinder unbinder = ButterKnife.bind(activity);
                bean.setUnbinder(unbinder);
                //保存变量
                activity.getIntent().putExtra(EXTRA_ACTIVITY_BEAN, bean);
                //Dagger注入
                iActivity.initInject();
                //IBaseMvpActivity 如果是 MVP Activity 则实现 IBaseMvpActivity
                if (isIBaseMvpActivity) {
                    IBaseMvpActivity mvpActivity = (IBaseMvpActivity) activity;
                    BaseView view = (BaseView) mvpActivity;
                    if (mvpActivity.getPresenter() != null) {
                        mvpActivity.getPresenter().attachView(view);
                    }
                }
                //TODO 如有其它特殊 Activity,定义新接口继承IBaseActivity,并在此处理
    
                //初始化
                iActivity.initViewAndEvent();
            }
            //TODO 第三方的 Activity 如需做公共处理,可在此处添加
    
        }
    
        @Override
        public void onActivityStarted(Activity activity) {
            if (activity instanceof IBaseMvpActivity) {
                IBaseMvpActivity mvpActivity = (IBaseMvpActivity) activity;
                mvpActivity.getPresenter().loadData();
            }
        }
    
        @Override
        public void onActivityResumed(Activity activity) {
    
        }
    
        @Override
        public void onActivityPaused(Activity activity) {
    
        }
    
        @Override
        public void onActivityStopped(Activity activity) {
            if (activity instanceof IBaseMvpActivity) {
                IBaseMvpActivity mvpActivity = (IBaseMvpActivity) activity;
                mvpActivity.getPresenter().releaseData();
            }
        }
    
        @Override
        public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
        }
    
        @Override
        public void onActivityDestroyed(Activity activity) {
            if (activity instanceof IBaseActivity) {
                ActivityBean bean = activity.getIntent().getParcelableExtra(EXTRA_ACTIVITY_BEAN);
                bean.getUnbinder().unbind();
                if (activity instanceof IBaseMvpActivity) {
                    IBaseMvpActivity iActivity = (IBaseMvpActivity) activity;
                    if (iActivity.getPresenter() != null) {
                        iActivity.getPresenter().detachView();
                    }
                }
            }
        }
    
    }
    

    在Application中设置就好

    public class App extends Application {
    
        @Override
        public void onCreate() {
            super.onCreate();
            registerActivityLifecycleCallbacks(new ActivityLifecycleManager());
        }
        
    }
    

    通过ActivityLifecycleCallbacks我们可以完成基类中的功能并且适当解耦,很多公共的逻辑都可以写进这里面,与其他基类并不冲突。并且通过Intent还可以对对象进行存储,比如完成ButterKnife的绑定与解绑。

    可以发现完全实现了基类的效果,当然用实现接口+代理的模式也可以解决基类冲突的问题,但这不失为一种优雅地解决方式。

    项目地址:FakeBiliBili

    还可以的话就赏个star吧!(≧▽≦)/

    相关文章

      网友评论

          本文标题:仿B站Android客户端系列(一)项目环境搭建

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