离职在即,也没什么事情做,就鼓捣了一下,随意搭建了一个小框架,看看以后能不能搞出自己的一个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请求模块
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的保持,在某些公司的后台并不能支持这样的请求库,我稍候会上传一个更新后的版本
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(); }
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); }
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,我就不一一上传了。
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次,第一次是刚进去页面的时候,第一次读取数据,第二个是下拉加载的时候,读取了下一波的数据,再有一次是上拉刷新的时候,我们重新刷新了一次页面拿取了最新的一波数据,但是?拿数据的在哪里呢?网络请求呢?在哪里??
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沟通全局。