編輯:關於Android編程
??在Android項目中,Activity和Fragment占據了大部分的開發工作。而MVP設計模式可以優化Activity和Fragment的代碼。
??相信很多人閱讀代碼的時候,都是從Activity開始的,對著一個1000+行代碼的Activity,看了都覺得難受。
??使用MVP之後,Activity就能瘦身許多了,基本上只有FindView、SetListener以及Init的代碼。其他的就是對Presenter的調用,還有對View接口的實現。這種情形下閱讀代碼就容易多了,而且你只要看Presenter的接口,就能明白這個模塊都有哪些業務,很快就能定位到具體代碼。Activity變得容易看懂,容易維護,以後要調整業務、刪減功能也就變得簡單許多。
MVP模式優點:
分離了視圖邏輯和業務邏輯,降低了耦合 Activity只處理生命周期的任務,代碼變得更加簡潔 視圖邏輯和業務邏輯分別抽象到了View和Presenter的接口中去,提高代碼的可閱讀性 Presenter被抽象成接口,可以有多種具體的實現,所以方便進行單元測試 把業務邏輯抽到Presenter中去,避免後台線程引用著Activity導致Activity的資源無法被系統回收從而引起內存洩露和OOMvcq9tcS8r7rPoaM8YnIgLz4NClByZXNlbnRlciC4utTwzeqzyVZpZXfT2k1vZGVsvOS1xL27u6WhozwvcD4NCjxwPk1WULvhveKz/VZpZXe6zU1vZGVstcTx7rrPo6zNrMqx09a0+MC0wcvBvLrDtcS/ycCp1bnQ1KGiv8my4srU0NSjrLGj1qTBy8+1zbO1xNX7veDQ1LrNwem77tDUoaM8L3A+DQo8cD5NVlC/ydLUt9bA68/Uyr6y47rNwt+8rbLjo6zL+8PH1q685M2ouf2907/avfjQ0M2o0MWjrLz1tc3x7rrPoaPA7c/ru6+1xE1WUMSjyr2/ydLUyrXP1s2s0ru33cLfvK20+sLrtO7F5LK7zay1xM/Uyr6958Pmo6zS8s6qy/vDx9auvOSyorK70sDAtb7fzOWjrLb4ysfSwMC109qz6c/zoaPV4sq5tcNQcmVzZW50ZXK/ydLU1MvTw9PayM66zsq1z9bBy1ZpZXfC37ytvdO/2rXEVUmjrMq51q6+39PQuPy547e6tcTKytPD0NSjrLGj1qTBy8Hpu+7Q1KGjPC9wPg0KPGgyIGlkPQ=="3mvp與mvc的區別">3.MVP與MVC的區別
??其實最明顯的區別就是,MVC中是允許Model和View進行交互的,而MVP中很明顯,Model與View之間的交互由Presenter完成。還有一點就是Presenter與View之間的交互是通過接口的(代碼中會體現)。
方案1:MVP把Activity中的UI邏輯抽象成View接口,把業務邏輯抽象成Presenter接口,Model類還是原來的Model。這就是MVP模式,現在這樣的話,Activity的工作的簡單了,只用來響應生命周期,其他工作都丟到Presenter中去完成。
方案2:Activity作為Presenter,也有這種方案,不常見,也不易理解,這裡不講解。以下代碼也主要以方案1為主。
public class WeatherEntity {
/**
* error : 0
* status : success
* date : 2016-07-18
* results : [{"currentCity":"花都","pm25":"","index":[{"title":"穿衣","zs":"炎熱","tipt":"穿衣指數","des":"天氣炎熱,建議著短衫、短裙、短褲、薄型T恤衫等清涼夏季服裝。"},{"title":"洗車","zs":"較適宜","tipt":"洗車指數","des":"較適宜洗車,未來一天無雨,風力較小,擦洗一新的汽車至少能保持一天。"},{"title":"旅游","zs":"一般","tipt":"旅游指數","des":"天氣較好,同時有微風相伴,但溫度較高,天氣熱,請盡量避免高溫時段外出,若外出請注意防暑降溫和防曬。"},{"title":"感冒","zs":"少發","tipt":"感冒指數","des":"各項氣象條件適宜,發生感冒機率較低。但請避免長期處於空調房間中,以防感冒。"},{"title":"運動","zs":"較適宜","tipt":"運動指數","des":"天氣較好,戶外運動請注意防曬。推薦您進行室內運動。"},{"title":"紫外線強度","zs":"中等","tipt":"紫外線強度指數","des":"屬中等強度紫外線輻射天氣,外出時建議塗擦SPF高於15、PA+的防曬護膚品,戴帽子、太陽鏡。"}],"weather_data":[{"date":"周一 07月18日 (實時:33℃)","dayPictureUrl":"http://api.map.baidu.com/images/weather/day/qing.png","nightPictureUrl":"http://api.map.baidu.com/images/weather/night/duoyun.png","weather":"晴轉多雲","wind":"微風","temperature":"35 ~ 27℃"},{"date":"周二","dayPictureUrl":"http://api.map.baidu.com/images/weather/day/duoyun.png","nightPictureUrl":"http://api.map.baidu.com/images/weather/night/duoyun.png","weather":"多雲","wind":"微風","temperature":"35 ~ 27℃"},{"date":"周三","dayPictureUrl":"http://api.map.baidu.com/images/weather/day/duoyun.png","nightPictureUrl":"http://api.map.baidu.com/images/weather/night/duoyun.png","weather":"多雲","wind":"微風","temperature":"35 ~ 27℃"},{"date":"周四","dayPictureUrl":"http://api.map.baidu.com/images/weather/day/duoyun.png","nightPictureUrl":"http://api.map.baidu.com/images/weather/night/qing.png","weather":"多雲轉晴","wind":"微風","temperature":"35 ~ 27℃"}]}]
*/
private int error;
private String status;
private String date;
/**
* currentCity : 花都
* pm25 :
* index : [{"title":"穿衣","zs":"炎熱","tipt":"穿衣指數","des":"天氣炎熱,建議著短衫、短裙、短褲、薄型T恤衫等清涼夏季服裝。"},{"title":"洗車","zs":"較適宜","tipt":"洗車指數","des":"較適宜洗車,未來一天無雨,風力較小,擦洗一新的汽車至少能保持一天。"},{"title":"旅游","zs":"一般","tipt":"旅游指數","des":"天氣較好,同時有微風相伴,但溫度較高,天氣熱,請盡量避免高溫時段外出,若外出請注意防暑降溫和防曬。"},{"title":"感冒","zs":"少發","tipt":"感冒指數","des":"各項氣象條件適宜,發生感冒機率較低。但請避免長期處於空調房間中,以防感冒。"},{"title":"運動","zs":"較適宜","tipt":"運動指數","des":"天氣較好,戶外運動請注意防曬。推薦您進行室內運動。"},{"title":"紫外線強度","zs":"中等","tipt":"紫外線強度指數","des":"屬中等強度紫外線輻射天氣,外出時建議塗擦SPF高於15、PA+的防曬護膚品,戴帽子、太陽鏡。"}]
* weather_data : [{"date":"周一 07月18日 (實時:33℃)","dayPictureUrl":"http://api.map.baidu.com/images/weather/day/qing.png","nightPictureUrl":"http://api.map.baidu.com/images/weather/night/duoyun.png","weather":"晴轉多雲","wind":"微風","temperature":"35 ~ 27℃"},{"date":"周二","dayPictureUrl":"http://api.map.baidu.com/images/weather/day/duoyun.png","nightPictureUrl":"http://api.map.baidu.com/images/weather/night/duoyun.png","weather":"多雲","wind":"微風","temperature":"35 ~ 27℃"},{"date":"周三","dayPictureUrl":"http://api.map.baidu.com/images/weather/day/duoyun.png","nightPictureUrl":"http://api.map.baidu.com/images/weather/night/duoyun.png","weather":"多雲","wind":"微風","temperature":"35 ~ 27℃"},{"date":"周四","dayPictureUrl":"http://api.map.baidu.com/images/weather/day/duoyun.png","nightPictureUrl":"http://api.map.baidu.com/images/weather/night/qing.png","weather":"多雲轉晴","wind":"微風","temperature":"35 ~ 27℃"}]
*/
private List results;
public void setError(int error) {
this.error = error;
}
public void setStatus(String status) {
this.status = status;
}
public void setDate(String date) {
this.date = date;
}
public void setResults(List results) {
this.results = results;
}
public int getError() {
return error;
}
public String getStatus() {
return status;
}
public String getDate() {
return date;
}
public List getResults() {
return results;
}
public static class ResultsEntity {
private String currentCity;
private String pm25;
/**
* title : 穿衣
* zs : 炎熱
* tipt : 穿衣指數
* des : 天氣炎熱,建議著短衫、短裙、短褲、薄型T恤衫等清涼夏季服裝。
*/
private List index;
/**
* date : 周一 07月18日 (實時:33℃)
* dayPictureUrl : http://api.map.baidu.com/images/weather/day/qing.png
* nightPictureUrl : http://api.map.baidu.com/images/weather/night/duoyun.png
* weather : 晴轉多雲
* wind : 微風
* temperature : 35 ~ 27℃
*/
private List weather_data;
public void setCurrentCity(String currentCity) {
this.currentCity = currentCity;
}
public void setPm25(String pm25) {
this.pm25 = pm25;
}
public void setIndex(List index) {
this.index = index;
}
public void setWeather_data(List weather_data) {
this.weather_data = weather_data;
}
public String getCurrentCity() {
return currentCity;
}
public String getPm25() {
return pm25;
}
public List getIndex() {
return index;
}
public List getWeather_data() {
return weather_data;
}
public static class IndexEntity {
private String title;
private String zs;
private String tipt;
private String des;
public void setTitle(String title) {
this.title = title;
}
public void setZs(String zs) {
this.zs = zs;
}
public void setTipt(String tipt) {
this.tipt = tipt;
}
public void setDes(String des) {
this.des = des;
}
public String getTitle() {
return title;
}
public String getZs() {
return zs;
}
public String getTipt() {
return tipt;
}
public String getDes() {
return des;
}
}
public static class WeatherDataEntity {
private String date;
private String dayPictureUrl;
private String nightPictureUrl;
private String weather;
private String wind;
private String temperature;
public void setDate(String date) {
this.date = date;
}
public void setDayPictureUrl(String dayPictureUrl) {
this.dayPictureUrl = dayPictureUrl;
}
public void setNightPictureUrl(String nightPictureUrl) {
this.nightPictureUrl = nightPictureUrl;
}
public void setWeather(String weather) {
this.weather = weather;
}
public void setWind(String wind) {
this.wind = wind;
}
public void setTemperature(String temperature) {
this.temperature = temperature;
}
public String getDate() {
return date;
}
public String getDayPictureUrl() {
return dayPictureUrl;
}
public String getNightPictureUrl() {
return nightPictureUrl;
}
public String getWeather() {
return weather;
}
public String getWind() {
return wind;
}
public String getTemperature() {
return temperature;
}
}
}
}
public abstract class BasePresenter {
protected Reference mViewRef;
public void attachView(T view) {
mViewRef = new WeakReference(view);
}
public boolean isViewAttached() {
return mViewRef != null && mViewRef.get() != null;
}
public void detachView() {
if (mViewRef != null) {
mViewRef.clear();
mViewRef = null;
}
}
}
public class WeatherPresenter extends BasePresenter {
public void fetchList() {
mViewRef.get().onShowLoading();
VolleyNetHelper.getInstance().doPost(new BaseRequest() {
@Override
public String getMobileApi() {
return "http://api.map.baidu.com/telematics/v3/weather?location=guangzhou&output=json&ak=B95329fb7fdda1e32ba3e3a245193146";
}
@Override
public Map getParams() {
return null;
}
}, new BaseResponse() {
@Override
public void onSuccess(WeatherEntity o) {
mViewRef.get().onHideLoading();
mViewRef.get().onFetchDataSuccess(o);
}
@Override
public void onError(String msg) {
mViewRef.get().onHideLoading();
mViewRef.get().onFetchDataError(msg);
}
@Override
public Class getResponseClass() {
return WeatherEntity.class;
}
});
}
}
public interface WeatherView {
void onFetchDataSuccess(WeatherEntity entity);
void onShowLoading();
void onHideLoading();
void onFetchDataError(String msg);
}
public class WeahterActivity extends BaseActivity implements WeatherView {
@InjectView(R.id.weather_tv)
TextView mWeatherTv;
private WeatherPresenter mWeatherPresenter;
@Override
protected int getLayoutId() {
return R.layout.activity_weather;
}
@Override
protected void init(Bundle savedInstanceState) {
mWeatherPresenter = new WeatherPresenter();
mWeatherPresenter.attachView(this);
mWeatherPresenter.fetchList();
}
@Override
public void onFetchDataSuccess(WeatherEntity entity) {
mWeatherTv.setText(entity.getDate());
}
@Override
public void onShowLoading() {
super.mLoadingDialog.showLoading(LoadingDialog.NETWORK_LOADING);
}
@Override
public void onHideLoading() {
super.mLoadingDialog.hideLoading();
}
@Override
public void onFetchDataError(String msg) {
ToastUtils.longShow(msg);
}
@Override
protected void onDestroy() {
super.onDestroy();
mWeatherPresenter.detachView();
}
}
https://github.com/maoruibin/GankDaily
這裡個人感覺TLint的MVP實踐要更好一些。有需要的可以直接去看源碼。
這裡針對方案1:
例如當應用進入後台且內存不足的時候,系統是會回收這個Activity的。通常我們都知道要用OnSaveInstanceState()去保存狀態,用OnRestoreInstanceState()去恢復狀態。 但是在我們的MVP中,View層是不應該去直接操作Model的,這樣做不合理,同時也增大了M與V的耦合。 界面復用問題。通常我們在APP最初版本中是無法預料到以後會有什麼變動的,例如我們最初使用一個Fragment去作為界面的顯示,後來在版本變動中發現這個Fragment越來越龐大,而Fragment的生命周期又太過復雜造成很多難以理解的BUG,我們需要把這個界面放到一個Activity中實現。這時候就麻煩了,要把Fragment轉成Activity,這可不僅僅是改改類名的問題,更多的是一大堆生命周期需要去修改。例如參考文章2中的譯者就遇到過這樣的問題。 Activity本身就是Android中的一個Context。不論怎麼去封裝,都難以避免將業務邏輯代碼寫入到其中。 如何防止activity等等內存洩露。這個問題非常嚴重,好好想一下有無好的方案。 V,P對應的比例關系。Android中的Toast是很常見的一個消息提示框,但是默認的消息提示框就是一行純文本,所以我們可以為它設置一些其他的諸如是帶上圖片的消息提示。 實現這個很簡單: 就是
360來電顯示歸屬地怎麼設置? 1、如果你使用的是安卓手機,那麼下載安裝並打開安卓版360安全衛士,切換到隱私保護然後點擊右上角三點符號找到衛士設置;3
Android Studio中提供了非常方便的搜索工具,可以在編輯器的文件中使用,也可以在android輸出的日志中使用,用法都是一樣的.打開搜索工具欄一. 在當前編輯的
三種得到LinearInflater的方法a. LayoutInflater inflater = getLayoutInflater();b. LayoutInflat