此博文根據(jù)前面兩篇文章 Android MVP 架構(gòu)初試
Android MVP 架構(gòu)封裝
再結(jié)合主流框架Retrofit2+Rxjava
來個(gè)實(shí)踐(實(shí)現(xiàn)聚合網(wǎng)周公解夢)
源碼地址RxMVP
項(xiàng)目截圖
Retrofit2+Rxjava 封裝
JuHeService 數(shù)據(jù)請(qǐng)求接口
/**
* 請(qǐng)求示例:
* http://v.juhe.cn/dream/query
* q:夢境關(guān)鍵字艰垂,如:黃金 需要utf8 urlencode
* cid:指定分類蹲蒲,默認(rèn)全部
* full: 是否顯示詳細(xì)信息涩哟,1:是 0:否索赏,默認(rèn)0
*/
public interface JuHeService {
@GET("dream/query")
Observable<HttpJuHeResult<List<JuHeDream>>> getDreams(@QueryMap Map<String, Object> options);
}
HttpJuHeMethods 聚合解夢封裝的方法
public class HttpJuHeMethods {
public static final String BASE_URL = "http://v.juhe.cn/";
private static final int DEFAULT_TIMEOUT = 5;
private Retrofit retrofit;
private JuHeService juheService;
//構(gòu)造方法私有
private HttpJuHeMethods() {
//手動(dòng)創(chuàng)建一個(gè)OkHttpClient并設(shè)置超時(shí)時(shí)間
OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
httpClientBuilder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
httpClientBuilder.addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)).build();
retrofit = new Retrofit.Builder()
.client(httpClientBuilder.build())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl(BASE_URL)
.build();
juheService = retrofit.create(JuHeService.class);
}
//在訪問HttpMethods時(shí)創(chuàng)建單例
private static class SingletonHolder{
private static final HttpJuHeMethods INSTANCE = new HttpJuHeMethods();
}
//獲取單例
public static HttpJuHeMethods getInstance(){
return SingletonHolder.INSTANCE;
}
/**
* 用來統(tǒng)一處理Http的resultCode,并將HttpResult的Data部分剝離出來返回給subscriber
*
* @param <T> Subscriber真正需要的數(shù)據(jù)類型,也就是Data部分的數(shù)據(jù)類型
*/
private class HttpResultFunc<T> implements Func1<HttpJuHeResult<T>, T> {
@Override
public T call(HttpJuHeResult<T> httpResult) {
if (httpResult.getError_code() != 0) {
throw new ApiException(httpResult.getError_code());
}
return httpResult.getResult();
}
}
private <T> void toSubscribe(Observable<T> observable, Subscriber<T> subscriber){
observable.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);
}
/**
* 用于獲取聚合笑話的數(shù)據(jù)
* @param subscriber 由調(diào)用者傳過來的觀察者對(duì)象
* @param options 訪問參數(shù)
*/
public void getJokesByHttpResultMap(Subscriber<List<JuHeDream>> subscriber, Map<String, Object> options){
// juheService.getJokesByRxJavaHttpResult(options)
// .map(new HttpResultFunc<JuHeDream>())
// .subscribeOn(Schedulers.io())
// .unsubscribeOn(Schedulers.io())
// .observeOn(AndroidSchedulers.mainThread())
// .subscribe(subscriber);
Observable<List<JuHeDream>> observable = juheService.getDreams(options)
.map(new HttpResultFunc<List<JuHeDream>>());
toSubscribe(observable,subscriber);
}
}
其中包含異常的處理
public class ApiException extends RuntimeException{
public final static int TIME_MUST_10=209501;
public final static int TIME_OTHER=209502;
public ApiException(int resultCode) {
this(getApiExceptionMessage(resultCode));
}
public ApiException(String detailMessage) {
super(detailMessage);
}
/**
* 由于服務(wù)器傳遞過來的錯(cuò)誤信息直接給用戶看的話贴彼,用戶未必能夠理解
* 需要根據(jù)錯(cuò)誤碼對(duì)錯(cuò)誤信息進(jìn)行一個(gè)轉(zhuǎn)換潜腻,在顯示給用戶
* @param code
* @return
*/
private static String getApiExceptionMessage(int code){
String message = "";
switch (code) {
case TIME_MUST_10:
message = "必須為10位時(shí)間戳";
break;
case TIME_OTHER:
message = "page、pagesize必須為int類型,time為10位時(shí)間戳";
break;
default:
message = "未知錯(cuò)誤";
}
return message;
}
}
BaseMvp封裝
請(qǐng)參考上篇文章 Android MVP 架構(gòu)封裝
Retrofit2+Rxjava+MVP實(shí)踐
MvpView
public interface MvpView extends BaseView {
//ListView的初始化
void setListItem(List<JuHeDream> data);
//Toast 消息
void showMessage(String messgae);
}
MvpPresenter
public class MvpPresenter extends BasePresenter<MvpView> {
private Context mContext;
private Subscriber subscriber;
private List<JuHeDream> mDatas;
public MvpPresenter(Context context) {
this.mContext = context;
}
//獲取數(shù)據(jù)
public void getData(String q) throws UnsupportedEncodingException {
if (q.isEmpty()) {
mView.showMessage("請(qǐng)輸入解夢內(nèi)容");
return;
}
mView.showLoading();
getDream(q);
}
public void onItemClick(int position) {
List<String> stringList = mDatas.get(position).getList();
StringBuffer sbf = new StringBuffer();
for (String s : stringList) {
sbf.append(s).append("\n\n\n");
}
new SweetAlertDialog(mContext)
.setTitleText(mDatas.get(position).getTitle())
.setContentText(sbf.toString())
.show();
}
private void getDream(String q) throws UnsupportedEncodingException {
String content = URLDecoder.decode(q, "utf-8");
Map<String, Object> options = new HashMap<String, Object>();
options.put("key", "f86ed9f21931cd311deffada92b58ac7");
options.put("full", "1");
options.put("q", content);
subscriber = new Subscriber<List<JuHeDream>>() {
@Override
public void onCompleted() {
mView.hideLoading();
}
@Override
public void onError(Throwable e) {
mView.hideLoading();
mView.showMessage(e.toString());
}
@Override
public void onNext(List<JuHeDream> data) {
for (JuHeDream juheDream:data) {
Logger.e(juheDream.toString());
}
mDatas = data;
mView.setListItem(mDatas);
}
};
HttpJuHeMethods.getInstance().getJokesByHttpResultMap(subscriber,options);
}
public void destory(){
subscriber.unsubscribe();
}
}
布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context=".view.MainActivity">
<LinearLayout
android:layout_width="920px"
android:layout_height="130px"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20px"
android:orientation="horizontal" >
<LinearLayout
android:layout_width="680px"
android:layout_height="130px"
android:background="@drawable/shape_query_normal_stroke"
android:orientation="horizontal" >
<ImageView
android:layout_width="57px"
android:layout_height="70px"
android:layout_gravity="center_vertical"
android:layout_marginLeft="40px"
android:src="@drawable/login_yanzhengma"
android:text="設(shè)置密碼" />
<View
android:layout_width="0.5px"
android:layout_height="match_parent"
android:layout_marginLeft="40px"
android:background="@color/line" />
<EditText
android:id="@+id/id_dream_query"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:layout_marginLeft="13px"
android:background="@null"
android:hint="請(qǐng)輸入解夢的內(nèi)容"
android:singleLine="true"
android:textColor="@color/textcolor"
android:textSize="40px" />
</LinearLayout>
<View
android:layout_width="20px"
android:layout_height="match_parent" />
<Button
android:id="@+id/id_dream_btn"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:background="@drawable/query"
android:clickable="true"
android:gravity="center"
android:text="查詢"
android:textColor="@android:color/white"
android:textSize="40px" />
</LinearLayout>
<ListView
android:id="@+id/id_dream_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
/>
</LinearLayout>
MainActivity
public class MainActivity extends BaseMvpActivity<MvpView, MvpPresenter> implements MvpView, AdapterView.OnItemClickListener {
@BindView(R.id.id_dream_query)
EditText dreamQuery;
@BindView(R.id.id_dream_btn)
Button dreamBtn;
@BindView(R.id.id_dream_result)
ListView listView;
private Context mContext;
MyAdapter myAdapter;
SweetAlertDialog pd;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this;
ButterKnife.bind(this);
initEvent();
}
private void initEvent() {
listView.setOnItemClickListener(this);
}
@OnClick(R.id.id_dream_btn)
public void onClick() {
try {
String q = dreamQuery.getText().toString();
presenter.getData(q);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
@Override
public MvpPresenter initPresenter() {
return new MvpPresenter(this);
}
@Override
public void setListItem(List<JuHeDream> data) {
if (myAdapter == null){
myAdapter = new MyAdapter(mContext, data);
}
if (listView.getAdapter() == null){
listView.setAdapter(myAdapter);
}
myAdapter.refresh(data);
}
@Override
public void showMessage(String messgae) {
Toast.makeText(mContext, messgae, Toast.LENGTH_SHORT).show();
}
@Override
public void showLoading() {
if (pd == null) {
pd = new SweetAlertDialog(mContext, SweetAlertDialog.PROGRESS_TYPE);
pd.getProgressHelper().setBarColor(Color.parseColor("#A5DC86"));
pd.setTitleText("Loading");
pd.setCancelable(true);
}
pd.show();
}
@Override
public void hideLoading() {
pd.hide();
}
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
presenter.onItemClick(position);
}
@Override
protected void onDestroy() {
presenter.destory();
super.onDestroy();
}
}