離職在即,也沒什麼事情作,就鼓搗了一下。任意搭建了一個小框架,看看之後能不能搞出本身的一個model,好了。不說別的,上代碼html
1,先上依賴庫java
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。 依賴retrolambdareact
在app.build依賴android
apply plugin: 'me.tatarka.retrolambda'
compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 }
而後在項目的app.build依賴git
classpath 'me.tatarka:gradle-retrolambda:3.2.5'OK,到這裏咱們的環境搭建就完畢了
3。搭建Http請求模塊github
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的泛型裏面的那個
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溝通全局。