一个小框架,基于rx_retrofit2_mvp

离职在即,也没什么事情做,就鼓捣了一下,随意搭建了一个小框架,看看以后能不能搞出自己的一个model,好了,不说别的,上代码

1,先上依赖库

    compile 'io.reactivex:rxandroid:1.2.1'
    compile 'com.squareup.okhttp3:okhttp:3.3.1'
    compile 'io.reactivex:rxandroid:1.1.0'
    compile 'io.reactivex:rxjava:1.1.0'
    compile 'com.squareup.retrofit:retrofit:2.0.0-beta2'
    compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2'
    compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta2'
    compile 'com.android.support:design:24.2.1'
    compile 'com.android.support:recyclerview-v7:24.2.1'
    compile 'com.android.support:cardview-v7:24.2.1'
    compile 'com.jakewharton:butterknife:7.0.1'
    compile 'com.github.bumptech.glide:glide:3.7.0'
    compile 'com.github.chrisbanes.photoview:library:1.2.3'

2, 依赖retrolambda

在app.build依赖

    apply plugin: 'me.tatarka.retrolambda'
   compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

然后在项目的app.build依赖

        classpath 'me.tatarka:gradle-retrolambda:3.2.5'
       OK,到这里我们的环境搭建就完成了


3,搭建Http请求模块

  1. 搭建工具类RetrofitUtils
    package mvpmaster.lht.com.lht.utils;
    
    import com.squareup.okhttp.OkHttpClient;
    
    import java.util.concurrent.TimeUnit;
    
    import retrofit.GsonConverterFactory;
    import retrofit.Retrofit;
    import retrofit.RxJavaCallAdapterFactory;
    
    /**
     * Created by Ly on 2016/10/14.
     */
    
    public class RetrofitUtils {
        private static final int READ_TIMEOUT = 60;//读取超时时间 单位 秒
        private static final int CONN_TIMEOUT = 60;//连接超时时间 单位 秒
        private static Retrofit retrofit;
    
        public RetrofitUtils() {
        }
    
        public static Retrofit getInstance(String url) {
            retrofit = null;
            // 初始化一个okhttpClicent的对象 不然ref会自己添加一个
            OkHttpClient client = new OkHttpClient();
    //        设置读取时间为1分钟
            client.setReadTimeout(READ_TIMEOUT, TimeUnit.MINUTES);
    //        设置链接时间为12s
            client.setConnectTimeout(CONN_TIMEOUT, TimeUnit.SECONDS);
            retrofit = new Retrofit.Builder()
                    .client(client)
                    .baseUrl(url)
                    .addConverterFactory(GsonConverterFactory.create())
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                    .build();
            return retrofit;
        }
    }
    
    Ps,我发现这里并不能做到session的保持,在某些公司的后台并不能支持这样的请求库,我稍候会上传一个更新后的版本
  2. 这里写上我的一个interface(为什么我用了rx还要有callback???黑人问号脸)
    package mvpmaster.lht.com.lht.conf;
    
    /**
     * Created by Ly on 2016/10/13.
     */
    
    public interface OkHttpCallBack<T> {
        void onSuccess(T t);//成功的回调
    
        void onFaild(Throwable e);//失败的回调
    
        void onFinish();
    }
    

  3. 然后是一些比较通用的api文件了,我就不写注释了
    package mvpmaster.lht.com.lht.conf;
    
    /**
     * Created by Ly on 2016/11/2.
     */
    
    public class HttpConf {
        private static final String ZHIHU_BASE_URL = "http://news-at.zhihu.com/api/4/";
        private static final String GANK_BASE_URL = "http://gank.io/api/";
        private static final String DAILY_BASE_URL = "http://app3.qdaily.com/app3/";
    
        public static String getZhihuBaseUrl() {
            return ZHIHU_BASE_URL;
        }
    
        public static String getGankBaseUrl() {
            return GANK_BASE_URL;
        }
    
        public static String getDailyBaseUrl() {
            return DAILY_BASE_URL;
        }
    }
    

    package mvpmaster.lht.com.lht.conf;
    
    /**
     * Created by Ly on 2016/11/2.
     */
    
    public class HttpStatusConf {
        private static final int SUCCESS = 200;
    
        public static int getSUCCESS() {
            return SUCCESS;
        }
    }
    

    package mvpmaster.lht.com.lht.utils;
    
    
    import mvpmaster.lht.com.lht.ui.beanIml.DailyBean;
    import mvpmaster.lht.com.lht.ui.beanIml.NewsDetailBean;
    import mvpmaster.lht.com.lht.ui.beanIml.NewsTimeLine;
    import retrofit.http.GET;
    import retrofit.http.Path;
    import rx.Observable;
    
    /**
     * Created by Ly on 2016/10/14.
     */
    
    public interface APIService {
    
    
        @GET("news/latest")
        Observable<NewsTimeLine> getZhiHuList();
    
        @GET("news/before/{time}")
        Observable<NewsTimeLine> getBeforetNews(@Path("time") String time);
    
        @GET("news/{id}")
        Observable<NewsDetailBean> getDetailNews(@Path("id") String id);
    
    
        //    for daily
        @GET("homes/index/{num}.json")
        Observable<DailyBean> getDailyTimeLine(@Path("num") String num);
    
    }

