編輯:關於Android編程
因為要讓別人看得懂我們的代碼,使代碼更利於維護,簡單講就是模塊化,使各個包下的類各在其位,各司其職。比如怎樣請求數據和它被用來干什麼是沒有關系的,所以要分離,這樣做的好處是:一,大量減少了UI層業務邏輯的代碼量。二,即使UI界面變了,也不會影響到業務層的代碼。使兩者充分解耦,也就達到了我們的目的了。
下圖是我理解的MVP的職責圖示:

對於它的解釋是 model把封裝好的數據通過接口回調給Presenter ,View 負責UI層例如Dialog,Empty data, no network,Datas done的顯示,讓Presenter持有View的引用,當model和view在presenter中匯合時,再由presenter去決定View 顯示的時機,也就是presenter的調度。這樣,model無需關心數據的流向,view不用關系數據的來源,activity也不用處理兩者之間的復雜關系,只需要在需要的地方設置“Adapter”就行了,更多的事交給Presenter去處理。
光說不練假把式,來嘗試一個簡單的功能
下面是一個采用MVP模式設計的功能非常的APP的效果圖,就是從網絡獲取一段字符串,在開始獲取的時候Toast:開始加載數據,在成功獲取到數據後,直接顯示到ListView,怎麼樣,簡單得不能再簡單了!

