Google 官方Android MVP架構實踐
一、Google 官方MVP介紹
近期,關於Android開發架構的討論沸沸揚揚,各大技術平臺隨處可見關於Android架構的技術文章。MVC、MVP、MVVM等等,就目前的形式來看,MVP模式在Android開發領域界逐漸流行了起來。前段時間,Google也忍耐不住Android MVP架構的火熱程度,給廣大Android程式設計師帶來了福利,推出了Google官方MVP架構例子。原始碼見: https://github.com/googlesamples/android-architecture
官方給出了四種MVP架構模式:
1、todo-mvp:MVP基礎架構
2、todo-mvp-loaders:基於MVP基礎架構,獲取資料部分使用了Loaders架構
3、todo-mvp-databinding:基於MVP基礎架構,使用了資料繫結元件
4、todo-mvp-clean:基於MVP基礎架構,引入Clean架構概念
官方正在進行的MVP架構模式:
1、todo-mvp-contentproviders:基於MVP基礎架構,使用了Content Provider
2、todo-mvp-dragger:基於MVP基礎架構,使用dragger2依賴注入
3、todo-mvp-rxjava:基於MVP基礎架構,使用RxJava解決資料併發
二、MVP架構模式介紹
MVP中的M代表Model,即資料層,V代表View,即介面層,P代表Presenter,負責關聯Model和View,把Model層的資料顯示到View。
三、MVP架構實踐
這裡,我從todo-mvp基礎架構入手,模仿一下官方MVP原始碼,跟大家詳細介紹一下Google官方MVP架構模式。官方的MVP示例原始碼展示的是一個簡易便籤,資料提供者是Sqlite資料庫。我的專案裡面資料提供者是網路,使用okhttp網路請求框架從伺服器獲取資料。一起來看看神奇的MVP架構模式是怎樣把資料顯示到手機介面的吧。
google官方todo-mvp模式架構圖(結合todo-mvp原始碼可以好好感受一下mvp的魅力)
Presente基礎介面
public interface BasePresenter {
void start();
}
View基礎介面public interface BaseView<T> { void setPresenter(T presenter); }
具體任務的Presener和View介面,Presenter接口裡面封裝的是資料獲取的方法,需要資料提供者具體實現;View裡面封裝的方法是介面層(Fragment/Activity)要實現的方法。
public interface GankContract {
interface Presenter extends BasePresenter{
void loadGank(int pageIndex, int pageSize);
}
interface View extends BaseView<Presenter>{
void showProgress();
void hideProgress();
void showGank(List<Gank> gankList);
}
}
資料提供者,基於Okhttp請求,我這裡使用的鴻洋大神封裝好的Okhttp請求庫。提供一個介面,將資料共享出去,提供給具體Presenter。
資料提供的伺服器是我自己搭建的一個阿里雲伺服器,為了平時開發方便,寫了一個數據介面,可以獲取大量的美女圖片和文字資訊,get和post請求都支援,便於開發時候做資料測試。資料介面地址: http://gank.io/api/data/%E7%A6%8F%E5%88%A9/10/3 感謝乾貨提供。
public class ServerHelper {
private DataLoadListener listener;
public void getGankList(int pageSize, int pageIndex){
String url = "http://gank.io/api/data/%E7%A6%8F%E5%88%A9/" + pageSize + "/" + pageIndex;
Log.i("test", url);
OkHttpUtils.get().url(url).build().execute(new GankResponseCallBack() {
@Override
public void onError(Call call, Exception e) {
listener.failure(e);
Log.i("test", "errorerror");
}
@Override
public void onResponse(List<Gank> response) {
Log.i("test", "資料獲取成功 " + new Gson().toJson(response, List.class));
listener.success(response);
}
});
}
public interface DataLoadListener{
void failure(Exception e);
void success(List<Gank> gankList);
}
public void setListener(DataLoadListener listener) {
this.listener = listener;
}
}
具體Presenter,實現了GankContract.Presenter和ServerHelper.DataLoadListener介面,關聯了GankContract.View介面,把網路請求到的資料提供給View。
public class GankPresenter implements GankContract.Presenter,ServerHelper.DataLoadListener {
private GankContract.View view;
private ServerHelper serverHelper;
//資料提供者 這裡應該封裝網路資料請求
public GankPresenter(GankContract.View view) {
this.view = view;
view.setPresenter(this);
serverHelper = new ServerHelper();
serverHelper.setListener(this);
}
@Override
public void start() {
}
@Override
public void failure(Exception e) {
view.hideProgress();
}
@Override
public void success(List<Gank> gankList) {
view.hideProgress();
view.showGank(gankList);
}
@Override
public void loadGank(int pageIndex, int pageSize) {
serverHelper.getGankList(pageIndex, pageSize);
}
}
具體的View,這裡的BeautyFragment實現了GankContract.View,使用GankContract.Presenter進行資料請求,View如果接受到資料,則對資料進行介面展示操作。這樣保證了介面層只負責資料的顯示,減少了介面層的資料邏輯處理,使得介面更加流暢。
public class GankFragment extends Fragment implements GankContract.View, SwipeRefreshLayout.OnRefreshListener {
private GankContract.Presenter presenter;
private SwipeRefreshLayout refreshLayout;
private RecyclerView recyclerView;
private GankAdapter adapter;
private List<Gank> gankList;
private int pageIndex = 1;
private int pageSize = 10;
private boolean isLastPage = false;
private int lastVisibleItem = 0;
private LinearLayoutManager linearLayoutManager;
public static GankFragment newInstance(){
return new GankFragment();
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
gankList = new ArrayList<>();
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_beauty,container,false);
recyclerView = (RecyclerView) view.findViewById(R.id.tabRecyler);
refreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.tabSwipeRefresh);
linearLayoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL,false);
//設定下拉重新整理
refreshLayout.setColorSchemeColors(R.color.colorAccent);
refreshLayout.setOnRefreshListener(this);
//第一次進入介面時候載入進度條
refreshLayout.setProgressViewOffset(false, 0, (int) TypedValue
.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 24, getResources()
.getDisplayMetrics()));
recyclerView.setLayoutManager(linearLayoutManager);
adapter = new GankAdapter(gankList,getActivity());
recyclerView.setAdapter(adapter);
Log.i("test", "11111");
presenter.loadGank(pageSize,pageIndex);
recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
}
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE
&& lastVisibleItem + 1 == adapter.getItemCount()) {
Log.i("pageIndex",pageIndex+"");
//根據類目網路請求資料
Log.e("test", "最後一頁" + isLastPage);
if(!isLastPage){
presenter.loadGank(pageSize,pageIndex);
}
}
}
});
return view;
}
@Override
public void showProgress() {
refreshLayout.setRefreshing(true);
}
@Override
public void hideProgress() {
refreshLayout.setRefreshing(false);
}
@Override
public void showGank(List<Gank> list) {
if (list != null) {
if (pageIndex == 1) {
gankList.clear();
gankList.addAll(list);
isLastPage = false;
pageIndex++;
} else if (list.size() == pageSize) {
gankList.addAll(list);
isLastPage = false;
pageIndex++;
} else {
gankList.addAll(list);
isLastPage = true;
}
}
adapter.notifyDataSetChanged();
}
@Override
public void setPresenter(GankContract.Presenter presenter) {
this.presenter = presenter;
}
@Override
public void onRefresh() {
pageIndex = 1;
presenter.loadGank(pageSize,pageIndex);
}
}
public class GankActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_beauty);
GankFragment fragment = GankFragment.newInstance();
ActivityUtils.addFragmentToActivity(getSupportFragmentManager(),fragment,R.id.container);
//設定presenter
new GankPresenter(fragment);
}
}
好了,Google 官方MVP架構實踐介紹完畢,希望對大家有收穫。上述程式碼是實現MVP架構模式的關鍵程式碼,中間還涉及到的ActivityUtils等類都在原始碼中哦,歡迎大家下載。