摘要:數(shù)據(jù)模型,提供數(shù)據(jù)視圖模型,提供視圖展示控制器,負(fù)責(zé)控制和通信在中的應(yīng)用,如下圖,為,為,請求網(wǎng)絡(luò)數(shù)據(jù)模塊為。箭頭指向意為傳遞數(shù)據(jù),那就是獲取的數(shù)據(jù)傳遞給來請求網(wǎng)絡(luò),請求到的數(shù)據(jù)直接傳遞給來顯示,這是一條主線。
MVC由Model、View、Control組成。
Model數(shù)據(jù)模型,提供數(shù)據(jù)
View視圖模型,提供視圖展示
Control控制器,負(fù)責(zé)控制Model和View通信
MVC在Android中的應(yīng)用,如下圖,Activity為Control,XML為View,請求網(wǎng)絡(luò)數(shù)據(jù)模塊為Model。View箭頭指向Control意為傳遞數(shù)據(jù),那就是Control獲取View的數(shù)據(jù)傳遞給Model來請求網(wǎng)絡(luò),請求到的數(shù)據(jù)直接傳遞給View來顯示,這是一條主線。還有一條就是底部這兩個箭頭,也就是說Model可以不通過Control,直接獲取View的數(shù)據(jù),然后再返回結(jié)果數(shù)據(jù)給View。
MVP由Model、View、Presenter組成。
Model數(shù)據(jù)模型,提供數(shù)據(jù)
View視圖模型,提供視圖展示
Presenter主持者,負(fù)責(zé)邏輯處理
MVP與MVC最明顯的區(qū)別就在于Presenter和Control了。如下圖,Presenter傳遞數(shù)據(jù)給Model,Model得到數(shù)據(jù)來請求網(wǎng)絡(luò),再返回數(shù)據(jù)給Presenter,Presenter再把得到的Model數(shù)據(jù)傳遞給View顯示。MVP整體的一個流程就是這樣。相比MVC來說,Model和View互相不干涉,達(dá)到完全解耦
估計上面文字性的解釋都聽得有點暈,那我們就拿個例子來實戰(zhàn)一下吧
配置環(huán)境下面和大家一起完成一個簡單查詢快遞信息的例子,里面用到了當(dāng)下最流行的架構(gòu)RxJava+Retrofit+MVP+OkHttp,非常值得大家一學(xué)
在builde.gradle里面添加
compile "com.android.support:appcompat-v7:23.3.0" compile "com.squareup.retrofit2:retrofit:2.1.0" compile "com.squareup.retrofit2:adapter-rxjava:2.1.0" compile "com.squareup.retrofit2:converter-gson:2.1.0" compile "com.squareup.okhttp3:okhttp:3.4.1" compile "io.reactivex:rxandroid:1.2.1" compile "io.reactivex:rxjava:1.1.6" compile "com.squareup.okhttp3:logging-interceptor:3.4.1"
在AndroidManifest.xml添加所需權(quán)限
初始化配置Retrofit
public class MainApp extends Application { @Override public void onCreate() { super.onCreate(); //初始化retrofitUtils RetrofitUtils.getInstance().initOkHttp(this); } }
在MainApp中初始化Retrofit,設(shè)置超時和baseUrl,添加了日志攔截以及RxJava和數(shù)據(jù)解析,并暴露一個getRetrofit()方法供需要的地方調(diào)用
public class RetrofitUtils { private Retrofit retrofit; private String baseUrl = "http://www.kuaidi100.com/"; private static class SingleLoader{ private static final RetrofitUtils INSTANCE = new RetrofitUtils(); } public static RetrofitUtils getInstance(){ return SingleLoader.INSTANCE; } public void initOkHttp(@NonNull Context context){ HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(); interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); OkHttpClient client = new OkHttpClient.Builder() .connectTimeout(10000L,TimeUnit.MILLISECONDS) //設(shè)置連接超時 .readTimeout(10000L,TimeUnit.MILLISECONDS) //設(shè)置讀取超時 .writeTimeout(10000L, TimeUnit.MILLISECONDS) //設(shè)置寫入超時 .cache(new Cache(context.getCacheDir(),10 * 1024 * 1024)) //設(shè)置緩存目錄和10M緩存 .addInterceptor(interceptor) //添加日志攔截器(該方法也可以設(shè)置公共參數(shù),頭信息) .build(); retrofit = new Retrofit.Builder() .client(client) //設(shè)置OkHttp .baseUrl(baseUrl) .addConverterFactory(GsonConverterFactory.create()) // 添加數(shù)據(jù)解析ConverterFactory .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) //添加RxJava .build(); } public Retrofit getRetrofit(){ return retrofit; } }Model
public interface PostSearchModel { /** * 請求快遞信息 * @param type 快遞類型 * @param postid 快遞單號 * @param callback 結(jié)果回調(diào) */ void requestPostSearch(String type,String postid,PostSearchCallback callback); interface PostSearchCallback{ void requestPostSearchSuccess(PostQueryInfo postQueryInfo); void requestPostSearchFail(String failStr); } }
創(chuàng)建這個PostSearchModel接口,方便后期可以不修改之前代碼靈活切換多種實現(xiàn)方式
public interface PostServiceBiz { @POST("query") ObservablesearchRx(@Query("type") String type, @Query("postid") String postid); }
public class PostQueryInfo { private String message; private String nu; private String ischeck; private String com; private String status; private String condition; private String state; private Listdata; public static class DataBean { private String time; private String context; private String ftime; } }
PostQueryInfo沒有添加get和set方法,大家自行快捷鍵了
PostSearchModelImpl實現(xiàn)上面PostSearchModel接口,利用上一篇文章里學(xué)的Retrofit結(jié)合RxJava來請求網(wǎng)絡(luò)
這里傳了PostSearchCallback回調(diào)函數(shù),成功或者失敗都通過回調(diào)函數(shù)返回,完全不需要考慮其它
public class PostSearchModelImpl implements PostSearchModel { @Override public void requestPostSearch(String type, String postid, final PostSearchCallback callback) { RetrofitUtils.getInstance() .getRetrofit() .create(PostServiceBiz.class) .searchRx(type,postid) //訪問網(wǎng)絡(luò)切換異步線程 .subscribeOn(Schedulers.io()) //響應(yīng)結(jié)果處理切換成主線程 .observeOn(AndroidSchedulers.mainThread()) .subscribe(new SubscriberView() { @Override public void onCompleted() { //請求結(jié)束回調(diào) } @Override public void onError(Throwable e) { //錯誤回調(diào) callback.requestPostSearchFail(e.getMessage()); } @Override public void onNext(PostQueryInfo postQueryInfo) { //成功結(jié)果返回 callback.requestPostSearchSuccess(postQueryInfo); } }); } }
activity_main.xml主界面布局
view_item_logistics.xml
listview適配器的item布局
ListView適配器
public class LogisticsAdapter extends BaseAdapter { private Listdatas; private LayoutInflater inflater; public LogisticsAdapter(Context context, List datas) { this.datas = datas; inflater = LayoutInflater.from(context); } @Override public View getView(int i, View view, ViewGroup viewGroup) { PostQueryInfo.DataBean data = datas.get(i); view = inflater.inflate(R.layout.view_item_logistics, null); TextView tv_content= (TextView) view.findViewById(R.id.tv_conent); TextView tv_date= (TextView) view.findViewById(R.id.tv_date); tv_content.setText(data.getContext().replace("[","【").replace("]","】")); tv_date.setText(data.getTime()); return view; } @Override public int getCount() { return datas != null ? datas.size() : 0; } @Override public Object getItem(int i) { return datas.get(i); } @Override public long getItemId(int i) { return i; } }
BaseView提供通用顯示和隱藏加載框,如果有通用的方法都可以在寫在這里面
public interface BaseView { void showProgressDialog(); void hideProgressDialog(); }
MainView接口繼承提供MainActivity所有需要更新界面UI的方法
public interface MainView extends BaseView{ void updateListUI(PostQueryInfo postQueryInfo); void errorToast(String message); }
BaseActivity實現(xiàn)BaseVew所有接口方法
public class BaseActivity extends Activity implements BaseView{ private ProgressDialog progressDialog; @Override protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); progressDialog = new ProgressDialog(this); progressDialog.setMessage("查詢中..."); } @Override public void showProgressDialog(){ if(progressDialog!=null){ progressDialog.show(); } } @Override public void hideProgressDialog(){ if(progressDialog!=null&&progressDialog.isShowing()){ progressDialog.dismiss(); } } }
MainActivity繼承BaseActivity實現(xiàn)MainView所有方法供PostPresenter調(diào)用,點擊查詢按鈕通過實例化的PostPresenter,調(diào)用相關(guān)方法,后面的事情就全部交給PostPresenter去處理了,在activity銷毀的時候調(diào)用postPresenter.detach()防止內(nèi)存泄漏
public class MainActivity extends BaseActivity implements View.OnClickListener, MainView { private EditText post_name_et; private EditText post_id_et; private ListView post_list_lv; private Button post_search_bn; private PostPresenter postPresenter; private ListPresenterdataArray = new ArrayList<>(); private LogisticsAdapter logisticsAdapter; @Override protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); initData(); initEvent(); } private void initView() { post_name_et = (EditText) findViewById(R.id.post_name_et); post_id_et = (EditText) findViewById(R.id.post_id_et); post_list_lv = (ListView) findViewById(R.id.post_list_lv); post_search_bn = (Button) findViewById(R.id.post_search_bn); } private void initData() { logisticsAdapter = new LogisticsAdapter(getApplicationContext(),dataArray); postPresenter = new PostPresenter(this); post_list_lv.setAdapter(logisticsAdapter); } private void initEvent() { post_search_bn.setOnClickListener(this); } @Override public void onClick(View v) { switch(v.getId()){ case R.id.post_search_bn: postPresenter.requestHomeData(post_name_et.getText().toString(),post_id_et.getText().toString()); break; } } @Override public void updateListUI(PostQueryInfo postQueryInfo) { dataArray.clear(); dataArray.addAll(postQueryInfo.getData()); logisticsAdapter.notifyDataSetChanged(); } @Override public void errorToast(String message) { Toast.makeText(getApplicationContext(),message,Toast.LENGTH_LONG).show(); } @Override protected void onDestroy(){ //防止activity銷毀,postPresenter對象還存在造成的內(nèi)存泄漏 if(postPresenter!=null) postPresenter.detach(); super.onDestroy(); } }
BasePresenter基類,提供了一個通用view對象,以及初始化和銷毀view對象的方法
public abstract class BasePresenter{ public T mView; public void attach(T view){ this.mView = view; } public void detach(){ mView = null; } }
PostPresenter在構(gòu)造函數(shù)中通過基類attach的方法初始化MainActivity提供的view對象,實例化PostSearchModelImpl對象,通過它提供的方法來請求網(wǎng)絡(luò)數(shù)據(jù),在成功和失敗回調(diào)的函數(shù)里,可以做一些邏輯處理,通過view對象更新相應(yīng)的UI
public class PostPresenter extends BasePresenter{ private PostSearchModel postSearchModel; public PostPresenter(MainView mainView){ attach(mainView); postSearchModel = new PostSearchModelImpl(); } public void requestHomeData(String type,String postid){ if(postSearchModel == null||mView == null) return; mView.showProgressDialog(); postSearchModel.requestPostSearch(type, postid, new PostSearchModel.PostSearchCallback() { @Override public void requestPostSearchSuccess(PostQueryInfo postQueryInfo) { mView.hideProgressDialog(); if(postQueryInfo!=null&&"ok".equals(postQueryInfo.getMessage())) { mView.updateListUI(postQueryInfo); } } @Override public void requestPostSearchFail(String failStr) { mView.hideProgressDialog(); mView.errorToast(failStr); } }); } }
到這里全部代碼基本都已編寫完,代碼的結(jié)構(gòu)如下圖:
下面就運行程序看看效果吧,快遞公司名和快遞單號默認(rèn)填寫上去了,大家只需要點擊查詢,結(jié)果和下面圖片一樣就說明成功了
為什么沒有直接提供一個可以運行的DEMO出來,原因很簡單就是希望大家能夠跟著一步一步學(xué)習(xí),然后動手慢慢邊敲代碼邊理解,最后敲完運行成功,應(yīng)該就會更加理解MVP了。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/70565.html
摘要:音樂團(tuán)隊分享數(shù)據(jù)綁定運行機(jī)制分析一個項目搞定所有主流架構(gòu)單元測試一個項目搞定所有主流架構(gòu)系列的第二個項目。代碼開源,展示了的用法,以及如何使用進(jìn)行測試,還有用框架對的進(jìn)行單元測試。 Android 常用三方框架的學(xué)習(xí) Android 常用三方框架的學(xué)習(xí) likfe/eventbus3-intellij-plugin AS 最新可用 eventbus3 插件,歡迎品嘗 簡單的 MVP 模...
閱讀 2205·2021-10-13 09:39
閱讀 3408·2021-09-30 09:52
閱讀 800·2021-09-26 09:55
閱讀 2775·2019-08-30 13:19
閱讀 1888·2019-08-26 10:42
閱讀 3185·2019-08-26 10:17
閱讀 543·2019-08-23 14:52
閱讀 3631·2019-08-23 14:39