根據上面的內容,在寫代碼前,要先‘’分清職責‘’
首先,Model負責訪問數據接口,並把數據回調給Presenter 所以IHomeListLoad肯定會有loadData()這個方法去加載數據。所以它的代碼應該是這樣的
public interface IHomeListLoad { //加載數據 void loadData(Context context,ILoadDataComplete iLoadDataComplete); //數據加載後的回調 interface ILoadDataComplete{ void dataComing(List datas); void dataError(Exception e); void onStart(); } }
在這裡我做了兩件事,一是加載數據,二是預制了ILoadDataComlete數據回調接口方便獲取數據。現在我不僅獲取了數據,並且還知道數據是什麼時候開始加載的,什麼時候結束的,加載是否出錯。。
public interface IMainView { void showLoading(); void loadFinish(List datas); void loadError(Exception e); }
前面的Model雖然把數據請求下來了,但是它並不知道該把數據交給誰,因為它只負責去請求數據。View也並不知道該什麼時候去呈現各種定義好的視圖效果。這時候Presenter出場了,通通交給它去調度,如圖所示是它的一般調度關系。
這就是我們所說的中間層的作用,它帶來好處是即使model和view發生變化,只要他們的調度關系還在,我就不會去改寫presenter的代碼,使其充分解耦。要知道,presenter可占了很大一部分代碼量O(∩_∩)O~。
讓我們來實現它
前面都是通過接口編寫了抽象方法,想好了操作步驟,接下來就去編寫它的實現類,但在這之前我們必須做一些准備工作,以提高代碼的復用性
一、封裝統一的HTTP RESOULT類 BaseHttpResponse
public class BaseHttpResponse{ private String error_code; private String reason; private T result;//不確定的數據類型 public String getError_code() { return error_code; } public void setError_code(String error_code) { this.error_code = error_code; } public String getReason() { return reason; } public void setReason(String reason) { this.reason = reason; } public T getResult() { return result; } public void setResult(T result) { this.result = result; } }
二、繼承RXJAVA中Func1()類,並重寫Call()方法增加,對返回的數據重新整理。在BaseHttpResponse中,我們真正關心的數據只有當error_code=0時result的數據(這裡我規定error_code=0時,且result不為null表示獲取成功),所以如果我們不進行預處理的話使用RXJAVA時的map函數將是這樣處理數據的
.map(new Func1>, List >() { @Override public List call(BaseHttpResponse > baseHttpResponse) { if("0".equals(baseHttpResponse.getError_code())) { if(baseHttpResponse.getResult() != null) { return baseHttpResponse.getResult(); } else { //自定義異常類 throw new DataResponseException("數據為空");//DataResponseException } } else { throw new DataResponseException("請求發生錯誤"); } } })
(PS:此過程中拋出的異常是會回調到OnError函數中的,源碼中的注釋是@parame the exception encountered by the Observable)實在太麻煩,所以干脆重寫一下Func1()的方法算了!
public class BetterFuncimplements Func1 ,T> { @Override public T call(BaseHttpResponse tBaseHttpResponse) { String error_code = tBaseHttpResponse.getError_code(); String reason = tBaseHttpResponse.getReason(); T result = tBaseHttpResponse.getResult(); if("0".equals(error_code)){ if(result !=null){ return result; }else { throw new DataResponseException("數據為空"); } } else { throw new DataResponseException(reason); } } }
.map(new BetterFunc我靠( ‵o′)凸,簡直不要太嗨!准備工作完成了接下來是真正的實現類>())
①Model implement
public class IHomeListLoadIml implements IHomeListLoad {
@Override
public void loadData(Context context, final ILoadDataComplete iLoadDataComplete) {
RetrofitUtils.createApi(context, AnswerService.class)
.getData("CN", "7568f1905fde469e90009614e8c167b0")
.subscribeOn(Schedulers.io())
.map(new BertterFunc>())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber>() {
@Override
public void onCompleted() {}
@Override
public void onStart() {
super.onStart();
iLoadDataComplete.onStart();
}
@Override
public void onError(Throwable e) {
iLoadDataComplete.dataError((Exception) e);
}
@Override
public void onNext(List xxxes) {
iLoadDataComplete.dataComing(xxxes);
}
});
}
}
②Viewimplement(肯定是Activity啊)
public class MainActivity extends AppCompatActivity implements IMainView {
private ListView mListView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView= (ListView) findViewById(R.id.mList);
//IMainView ---》presenter
MainPresenter presenter = new MainPresenter(this,this);
presenter.getData();
}
@Override
public void showLoading() {
Toast.makeText(this,"開始加載數據",Toast.LENGTH_LONG).show();
}
@Override
public void loadFinish(List datas) {
mListView.setAdapter(new HomeListAdapter(this,datas));
}
@Override
public void loadError(Exception e) {
Toast.makeText(this,"數據加載出錯",Toast.LENGTH_LONG).show();
}
}
public class MainPresenter {
private IMainView iMainView;
private Context context;
private IHomeListLoad iHomeListLoad = new IHomeListLoadIml();
public MainPresenter(Context context,IMainView iMainView) {
this.iMainView = iMainView;
this.context = context;
}
//請求數據
public void getData(){
iHomeListLoad.loadData(context,new IHomeListLoad.ILoadDataComplete() {
@Override
public void dataComing(List datas) {
//datas--->activity
iMainView.loadFinish(datas);
}
@Override
public void dataError(Exception e) {
//view --->error
iMainView.loadError(e);
}
@Override
public void onStart() {
//view --->dialog
iMainView.showLoading();
}
});
}
}
哦,對了本文涉及到RXJAVA和Retrofit的用法也會抽時間整理一下留作筆記,代碼等我完善後也將隨後上傳至GITHUB並補上鏈接。個人能力受限,還請各位前輩不吝賜教!完
Android應用經典主界面框架之二:仿網易新聞客戶端、CSDN 客戶端 (Fragment ViewPager)
第二種主界面風格則是以網易新聞、鳳凰新聞以及新推出的新浪博客(閱讀版)為代表,使用ViewPager+Fragment,即ViewPager裡適配器裡放的不是一般的Vie
Android消息提示類viewbadger
Android消息提示類viewbadger ,效果如下: 代碼如下 BadgeView.java import android.content.Context
Android 服務(service)的生命周期以及利用bindservice調用服務裡面的方法
服務的生命周期 服務的生命周期跟啟動服務的方法有關: 當采用Context.startService()方法啟動服務,與之有關的生命周期方法 onCreate()
Android移動APP開發筆記——Cordova(PhoneGap)通過CordovaPlugin插件調用 Activity 實例
引言 Cordova(PhoneGap)采用的是HTML5+JavaScript混合模式來開發移動手機APP,因此當頁面需要獲取手機內部某些信息時(例如:聯系人信息,坐