最近在學(xué)習(xí)Android的MVP模式姑曙,就是MVP(Model-View-Presenter)伤靠,網(wǎng)上大部分都是比較小的例子啼染,所以想拿個小項目練手焕梅,于是采用了基于Rss feed的閱讀器。
1.Rss feeds是什么徒欣?
是一種根據(jù)XML特性所制定的格式打肝,將網(wǎng)頁內(nèi)容抽取出來,讀者訂閱RSS Feed争便,即可直接取得有興趣的資訊断医。簡單來說就是一種xml。2.MVP是什么?
解決的問題: 不讓activity承接太多任務(wù) 斩启;使得Model和View層解耦醉锅,職責(zé)劃分明顯硬耍。結(jié)構(gòu)清晰。(感覺說了跟白說一樣)1.Model 提供數(shù)據(jù)
2.View 負(fù)責(zé)顯示
3.Presenter 邏輯的處理狸窘,作為Model和view的中間者坯认,從Model獲得數(shù)據(jù)然后控制view顯示.
3.整個結(jié)構(gòu):
具體效果:
- 4.怎么獲取Rss feeds數(shù)據(jù)鹃操?
我在這里使用的是volley + 自定義的xmlRequest荆隘,在文章底部有附源碼,主要寫大概獲取和使用方式:
首先自定義一個接口:
public interface RssLoadListener {
void onLoadSuccess(List<RssInfo> rssInfoList);//獲取成功
void onLoadFailed();//獲取失敗
void onNetWorkFailed();//網(wǎng)絡(luò)錯誤
void onBeginLoad();//開始任務(wù)
}
讓RssLoad下載任務(wù)時候?qū)崿F(xiàn)這個接口并作為參數(shù)傳進(jìn)去, 有了這個接口晶渠,我們在哪里需要下載數(shù)據(jù)的時候就可以這么應(yīng)用:
new RssLoadModel(context,RSS_URL).excute(new RssLoadListener() {
@Override
public void onBeginLoad() {
view.showLoading();//剛開始下載的操作
}
@Override
public void onLoadSuccess(List<RssInfo> rssInfoList) {
//下載成功后要做什么
Log.d(TAG, "onLoadSuccess: ");
view.hideLoading();
view.showResult(rssInfoList);
}
@Override
public void onLoadFailed() {
//若失敗后的操作
view.hideLoading();
view.showError("更新失敗");
}
@Override
public void onNetWorkFailed() {
view.showError("網(wǎng)絡(luò)不可用");
view.hideLoading();
}
});
RssLoadModel是一個負(fù)責(zé)下載的類,里面的excute方法負(fù)責(zé)下載褒脯,并在下載過程中調(diào)用loadListener的方法,比如下載成功就調(diào)用onLoadSuccess(),至于里面成功后應(yīng)該怎么做到涂,就由你來實現(xiàn)践啄,這樣就達(dá)到了將狀態(tài)和結(jié)果傳遞出去的目的沉御。
public void excute(final RssLoadListener loadListener){
if(!NetworkUtils.isNetworkAvailable(context)){
loadListener.onNetWorkFailed();//網(wǎng)絡(luò)失敗
return;
}
loadListener.onBeginLoad();
XMLRequest xmlRequest = new XMLRequest(Constants.RSS_URL,
new Response.Listener<XmlPullParser>() {
@Override
public void onResponse(XmlPullParser response) {
parserXML(response);
loadListener.onLoadSuccess(rssInfos);
//調(diào)用下載成功,將結(jié)果傳遞出去
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e("TAG", error.getMessage(), error);
loadListener.onLoadFailed();//失敗
}
});
mQueue.add(xmlRequest);
}
XMLRequest 是繼承volley.Request的自定義類吠裆,volley是一個方便Android應(yīng)用網(wǎng)絡(luò)操作框架,默認(rèn)沒有XML的request衩婚,(寶寶不開心):
public class XMLRequest extends Request<XmlPullParser> {
private final Response.Listener<XmlPullParser> mListener;
public XMLRequest(int method, String url, Response.Listener<XmlPullParser> listener,
Response.ErrorListener errorListener) {
super(method, url, errorListener);
mListener = listener;
}
public XMLRequest(String url, Response.Listener<XmlPullParser> listener, Response.ErrorListener errorListener) {
this(Method.GET, url, listener, errorListener);
}
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
//需要加非春,否則獲取不到數(shù)據(jù)
HashMap<String, String> headers = new HashMap<String, String>();
headers.put("Content-Type", "application/xml; charset=utf-8");
return headers;
}
@Override
protected Response<XmlPullParser> parseNetworkResponse(NetworkResponse response) {
try {
String xmlString = new String(response.data,
HttpHeaderParser.parseCharset(response.headers));
Log.d("tag",xmlString);
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser xmlPullParser = factory.newPullParser();
xmlPullParser.setInput(new StringReader(xmlString));
return Response.success(xmlPullParser, HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (XmlPullParserException e) {
return Response.error(new ParseError(e));
}
}
@Override
protected void deliverResponse(XmlPullParser response) {
mListener.onResponse(response);
}
}
- 5.mvp
VIew
- MvpView類是個接口
public interface MvpView {}
- RssView 繼承MvpView接口奇昙,具體的View類需要實現(xiàn)下面的方法敌完,那么presenter想要控制具體的View類操作滨溉,就可以直接調(diào)用showLoading()等方法,這也是針對抽象編程闽撤。
public interface RssView extends MvpView {
/**
* 顯示loading下載視圖
*/
void showLoading();
/**
*隱藏loading下載視圖
*/
void hideLoading();
/**
* 顯示錯誤信息
* @param msg
*/
void showError(String msg);
/**
* 顯示結(jié)果
* @param rssInfos
*/
void showResult(List<RssInfo> rssInfos);
/**
* @param title
*/
void showTitle(String title);
}
- 具體的view類脯颜,這里使用Activity作為view類,現(xiàn)在很多都將fragment作為view闸餐,將activity控制生命周期舍沙。
public class MainActivity extends BaseActivty implements RssView
需要實現(xiàn)下列方法,實現(xiàn)這么多方法給誰調(diào)用呢壹无?當(dāng)然是Presenter了和媳。
@Override
public void showLoading() {//顯示下載
progressWheel.setVisibility(View.VISIBLE);
swipeRefreshLayout.setVisibility(View.GONE);
ValueAnimator progressFadeInAnim = ObjectAnimator.ofFloat(progressWheel, "alpha", 0, 1, 1);
progressFadeInAnim.start();
}
@Override
public void hideLoading() {//隱藏下載
progressWheel.setVisibility(View.GONE);
swipeRefreshLayout.setVisibility(View.VISIBLE);
swipeRefreshLayout.setRefreshing(false); // close refresh animator
ValueAnimator progressFadeInAnim = ObjectAnimator.ofFloat(progressWheel, "alpha", 1, 0, 0);
progressFadeInAnim.start();
}
@Override
public void showError(String msg) {//顯示錯誤信息
new SweetAlertDialog(this, SweetAlertDialog.ERROR_TYPE)
.setTitleText("Oops...")
.setContentText(msg)
.show();
}
@Override
public void showResult(List<RssInfo> rssInfos) {//顯示結(jié)果
rssAdapter.setRssInfos(rssInfos);
}
@Override
public void showTitle(String title) {//顯示標(biāo)題
((TextView)findViewById(R.id.toolbar_title)).setText(title);
}
Presenter
MvpPresenter 接口留瞳,里面有兩個方法attachView和detachView骚秦,負(fù)責(zé)將MvpView 綁定在MvpPresenter和解除綁定;例如在view類里面調(diào)用
presenter.attachView(this);
將自己傳進(jìn)去作箍,這樣 presenter就擁有了view,也就可以隨心所欲地控制view了荧止,Presenter通過接口進(jìn)行對View的操作阶剑。
public interface MvpPresenter<V extends MvpView> {
/**
* 將 MvpView 綁定在MvpPresenter
* @param view
*/
public void attachView(V view);
/**
* @param retainInstance
* 解除綁定
*/
public void detachView(boolean retainInstance);
}
RssPresenter類
/**
* Created by cheng on 16-7-24.
*/
public class RssPresenter implements MvpPresenter<RssView> {
private final static String TAG = "RssPresenter";
private RssView view;
private Context context;
public RssPresenter(Context context) {
this.context = context;
}
public void startLoadTask() {//開始下載
if (view == null) {
Log.w(TAG, "please attach view first.");
return;
}
new RssLoadModel(context,RSS_URL).excute(new RssLoadListener() {
@Override
public void onBeginLoad() {
view.showLoading();
}
@Override
public void onLoadSuccess(List<RssInfo> rssInfoList) {
Log.d(TAG, "onLoadSuccess: ");
view.hideLoading();
view.showResult(rssInfoList);
}
@Override
public void onLoadFailed() {
view.hideLoading();
view.showError("更新失敗");
}
@Override
public void onNetWorkFailed() {
view.showError("網(wǎng)絡(luò)不可用");
view.hideLoading();
}
});
}
@Override
public void attachView(RssView view) {
this.view = view;
}
@Override
public void detachView(boolean retainInstance) {
// TODO
}
}
6.以上只是一部分源碼素邪,具體的源碼:
https://github.com/ChyengJason/RssReader7.不足
mvp clean模式
對mvp理解還比較淺顯猪半,繼續(xù)學(xué)習(xí)。沽甥。乏奥。