前言
挖了很久的坑来填。。(゚▽゚)/
上接👉👉👉仿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吧!(≧▽≦)/
网友评论