life2015 / WePeiYangRD

WePeiYang Redesign

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

WePeiYangRD

WePeiYang Redesign and Refactor

模块化

每个功能模块独立开发,共同依赖基础库commons

自己开发的模块内可以使用自己喜欢的架构和依赖,没有架构也可以,开心就好

每个模块统一提供Provider模式的对外数据接口

使用RxJava的Action1接口封装,更好的适配lamdba表达式

实例代码:

/**
 * Created by retrox on 2017/1/17.
 * 每个模块的对外暴露的数据提供接口,同级无依赖的module无法调用,考虑router统一调用,暂不做实现
 * 上层依赖模块可以用普通方法调用
 * 包含一个数据的回调,使用RxJava自带的Action接口实现
 * 兼容lambda表达式
 * 内部也可以用
 */

public class GpaProvider  {

    public static final String TOKEN_GPA_LOAD_FINISHED = "token_gpa_load_finished";

    //绑定生命周期用
    private RxAppCompatActivity mActivity;

    private Action1<GpaBean> action;

    private GpaProvider(RxAppCompatActivity activity) {
        mActivity = activity;
    }

//    public GpaProvider(RxAppCompatActivity activity, Action1<GpaBean> action) {
//        mActivity = activity;
//        this.action = action;
//    }

    public void getData() {
        Observable<Notification<GpaBean>> gpaObservable =
                RetrofitProvider.getRetrofit()
                        .create(GpaApi.class)
                        .getGpa()
                        .subscribeOn(Schedulers.io())
                        .compose(mActivity.bindToLifecycle())
                        .map(ApiResponse::getData)
                        .materialize().share();

        gpaObservable.filter(Notification::isOnNext)
                .map(Notification::getValue)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(gpaBean -> {
                    //提供模块内的刷新服务,因为数据的bus是不能跨module的
                    Messenger.getDefault().send(gpaBean, TOKEN_GPA_LOAD_FINISHED);
                    if (action != null) {
                        action.call(gpaBean);
                    }
                });

        ApiErrorHandler handler = new ApiErrorHandler(mActivity);

        handler.handleError(gpaObservable.filter(Notification::isOnError)
                .map(Notification::getThrowable));

    }

    public static GpaProvider init(RxAppCompatActivity rxActivity){
        return new GpaProvider(rxActivity);
    }

    public GpaProvider registerAction(Action1<GpaBean> action){
        this.action = action;
        return this;
    }

}

调用示例(lambda)

GpaProvider.init(mContext)
                .registerAction(observableGpa::set)
                .getData();

数据提供接口设计:

不必提供模块内所有数据,只需提供首页feed流中需要的数据还要其他的概括性数据

模块间的相互调用:

上层模块依赖与下层模块,可以直接调用,activity跳转直接使用Intent即可

下层调用上层或者同级模块相互跳转,需要使用反射

                    Class clazz = null;
                    try {
                        clazz = Class.forName("com.twtstudio.retrox.wepeiyangrd.home.HomeActivity");
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }
                    Intent intent = new Intent(mActivity, clazz);
                    mActivity.startActivity(intent);

暂不引入Router框架

将来可能会使用。

一些不错的参考资料:

Android架构思考(模块化、多进程)

Android业务组件化开发实践

基础库 Commons

功能:

封装了auth模块,直接使用其中的activity进行跳转

封装网络层,RetrofitProvider封装了签名验证机制

网络异常处理的ErrorHandler(这个用不用随你喽)

网络层的具体情况要看后台的情况,目前的封装只针对于规范API,后台不规范的话可在模块内自己配置RetrofitClient和签名拦截器

封装APP类,通过反射在非app模块获取Application示例

封装公共的Prefences模块,存放Token及一些公共数据

网络封装使用示例:

传入改模块的API接口类即可

 Observable<Notification<GpaBean>> gpaObservable =
                RetrofitProvider.getRetrofit()
                        .create(GpaApi.class)
                        .getGpa()
                        .subscribeOn(Schedulers.io())
                        .compose(mActivity.bindToLifecycle())
                        .map(ApiResponse::getData)
                        .materialize().share();

微北洋3.0 全新设计 MVVM篇

  • 架构:MVVM + RxJava

依赖:

fragmentation —— 处理fragment的各种坑

mvvmkit — — 处理databinding的支持框架,并且进行功能的添加和修改

Rxlifecycle —— 处理rx绑定时候的生命周期

推荐阅读

Library:MvvmLight框架地址

中文文档:MVVM Light Toolkit使用指南

引申阅读:如何构建Android MVVM应用程序

