柚子快报激活码778899分享:一个小框架,基于rx

http://www.51969.com/

离职在即,也没什么事情做,就鼓捣了一下。任意搭建了一个小框架,看看以后能不能搞出自己的一个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 getZhiHuList();

@GET("news/before/{time}")

Observable getBeforetNews(@Path("time") String time);

@GET("news/{id}")

Observable getDetailNews(@Path("id") String id);

// for daily

@GET("homes/index/{num}.json")

Observable getDailyTimeLine(@Path("num") String num);

}

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> 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> 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,我就不一一上传了。说一下我理解的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 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次。第一次是刚进去页面的时候,第一次读取数据。第二个是下拉载入的时候,读取了下一波的数据。再有一次是上拉刷新的时候。我们又一次刷新了一次页面拿取了最新的一波数据,可是?拿数据的在哪里呢?网络请求呢?在哪里??我们看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 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() {

@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

http://www.51969.com/

查看原文