4,网络请求搭建完了,重头戏来了,我们来搭建mvp的基本框架
  1. 我们的baseActivity
    package mvpmaster.lht.com.lht.base;
    
    import android.content.Context;
    import android.os.Build;
    import android.os.Bundle;
    import android.support.annotation.Nullable;
    import android.support.design.widget.AppBarLayout;
    import android.support.v4.widget.SwipeRefreshLayout;
    import android.support.v7.app.ActionBar;
    import android.support.v7.app.AppCompatActivity;
    import android.support.v7.widget.Toolbar;
    import android.util.TypedValue;
    import android.view.MenuItem;
    
    import butterknife.ButterKnife;
    import mvpmaster.lht.com.lht.R;
    
    /**
     * Created by Ly on 2016/11/2.
     */
    
    public abstract class BaseActivity<V, T extends BasePresenter<V>> extends AppCompatActivity {
    
        protected T mPresenter;
        private AppBarLayout mAppBar;
        private Toolbar mToolbar;
        private SwipeRefreshLayout mRefreshLayout;
    
        public Context mContext;
        private boolean mIsRequestDataRefresh = false;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            mContext = this;
            // 允许为空 不是所有的都要实现这个模式
            if (createPresenter() != null) {
                mPresenter = createPresenter();
                mPresenter.attachView((V) this);
            }
            setContentView(provideContentViewId());
            ButterKnife.bind(this);
    
            mAppBar = (AppBarLayout) findViewById(R.id.app_bar_layout);
            mToolbar = (Toolbar) findViewById(R.id.toolbar);
            if (mToolbar != null && mAppBar != null) {
                setSupportActionBar(mToolbar); //把Toolbar当做ActionBar给设置
    
                if (canBack()) {
                    ActionBar actionBar = getSupportActionBar();
                    if (null != actionBar) {
                        //设置ActionBar一个返回箭头,主界面没有,次级界面有
                        actionBar.setDisplayHomeAsUpEnabled(true);
                    }
                    if (Build.VERSION.SDK_INT >= 21) {
                        //Z轴浮动
                        mAppBar.setElevation(10.6F);
                    }
                }
            }
            if (isSetRefresh()) {
                setupSwipeRefresh();
            }
    
        }
    
        public static void toIntent(Context context, String... str) {
        }
    
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            // 此时android.R.id.home即为返回箭头
            if (item.getItemId() == android.R.id.home) {
                onBackPressed();
                finish();
                return true;
            } else {
                return super.onOptionsItemSelected(item);
            }
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            if (mPresenter != null) {
                mPresenter.detachView();
            }
        }
    
        /**
         * 生成下拉刷新
         */
        private void setupSwipeRefresh() {
            mRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh);
            if (null != mRefreshLayout) {
                mRefreshLayout.setColorSchemeResources(R.color.colorAccent, R.color.colorPrimary);
                mRefreshLayout.setProgressViewOffset(true,
                        0,
                        (int) TypedValue.applyDimension
                                (TypedValue.COMPLEX_UNIT_DIP, 24, getResources()
                                        .getDisplayMetrics()));
            }
        }
    
        /**
         * 设置刷新
         *
         * @param requestDataRefresh
         */
        public void setRefresh(boolean requestDataRefresh) {
            if (mRefreshLayout == null) {
                return;
            }
            if (!requestDataRefresh) {
                mIsRequestDataRefresh = false;
                mRefreshLayout.postDelayed(() -> {
                    if (mRefreshLayout != null) {
                        mRefreshLayout.setRefreshing(false);
                    }
                }, 1000);
            } else {
                mRefreshLayout.setRefreshing(true);
            }
        }
    
        /**
         * 数据刷新
         */
        public void requestDataRefresh() {
            mIsRequestDataRefresh = true;
        }
    
        /**
         * 判断当前 Activity 是否允许返回
         * 主界面不允许返回,次级界面允许返回
         *
         * @return false
         */
        public boolean canBack() {
            return false;
        }
    
        /**
         * 判断子Activity是否需要刷新功能
         *
         * @return false
         */
        public Boolean isSetRefresh() {
            return false;
        }
    
        /**
         * 创建P
         *
         * @return T
         */
        protected abstract T createPresenter();
    
        /**
         * 用于引入布局文件
         *
         * @return
         */
        abstract protected int provideContentViewId();
    }
    

    package mvpmaster.lht.com.lht.base;
    
    import android.content.Context;
    import android.os.Bundle;
    import android.support.v4.app.Fragment;
    import android.support.v4.widget.SwipeRefreshLayout;
    import android.util.TypedValue;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    
    import butterknife.ButterKnife;
    import mvpmaster.lht.com.lht.R;
    
    /**
     * Created by Ly on 2016/11/2.
     */
    
    public abstract class BaseFragment<V, T extends BasePresenter<V>> extends Fragment {
        protected Context mContext;
        protected T mPresenter;
    
        private boolean mIsRequestDataRefresh = false;
        private SwipeRefreshLayout mRefreshLayout;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            mContext = getActivity();
            mPresenter = createPresenter();
            mPresenter.attachView((V) this);
        }
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            View rootView = inflater.inflate(createViewLayoutId(), container, false);
            ButterKnife.bind(this, rootView);
            initView(rootView);
            if (isSetRefresh()) {
                setupSwipeRefresh(rootView);
            }
            return rootView;
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            mPresenter.detachView();
        }
    
        private void setupSwipeRefresh(View view) {
            mRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipe_refresh);
            if (mRefreshLayout != null) {
                mRefreshLayout.setColorSchemeResources(R.color.refresh_progress_1,
                        R.color.refresh_progress_2, R.color.refresh_progress_3);
                mRefreshLayout.setProgressViewOffset(true, 0, (int) TypedValue
                        .applyDimension(TypedValue.COMPLEX_UNIT_DIP, 24, getResources().getDisplayMetrics()));
                mRefreshLayout.setOnRefreshListener(this::requestDataRefresh);
            }
        }
    
        public void requestDataRefresh() {
            mIsRequestDataRefresh = true;
        }
    
    
        public void setRefresh(boolean requestDataRefresh) {
            if (mRefreshLayout == null) {
                return;
            }
            if (!requestDataRefresh) {
                mIsRequestDataRefresh = false;
                mRefreshLayout.postDelayed(() -> {
                    if (mRefreshLayout != null) {
                        mRefreshLayout.setRefreshing(false);
                    }
                }, 1000);
            } else {
                mRefreshLayout.setRefreshing(true);
            }
        }
    
        protected abstract T createPresenter();
    
        protected abstract int createViewLayoutId();
    
        protected void initView(View rootView) {
        }
    
        public Boolean isSetRefresh() {
            return true;
        }
    }
    
    还有其他的一些base,我就不一一上传了。
  2. 说一下我理解的mvp,在我的看法中,mvp,m是要做一些耗时操作的,像读取网络数据,数据库数据,sp数据啊...这些脏活苦活全部都丢给它去做,我们在contract中给它定义好了interface,model类在自己本身去实现它,然后按着上层的要求去做那些苦活累活;而View呢?我觉得一般是指我们的activity或者fragment巴,他们就负责一些比较轻松的东西了,像显示个toast啊,show一下dialog啊,拿一下editext的数据啊,最苦力也就是设置个适配器啊,监听一下滑动啊之类的,反正最轻松的那个就是它了;然后就是presenter了,这个类我觉得挺难弄的,类似于红娘吧,它也要实现Contract的interface,并且要持有model和view的引用,在interface的回调里面去操控model类去做耗时操作,然后在相应的callback(怎么又是callback?)去操控view去实现各种交互。(不要喷我说得那么模糊,但是这种东西写不出来,用了就会有这种想法,而且!用了一次mvp,你就不会再想去用mvc了)
  3. 我们举一个例子,首页那里拿取了知乎的信息,用了一个recyclerview去显示拿到的数据,我们就用它来讲,我先上传一波项目目录,不然太懵逼了。
  4. 我们先看我们的fragment 
    package mvpmaster.lht.com.lht.ui.fragment.zhuhu;
    
    import android.os.Bundle;
    import android.support.v7.widget.LinearLayoutManager;
    import android.support.v7.widget.RecyclerView;
    import android.view.View;
    import android.widget.Toast;
    
    import butterknife.Bind;
    import mvpmaster.lht.com.lht.R;
    import mvpmaster.lht.com.lht.base.BaseFragment;
    import mvpmaster.lht.com.lht.ui.adapter.ZhiHuAdapter;
    import mvpmaster.lht.com.lht.ui.beanIml.NewsTimeLine;
    
    /**
     * Created by Ly on 2016/11/2.
     */
    
    public class ZhiHuFragment extends BaseFragment<ZhiHuContract.ZhiHuView, ZhiHuPresenter> implements ZhiHuContract.ZhiHuView {
        @Bind(R.id.content_list)
        RecyclerView mRlvZhiHu;
        
        private LinearLayoutManager mLayoutManager;
        private ZhiHuAdapter zhiHuAdapter;
    
        // 最后一个可见的视图
        private int lastVisibleItem;
        // 是否加载过更多
        private boolean isLoadMore = false;
        // 知乎日报需要的下一个参数
        private String time;
    
    
    
        /**
         * 初始化配置
         */
        private void initConf() {
    //        适配器
            zhiHuAdapter = new ZhiHuAdapter(getActivity());
    //        manager
            mLayoutManager = new LinearLayoutManager(getActivity());
            mRlvZhiHu.setLayoutManager(mLayoutManager);
            mRlvZhiHu.setAdapter(zhiHuAdapter);
    //        启动自动刷新配置
            setDataRefresh(true);
    //        获取第一次的数据
            mPresenter.getDataList();
    //        检测recView的滑动状态
            scrollRecycleView();
        }
    
        /**
         * recyclerView Scroll listener , maybe in here is wrong ?
         */
        public void scrollRecycleView() {
            mRlvZhiHu.addOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override
                public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                    super.onScrollStateChanged(recyclerView, newState);
                    if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                        lastVisibleItem = mLayoutManager
                                .findLastVisibleItemPosition();
                        if (mLayoutManager.getItemCount() == 1) {
                            zhiHuAdapter.updateLoadStatus(zhiHuAdapter.getLOAD_MORE());
                            return;
                        }
                        if (lastVisibleItem + 1 == mLayoutManager
                                .getItemCount()) {
                            zhiHuAdapter.updateLoadStatus(zhiHuAdapter.getLOAD_PULL_TO());
                            isLoadMore = true;
                            zhiHuAdapter.updateLoadStatus(zhiHuAdapter.getLOAD_MORE());
                            mPresenter.getBeforeDateList(time);
                        }
                    }
                }
    
                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
                    lastVisibleItem = mLayoutManager.findLastVisibleItemPosition();
                }
            });
        }
    
        @Override
        public void requestDataRefresh() {
            super.requestDataRefresh();
            setDataRefresh(true);
            mPresenter.getDataList();
        }
    
        @Override
        protected ZhiHuPresenter createPresenter() {
            return new ZhiHuPresenter(this);
        }
    
        @Override
        protected int createViewLayoutId() {
            return R.layout.fragment_zhihu;
        }
    
        @Override
        public void setDataRefresh(boolean refresh) {
            setRefresh(refresh);
        }
    
        public static ZhiHuFragment newInstance() {
            Bundle args = new Bundle();
            ZhiHuFragment fragment = new ZhiHuFragment();
            fragment.setArguments(args);
            return fragment;
        }
    
    
        @Override
        public void loadFinishAndReset(NewsTimeLine newsTimeLine, String time) {
            zhiHuAdapter.resetData(newsTimeLine);
            setDataRefresh(false);
            this.time = time;
        }
    
        @Override
        public void loadFinishAndAdd(NewsTimeLine newsTimeLine, String time) {
            zhiHuAdapter.addData(newsTimeLine);
            this.time = time;
        }
    
        @Override
        public void loadFailure() {
            setDataRefresh(false);
            zhiHuAdapter.updateLoadStatus(zhiHuAdapter.getLOAD_FAILURE());
        }
    
        @Override
        protected void initView(View rootView) {
            super.initView(rootView);
            initConf();
        }
    
        @Override
        public void TsShow(String msg) {
            Toast.makeText(getActivity(), msg, Toast.LENGTH_SHORT).show();
        }
    }
    
    我们在这个看到一个mPresenter,这个是什么鬼?是从哪里来的?其实这个就是Presenter的对象了,也是BaseActivity的泛型里面的那个我们点取查看它的引用,发现在这个fragment里面一共被引用了3次,第一次是刚进去页面的时候,第一次读取数据,第二个是下拉加载的时候,读取了下一波的数据,再有一次是上拉刷新的时候,我们重新刷新了一次页面拿取了最新的一波数据,但是?拿数据的在哪里呢?网络请求呢?在哪里??
  5. 我们看Presenter里面做的操作吧:
    package mvpmaster.lht.com.lht.ui.fragment.zhuhu;
    
    import mvpmaster.lht.com.lht.base.BasePresenter;
    import mvpmaster.lht.com.lht.conf.OkHttpCallBack;
    import mvpmaster.lht.com.lht.ui.beanIml.NewsTimeLine;
    
    /**
     * Created by Ly on 2016/11/2.
     */
    
    public class ZhiHuPresenter extends BasePresenter<ZhiHuContract.ZhiHuView> implements ZhiHuContract.ZhiHuPresenter {
        private ZhiHuContract.ZhiHuView zhiHuView;
        private ZhiHuContract.ZhiHuModel zhiHuModel;
    
        public ZhiHuPresenter(ZhiHuContract.ZhiHuView zhiHuView) {
            this.zhiHuView = zhiHuView;
            zhiHuModel = new ZhiHuModel();
        }
    
    
        @Override
        public void getDataList() {
            zhiHuModel.getDataList(new OkHttpCallBack<NewsTimeLine>() {
                @Override
                public void onSuccess(NewsTimeLine newsTimeLine) {
                    zhiHuView.loadFinishAndReset(newsTimeLine, newsTimeLine.getDate());
                }
    
                @Override
                public void onFaild(Throwable e) {
                    loadError(e);
                    zhiHuView.loadFailure();
                }
    
                @Override
                public void onFinish() {
    
                }
            });
        }
    
        @Override
        public void getBeforeDateList(String time) {
            zhiHuModel.getBeforeDateList(time, new OkHttpCallBack<NewsTimeLine>() {
                @Override
                public void onSuccess(NewsTimeLine newsTimeLine) {
                    zhiHuView.loadFinishAndAdd(newsTimeLine, newsTimeLine.getDate());
                }
    
                @Override
                public void onFaild(Throwable e) {
                    loadError(e);
                    zhiHuView.loadFailure();
                }
    
                @Override
                public void onFinish() {
    
                }
            });
        }
    
        private void loadError(Throwable throwable) {
            throwable.printStackTrace();
            zhiHuView.TsShow(throwable.getMessage());
        }
    }
    
    我们看到有三个ovver的方法,分别是刷新(第一次读取),加载,读取失败 三种情况:我们可以看到,这个类持有了View和Model两个模块,在方法体里面,我们调用了model的方法去做耗时,在结果方法体里面我们调用了view的方法去修改UI,同时presenter这个模块又被view持有了,view可以在声明周期里面去调用特定的方法,view和presenter相互沟通,view和model完全隔离,presenter调控model,presenter沟通全局。
补上我的git地址:https://github.com/LinHuanTanLy/mvpMaster
补上另外一个请求框架:https://github.com/LinHuanTanLy/OkHttpWithSession

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值