架构设计--使用场景:

  1. adapter模式:

    layout是绑定的layout,具体寻找学习资料

    父目录ViewModel —— layout

    适配器itemViewModel —— layout

    public class ToolItemViewModel implements ViewModel {
    
        private Context mContext;
    
        private Class<? extends BaseActivity> targetAct;
    
        public final ObservableInt iconRes = new ObservableInt();
    
        public final ObservableField<String> title = new ObservableField<>();
    
        public final ReplyCommand clickCommand = new ReplyCommand(this::jump);
    
        public ToolItemViewModel(Context context, int iconres, String title, Class<? extends BaseActivity> activityClass) {
            mContext = context;
            this.iconRes.set(iconres);
            this.title.set(title);
            this.targetAct = activityClass;
        }
    
        private void jump(){
            Intent intent = new Intent(mContext,targetAct);
            mContext.startActivity(intent);
        }
    
    }

    Item 所绑定的layout代码:

    <layout xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:bind="http://schemas.android.com/apk/res-auto">
        <data>
            <variable
                name="viewModel"
                type="com.twtstudio.retrox.wepeiyangrd.home.tools.ToolItemViewModel"/>
        </data>
        <LinearLayout
            android:layout_margin="5dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            bind:clickCommand="@{viewModel.clickCommand}">
    
            <ImageView
                android:layout_width="match_parent"
                android:layout_height="70dp"
                bind:placeholderImageRes="@{viewModel.iconRes}"
                android:layout_gravity="center_horizontal"
                />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal"
                android:layout_marginTop="3dp"
                android:text="@{viewModel.title}"/>
    
        </LinearLayout>
    </layout>
    

    绑定:运用开源库 BindingCollectionAdapter 可以查阅这里的文档

    根布局的viewmodel:

    public class ToolsFragViewModel implements ViewModel {
        private Context mContext;
    
        public final ObservableArrayList<ToolItemViewModel> itemList = new ObservableArrayList<>();
    
        public final ItemView itemView = ItemView.of(BR.viewModel, R.layout.item_tool);
    
        public ToolsFragViewModel(Context context) {
            mContext = context;
            init();
        }
    
        private void init(){
            itemList.add(new ToolItemViewModel(mContext,R.drawable.ic_main_schedule,"课程表", MainActivity.class));
            itemList.add(new ToolItemViewModel(mContext,R.drawable.ic_main_gpa,"GPA", MainActivity.class));
            itemList.add(new ToolItemViewModel(mContext,R.drawable.ic_main_bike,"哲学车", MainActivity.class));
            itemList.add(new ToolItemViewModel(mContext,R.drawable.ic_main_party,"党建", MainActivity.class));
            itemList.add(new ToolItemViewModel(mContext,R.drawable.ic_main_read,"图书馆", MainActivity.class));
            // TODO: 2017/1/15 修改跳转的activity
        }
    }

    RecyclerView的绑定

    <android.support.v7.widget.RecyclerView
                android:id="@+id/recyclerView"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                bind:layoutManager="@{LayoutManagers.linear()}"
                bind:itemView="@{viewmodel.itemView}"
                bind:items="@{viewmodel.list}"/>
  2. 普通视图模式:

    布局viewmodel — — layout 即可

  3. 事件绑定

    xml的控件里面绑定ReplyCommand ——— 事件绑定

    推荐java的viewmodel中使用lambda表达式写

    public final ReplyCommand<Integer> onLoadMoreCommand =  new ReplyCommand<>((itemCount) -> { 
     int page=itemCount/LIMIT+1; 
     loadData(page.LIMIT)
    });

    Sample: RecyclerView 绑定加载更多的命令(已封装)

    <android.support.v7.widget.RecyclerView 
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    bind:onLoadMoreCommand="@{viewModel.loadMoreCommand}"/>

    SwipeRefreshLayout的下拉刷新触发的指令

    <android.support.v4.widget.SwipeRefreshLayout
            android:id="@+id/swipe_refresh_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="fill_vertical"
            app:layout_behavior="@string/appbar_scrolling_view_behavior"
            app:onRefreshCommand="@{viewModel.onRefreshCommand}"
            app:setRefreshing="@{viewModel.viewStyle.isRefreshing}">

    点击的触发指令

    <RelativeLayout
            xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:padding="12dp"
            bind:clickCommand="@{viewModel.clickCommand}">
  4. ViewModel层的数据获取设计(Rx)

    使用Rxjava处理复杂逻辑

    public class OneInfoViewModel implements ViewModel {
    
        /**
         * 用于绑定fragment的生命周期,还有context的提供
         */
        private BaseFragment mFragment;
    
        /**
         * fields 与UI绑定的可变数据源
         */
        public final ObservableField<String> imageUrl = new ObservableField<>();
    
        public final ObservableField<String> content = new ObservableField<>();
    
        public final ObservableField<String> author = new ObservableField<>();
    
        public static final SimpleDateFormat dateFormate = new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA);
    
        public OneInfoViewModel(BaseFragment fragment) {
            mFragment = fragment;
            getData();
        }
    
        /**
         * Rx 风格的数据请求
         */
        private void getData() {
            Observable<Notification<OneInfoBean>> oneInfoOb =
                    Observable.just(Calendar.getInstance())
                            .subscribeOn(Schedulers.io())
                            .map(Calendar::getTime)
                            .map(dateFormate::format)
                            .flatMap(s -> ApiClient.getService().getOneHpInfo(s))
                            .compose(mFragment.bindToLifecycle())
                            .materialize().share();
    
            oneInfoOb.filter(Notification::isOnNext)
                    .map(Notification::getValue)
                    .map(oneInfoBean -> oneInfoBean.hpEntity)
                    .doOnNext(hpEntityBean -> {
                        imageUrl.set(hpEntityBean.strOriginalImgUrl);
                        content.set(hpEntityBean.strContent);
                        author.set(hpEntityBean.strAuthor);
                    })
                    .subscribe();
    
        }
    }
  5. ViewModel层的单独测试,viewmodel对view是解耦的,所以可以单独测试viewmodel的功能模块

    Sample : ViewModel Rxjava Network Request Test —— >_<

    private void test1(){
            BaseFragment fragment = new BaseFragment();
            OneInfoViewModel viewModel = new OneInfoViewModel(fragment);
        }

About

WePeiYang Redesign


Languages

Language:Java 100.0%