MVP+Retrofit+RxJava
添加依赖
ext { appcompatVersion = '27.1.0' butterknifeVersion = '8.4.0' retrofitVersion = '2.3.0' logginginterceptor = '3.9.1' rxjavaVersion = '2.1.11' rxandroidVersion = "2.0.2" }
implementation "com.squareup.retrofit2:retrofit:$retrofitVersion" implementation "com.squareup.okhttp3:logging-interceptor:$logginginterceptor" implementation "com.squareup.retrofit2:converter-gson:$retrofitVersion" implementation "com.squareup.retrofit2:adapter-rxjava2:$retrofitVersion" implementation "io.reactivex.rxjava2:rxandroid:$rxandroidVersion" implementation "io.reactivex.rxjava2:rxjava:$rxjavaVersion"
import okhttp3.OkHttpClient; import okhttp3.logging.HttpLoggingInterceptor; import retrofit2.Retrofit; import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; import retrofit2.converter.gson.GsonConverterFactory; public class ApiClient { public static Retrofit mRetrofit; public static Retrofit retrofit() { if (mRetrofit == null) { OkHttpClient.Builder builder = new OkHttpClient.Builder(); // Log信息拦截器 HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(); loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); //设置 Debug Log 模式 builder.addInterceptor(loggingInterceptor); OkHttpClient okHttpClient = builder.build(); mRetrofit = new Retrofit.Builder() .baseUrl(ApiStores.API_SERVER_URL) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .client(okHttpClient) .build(); } return mRetrofit; } }
import com.loaderman.jsoupdemo.main.MainModel; import io.reactivex.Observable; import retrofit2.Call; import retrofit2.http.GET; import retrofit2.http.Path; public interface ApiStores { //baseUrl String API_SERVER_URL = "http://www.weather.com.cn/"; //加载天气 @GET("adat/sk/{cityId}.html") Call<MainModel> loadDataByRetrofit(@Path("cityId") String cityId); //加载天气 @GET("adat/sk/{cityId}.html") Observable<MainModel> loadDataByRetrofitRxJava(@Path("cityId") String cityId); }
import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; public abstract class RetrofitCallback<M> implements Callback<M> { public abstract void onSuccess(M model); public abstract void onFailure(int code, String msg); public abstract void onThrowable(Throwable t); public abstract void onFinish(); @Override public void onResponse(Call<M> call, Response<M> response) { if (response.isSuccessful()) { onSuccess(response.body()); } else { onFailure(response.code(), response.errorBody().toString()); } onFinish(); } @Override public void onFailure(Call<M> call, Throwable t) { onThrowable(t); onFinish(); } }
import io.reactivex.observers.DisposableObserver; import retrofit2.HttpException; public abstract class ApiCallback<M> extends DisposableObserver<M> { public abstract void onSuccess(M model); public abstract void onFailure(String msg); public abstract void onFinish(); @Override public void onError(Throwable e) { e.printStackTrace(); if (e instanceof HttpException) { HttpException httpException = (HttpException) e; //httpException.response().errorBody().string() int code = httpException.code(); String msg = httpException.getMessage(); if (code == 504) { msg = "网络不给力"; } if (code == 502 || code == 404) { msg = "服务器异常,请稍后再试"; } onFailure(msg); } else { onFailure(e.getMessage()); } onFinish(); } @Override public void onNext(M model) { onSuccess(model); } @Override public void onComplete() { onFinish(); } }
import android.app.Activity; import android.app.ProgressDialog; import android.support.annotation.LayoutRes; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import android.widget.Toast; import com.loaderman.jsoupdemo.R; import com.loaderman.jsoupdemo.retrofit.ApiClient; import com.loaderman.jsoupdemo.retrofit.ApiStores; import java.util.ArrayList; import java.util.List; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.Disposable; import io.reactivex.observers.DisposableObserver; import io.reactivex.schedulers.Schedulers; import retrofit2.Call; public abstract class BaseActivity extends AppCompatActivity { public Activity mActivity; private CompositeDisposable mCompositeDisposable; private List<Call> calls; @Override public void setContentView(@LayoutRes int layoutResID) { super.setContentView(layoutResID); mActivity = this; } @Override public void setContentView(View view) { super.setContentView(view); mActivity = this; } @Override public void setContentView(View view, ViewGroup.LayoutParams params) { super.setContentView(view, params); mActivity = this; } @Override protected void onDestroy() { callCancel(); onUnsubscribe(); super.onDestroy(); } public ApiStores apiStores() { return ApiClient.retrofit().create(ApiStores.class); } public void addCalls(Call call) { if (calls == null) { calls = new ArrayList<>(); } calls.add(call); } private void callCancel() { if (calls != null && calls.size() > 0) { for (Call call : calls) { if (!call.isCanceled()) call.cancel(); } calls.clear(); } } public <T> void addSubscription(Observable<T> observable, DisposableObserver<T> observer) { if (mCompositeDisposable == null) { mCompositeDisposable = new CompositeDisposable(); } mCompositeDisposable.add(observer); observable.subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(observer); } public void addSubscription(Disposable disposable) { if (mCompositeDisposable == null) { mCompositeDisposable = new CompositeDisposable(); } mCompositeDisposable.add(disposable); } public void onUnsubscribe() { //取消注册,以避免内存泄露 if (mCompositeDisposable != null) mCompositeDisposable.dispose(); } public Toolbar initToolBar(String title) { Toolbar toolbar = findViewById(R.id.toolbar); if (toolbar != null) { setSupportActionBar(toolbar); TextView toolbaTitle = toolbar.findViewById(R.id.toolbar_title); toolbaTitle.setText(title); } ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { actionBar.setDisplayHomeAsUpEnabled(true); actionBar.setDisplayShowTitleEnabled(false); } return toolbar; } public Toolbar initToolBarAsHome(String title) { Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); if (toolbar != null) { setSupportActionBar(toolbar); TextView toolbaTitle = (TextView) toolbar.findViewById(R.id.toolbar_title); toolbaTitle.setText(title); } ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { actionBar.setDisplayHomeAsUpEnabled(false); actionBar.setDisplayShowTitleEnabled(false); } return toolbar; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: super.onBackPressed();//返回 return true; default: return super.onOptionsItemSelected(item); } } public void toastShow(int resId) { Toast.makeText(mActivity, resId, Toast.LENGTH_SHORT).show(); } public void toastShow(String resId) { Toast.makeText(mActivity, resId, Toast.LENGTH_SHORT).show(); } public ProgressDialog progressDialog; public ProgressDialog showProgressDialog() { progressDialog = new ProgressDialog(mActivity); progressDialog.setMessage("加载中"); progressDialog.show(); return progressDialog; } public ProgressDialog showProgressDialog(CharSequence message) { progressDialog = new ProgressDialog(mActivity); progressDialog.setMessage(message); progressDialog.show(); return progressDialog; } public void dismissProgressDialog() { if (progressDialog != null && progressDialog.isShowing()) { // progressDialog.hide();会导致android.view.WindowLeaked progressDialog.dismiss(); } } }
import android.app.Activity; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v7.widget.Toolbar; import android.view.View; import android.widget.TextView; import android.widget.Toast; import com.loaderman.jsoupdemo.R; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.observers.DisposableObserver; public class BaseFragment extends Fragment { public Activity mActivity; @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); mActivity = getActivity(); } public Toolbar initToolBar(View view, String title) { Toolbar toolbar = (Toolbar) view.findViewById(R.id.toolbar); TextView toolbar_title = (TextView) toolbar.findViewById(R.id.toolbar_title); toolbar_title.setText(title); return toolbar; } public void toastShow(int resId) { Toast.makeText(mActivity, resId, Toast.LENGTH_SHORT).show(); } public void toastShow(String resId) { Toast.makeText(mActivity, resId, Toast.LENGTH_SHORT).show(); } @Override public void onDestroy() { super.onDestroy(); onUnsubscribe(); } private CompositeDisposable mCompositeDisposable; public void onUnsubscribe() { //取消注册,以避免内存泄露 if (mCompositeDisposable != null) { mCompositeDisposable.dispose(); } } public void addSubscription(DisposableObserver observer) { // if (mCompositeDisposable == null) { mCompositeDisposable = new CompositeDisposable(); // } mCompositeDisposable.add(observer); } }
public interface BaseView { void showLoading(); void hideLoading(); }
public class MainModel { private WeatherinfoBean weatherinfo; public WeatherinfoBean getWeatherinfo() { return weatherinfo; } public void setWeatherinfo(WeatherinfoBean weatherinfo) { this.weatherinfo = weatherinfo; } public static class WeatherinfoBean { private String city; private String cityid; private String temp; private String WD; private String WS; private String SD; private String WSE; private String time; private String isRadar; private String Radar; private String njd; private String qy; public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getCityid() { return cityid; } public void setCityid(String cityid) { this.cityid = cityid; } public String getTemp() { return temp; } public void setTemp(String temp) { this.temp = temp; } public String getWD() { return WD; } public void setWD(String WD) { this.WD = WD; } public String getWS() { return WS; } public void setWS(String WS) { this.WS = WS; } public String getSD() { return SD; } public void setSD(String SD) { this.SD = SD; } public String getWSE() { return WSE; } public void setWSE(String WSE) { this.WSE = WSE; } public String getTime() { return time; } public void setTime(String time) { this.time = time; } public String getIsRadar() { return isRadar; } public void setIsRadar(String isRadar) { this.isRadar = isRadar; } public String getRadar() { return Radar; } public void setRadar(String Radar) { this.Radar = Radar; } public String getNjd() { return njd; } public void setNjd(String njd) { this.njd = njd; } public String getQy() { return qy; } public void setQy(String qy) { this.qy = qy; } } }
import com.loaderman.jsoupdemo.other.BasePresenter; import com.loaderman.jsoupdemo.retrofit.ApiCallback; public class MainPresenter extends BasePresenter<MainView> { public MainPresenter(MainView view) { attachView(view); } public void loadDataByRetrofitRxjava(String cityId) { mvpView.showLoading(); addSubscription(apiStores.loadDataByRetrofitRxJava(cityId), new ApiCallback<MainModel>() { @Override public void onSuccess(MainModel model) { mvpView.getDataSuccess(model); } @Override public void onFailure(String msg) { mvpView.getDataFail(msg); } @Override public void onFinish() { mvpView.hideLoading(); } }); } }
public interface MainView extends BaseView { void getDataSuccess(MainModel model); void getDataFail(String msg); }
import com.loaderman.jsoupdemo.retrofit.ApiClient; import com.loaderman.jsoupdemo.retrofit.ApiStores; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.observers.DisposableObserver; import io.reactivex.schedulers.Schedulers; public class BasePresenter<V> { public V mvpView; protected ApiStores apiStores; private CompositeDisposable mCompositeDisposable; public void attachView(V mvpView) { this.mvpView = mvpView; apiStores = ApiClient.retrofit().create(ApiStores.class); } public void detachView() { this.mvpView = null; onUnSubscribe(); } //RxJava取消注册,以避免内存泄露 public void onUnSubscribe() { if (mCompositeDisposable != null) { mCompositeDisposable.dispose(); } } public void addSubscription(Observable observable, DisposableObserver observer) { if (mCompositeDisposable == null) { mCompositeDisposable = new CompositeDisposable(); } mCompositeDisposable.add(observer); observable.subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribeWith(observer); } }
import android.os.Bundle; import com.loaderman.jsoupdemo.base.BaseActivity; public abstract class MvpActivity<P extends BasePresenter> extends BaseActivity { protected P mvpPresenter; @Override protected void onCreate(Bundle savedInstanceState) { mvpPresenter = createPresenter(); super.onCreate(savedInstanceState); } protected abstract P createPresenter(); @Override protected void onDestroy() { super.onDestroy(); if (mvpPresenter != null) { mvpPresenter.detachView(); } } public void showLoading() { showProgressDialog(); } public void hideLoading() { dismissProgressDialog(); } }
import android.os.Bundle; import android.view.View; import com.loaderman.jsoupdemo.base.BaseFragment; public abstract class MvpFragment<P extends BasePresenter> extends BaseFragment { protected P mvpPresenter; @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); mvpPresenter = createPresenter(); } protected abstract P createPresenter(); @Override public void onDestroyView() { super.onDestroyView(); if (mvpPresenter != null) { mvpPresenter.detachView(); } } }
import android.os.Bundle; import android.view.View; import android.widget.TextView; import com.loaderman.jsoupdemo.R; import com.loaderman.jsoupdemo.main.MainModel; import com.loaderman.jsoupdemo.main.MainPresenter; import com.loaderman.jsoupdemo.main.MainView; import com.loaderman.jsoupdemo.other.MvpActivity; import com.loaderman.jsoupdemo.retrofit.ApiCallback; import com.loaderman.jsoupdemo.retrofit.RetrofitCallback; import retrofit2.Call; public class MainActivity extends MvpActivity<MainPresenter> implements MainView { private TextView text; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); text = findViewById(R.id.text); initToolBarAsHome(getString(R.string.title)); } @Override protected MainPresenter createPresenter() { return new MainPresenter(this); } @Override public void getDataSuccess(MainModel model) { //接口成功回调 dataSuccess(model); } @Override public void getDataFail(String msg) { toastShow(getString(R.string.net_error)); } public void onClick(View view) { switch (view.getId()) { case R.id.button0://Retrofit常规用法 loadDataByRetrofit(); break; case R.id.button1://RxJava+Retrofit常规用法 loadDataByRetrofitRxJava(); break; case R.id.button2://mvp+RxJava+Retrofit常规用法 //请求接口 mvpPresenter.loadDataByRetrofitRxjava("101310222"); break; } } private void loadDataByRetrofit() { showProgressDialog(); Call<MainModel> call = apiStores().loadDataByRetrofit("101190201"); call.enqueue(new RetrofitCallback<MainModel>() { @Override public void onSuccess(MainModel model) { dataSuccess(model); } @Override public void onFailure(int code, String msg) { toastShow(msg); } @Override public void onThrowable(Throwable t) { toastShow(t.getMessage()); } @Override public void onFinish() { dismissProgressDialog(); } }); addCalls(call); } //全国+国外主要城市代码http://mobile.weather.com.cn/js/citylist.xml private void loadDataByRetrofitRxJava() { showProgressDialog(); addSubscription( apiStores().loadDataByRetrofitRxJava("101220602"), new ApiCallback<MainModel>() { @Override public void onSuccess(MainModel model) { dataSuccess(model); } @Override public void onFailure(String msg) { toastShow(msg); } @Override public void onFinish() { dismissProgressDialog(); } }); } private void dataSuccess(MainModel model) { MainModel.WeatherinfoBean weatherinfo = model.getWeatherinfo(); String showData = getResources().getString(R.string.city) + weatherinfo.getCity() + getResources().getString(R.string.wd) + weatherinfo.getWD() + getResources().getString(R.string.ws) + weatherinfo.getWS() + getResources().getString(R.string.time) + weatherinfo.getTime(); text.setText(showData); } }
main布局
<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:orientation="vertical" tools:context=".ui.MainActivity"> <include layout="@layout/toolbar" /> <Button android:id="@+id/button0" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_marginRight="10dp" android:layout_marginTop="20dp" android:onClick="onClick" android:text="@string/text0" /> <Button android:id="@+id/button1" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_marginRight="10dp" android:layout_marginTop="20dp" android:onClick="onClick" android:text="@string/text1" /> <Button android:id="@+id/button2" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_marginRight="10dp" android:layout_marginTop="20dp" android:onClick="onClick" android:text="@string/text2" /> <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="10dp" /> </LinearLayout>
toolbar布局
<?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?colorPrimary" android:minHeight="?actionBarSize"> <TextView android:id="@+id/toolbar_title" style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:textColor="@android:color/white" android:textStyle="bold"/> </android.support.v7.widget.Toolbar>
String
<resources> <string name="app_name">天气</string> <string name="hello_world">Hello world!</string> <string name="action_settings">Settings</string> <string name="city">城市:</string> <string name="wd">\n风向:</string> <string name="ws">\n风级:</string> <string name="time">\n发布时间:</string> <string name="net_error">网络不给力</string> <string name="title">MVP+Retrofit+Rxjava2</string> <string name="text0">普通写法(Retrofit)</string> <string name="text1">普通写法(Retrofit+Rxjava)</string> <string name="text2">MVP+Retrofit+Rxjava</string> </resources>
最后添加网络权限
<uses-permission android:name="android.permission.INTERNET" />
运行即可
最后,关注【码上加油站】微信公众号后,有疑惑有问题想加油的小伙伴可以码上加入社群,让我们一起码上加油吧!!!