zoukankan      html  css  js  c++  java
  • 一个小框架,基于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

  • 相关阅读:
    【转贴】判断sql server表是否存在的方法
    SQL SERVER 中将重复记录合并为一条记录
    数据清洗:将字段值全部为数字的记录置空
    【转贴】PLSQL不安装客户端连接远程oracle
    Datalength() 与 Len()的区别
    SQL SERVER 查询重复的记录的方法
    连接mysql利用jsp实现简单的登陆操作
    jsp包含文件的两种方法
    preparedStatment的用法
    request内置对象介绍和使用
  • 原文地址:https://www.cnblogs.com/mfmdaoyou/p/7366871.html
Copyright © 2011-2022 走看看