柚子快报激活码778899分享:一个小框架,基于rx
离职在即,也没什么事情做,就鼓捣了一下。任意搭建了一个小框架,看看以后能不能搞出自己的一个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请求模块
搭建工具类RetrofitUtilspackage 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的保持,在某些公司的后台并不能支持这种请求库,我稍候会上传一个更新后的版本号这里写上我的一个interface(为什么我用了rx还要有callback???黑人问号脸)package mvpmaster.lht.com.lht.conf;
/**
* Created by Ly on 2016/10/13.
*/
public interface OkHttpCallBack
void onSuccess(T t);//成功的回调
void onFaild(Throwable e);//失败的回调
void onFinish();
}
然后是一些比較通用的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
@GET("news/before/{time}")
Observable
@GET("news/{id}")
Observable
// for daily
@GET("homes/index/{num}.json")
Observable
}
4,网络请求搭建完了。重头戏来了,我们来搭建mvp的基本框架
我们的baseActivitypackage 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
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
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,我就不一一上传了。说一下我理解的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了)我们举一个样例,首页那里拿取了知乎的信息,用了一个recyclerview去显示拿到的数据。我们就用它来讲,我先上传一波项目文件夹,不然太懵逼了。我们先看我们的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
@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次。第一次是刚进去页面的时候,第一次读取数据。第二个是下拉载入的时候,读取了下一波的数据。再有一次是上拉刷新的时候。我们又一次刷新了一次页面拿取了最新的一波数据,可是?拿数据的在哪里呢?网络请求呢?在哪里??我们看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
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
@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
@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
柚子快报激活码778899分享:一个小框架,基于rx
发表评论