One: Add dependencies
1. Add rxJava, Retrofit and other dependencies to build.gradle
dependencies { compile fileTree(dir: 'libs', include: [' *. Jar ']) testCompile junit: junit: '4.12' compile 'com. Android. Support: appcompat - v7:23.4.0' compile 'com. Android. Support: design: 23.4.0' compile 'com. Jakewharton: butterknife: 7.0.0 rxjava / * * * * / compile 'IO. Reactivex: rxandroid: 1.1.0' compile 'IO. Reactivex: rxjava: 1.1.0' retrofit / * * * * / compile 'com. Squareup. Retrofit2: retrofit: 2.1.0' compile 'com. Squareup. Retrofit2: converter - gson: 2.0.2' compile 'com. Squareup. Retrofit2: adapter - rxjava: 2.1.0' okhttp / * * * * / compile 'com. Squareup. Okhttp3: okhttp: 3.3.1' compile 'com. Squareup. Okhttp3: logging - interceptor: 3.3.1'Copy the code
}
2. Add the OkHttp configuration
// create okHttpClient.builder Builder = new okHttpClient.builder (); builder.connectTimeout(1000*60, TimeUnit.SECONDS); WriteTimeout (1000*60, timeunit.seconds); ReadTimeout (1000*60, timeunit.seconds); // Write timeout builder.readTimeout(1000*60, timeunit.seconds); // Read operation timeout replicates codeCopy the code
3. Add retroFIT configuration
ApiConfig.BASE_URL = "https://wanandroid.com/"; // create OKHttpClient okHttpClient.builder httpBuilder = new okHttpClient.builder (); httpBuilder.connectTimeout(1000*60, TimeUnit.SECONDS); Httpbuilder.writetimeout (1000*60, timeUnit.seconds); // Write timeout httpBuilder.readTimeout(1000*60, timeunit.seconds); MRetrofit = new retrofit.builder ().client(httpBuilder.build()) .addConverterFactory(GsonConverterFactory.create()) .baseUrl(ApiConfig.BASE_URL) .build(); Copy the codeCopy the code
public class CommentResponse { private Integer errorCode; private String errorMsg; private CommentBean date; } public class CommentBean { private int total; private int size; private List<CommentData> datas; class CommentData{ private int articleId; private boolean canEdit; private String content; private int id; private String niceDate; private Date publishDate; private int rootCommentId; private int status; private int toUserId; private String toUserName; private int userId; private String userName; private int zan; }}Copy the code
Note: rxjava | rxandroid version needs to be consistent, retrofit | rxjava versions; If inconsistent, an error is reported.
Two: Create V in the MVP
We know that a complete request process from the view view includes: show the loading box – > load data successfully (load failed) – > update UI(prompt user) – > close the loading box.
We can assume that this is the case for most requests, so we can encapsulate it as a base class view, IBaseView
-
Define the base class view IBaseView
package bule.souv.com.mvp_rxjava_retrofittest_master.base; /** * description: View base class * [email protected] */ public interface IBaseView<T> {/** * @descriptoin loading progress * @author dc * @date 2017/2/16 11:00 */ void showProgress(); /** * @descriptoin progress * @author dc * @date 2017/2/16 11:01 */ void disimissProgress(); /** * @descriptoin * @author dc * @param tData * @date 2017/2/16 11:01 */ void loadDataSuccess(T tData); /** * @descriptoin Request data error * @author dc * @param Throwable exception type * @date 2017/2/16 11:01 */ void loadDataError(throwable throwable); }Copy the code
These request steps are also public methods, and subclasses can inherit the base class to obtain these public methods, avoiding repeating the definition of each request’s child view
-
Define the WeatherView subclass view
Public Interface CommentView extends IBaseView<CommentResponse> {}Copy the code
Create a model in the MVP
M mainly deals with business data logic in MVP; Such as: network request data, database access data and so on.
What we’re doing here is commenting on data from the web
- Interface definition for CommentModel
支那
/** * */ public Interface CommentModel<T> {/** * @descriptoin */ void loadComment(String questionId, IBaseRequestCallBack<T> iBaseRequestCallBack); }Copy the code
QuestionId is used to get data and IBaseRequestCallBack is the data callback interface, which will be discussed below.
- IBaseRequestCallBack defines the callback interface for the data
支那
package bule.souv.com.mvp_rxjava_retrofittest_master.base; /** * Description: Callback interface used by Presenter to receive data from model [email protected] */ public interface IBaseRequestCallBack<T> {** * @descriptoin * @author dc * @date 2017/2/16 11:34 */ void beforeRequest(); /** * @descriptoin request exception * @author dc * @param throwable Exception type * @date 2017/2/16 11:34 */ void requestError(throwable throwable); /** * @descriptoin * @author dc * @date 2017/2/16 11:35 */ void requestComplete(); /** * @descriptoin request succeeded * @author dc * @param callBack return the corresponding data to the business * @date 2017/2/16 11:35 */ void requestSuccess(T) callBack); }Copy the code
The operation before the request is the same, the Throwable is used to handle the request exception information, and the operation after the request is completed is the same. Only the Object returned by the successful request is different. Here, the T generic type is used to specify different Object objects.
- Define apis for services in RetroFIT
支那
Public Interface CommentServiceApi {@get ("wenda/comments/{questionId}/json?" ) Observable<CommentInfoBean> loadCommentsInfo(@Query("questionId") String questionId); }Copy the code
The first thing to note here is that the requested interface address is not concatenated incorrectly using Retrofit. Two parameters are provided;
-
Define CommentImp that implements CommentModel
支那
public class CommentImp extends BaseModel implements CommentModel<CommentInfoBean> { private Context context = null; private CommentServiceApi commentServiceApi; private CompositeSubscription mCompositeSubscription; public CommentImp(Context mContext) { super(); context = mContext; commentServiceApi = retrofitManager.getService(); mCompositeSubscription = new CompositeSubscription(); } @Override public void loadComment(String questionId, final IBaseRequestCallBack iBaseRequestCallBack) { MCompositeSubscription. Add (mCompositeSubscription. LoadCommentsInfo (key, city) / / add the subscribe to the subscription, Used to cancel the subscribe. ObserveOn (AndroidSchedulers mainThread ()) / / the specified event thread consumption. SubscribeOn Schedulers. IO () () / / specifies the subscribe () happened in IO Subscribe (new Subscriber<WeatherInfoBean>() {@override public void onStart() {super.onstart (); //onStart it is always called on the thread that subscribes. If your subscribe is not the main thread, you will get an error and need to specify the thread. iBaseRequestCallBack.beforeRequest(); } @ Override public void onCompleted () {/ / callback interface: the request has been completed, the progress can be hidden iBaseRequestCallBack. RequestComplete (); } @ Override public void onError (Throwable e) {/ / callback interface: abnormal iBaseRequestCallBack request. RequestError (e); } @override public void onNext(WeatherInfoBean WeatherInfoBean) { Request is successful, access to the entity class object iBaseRequestCallBack. RequestSuccess (weatherInfoBean); }})); } @Override }Copy the code
Because the interface CommentModel is implemented, two methods of the interface are also implemented.
Create P in MVP
P in MVP is primarily a bridge between view V and mode M.
-
Define the CommentPresenter interface
支那
package bule.souv.com.mvp_rxjava_retrofittest_master.presenter; /** * MVP P interface definition */ public interface CommentPresenter {/** * @descriptoin Request comment data * @author dc * @return */ void loadWeather(String questionId); }Copy the code
-
Define the base class for Presenter
In IBaseCallBack, we define several callback methods that handle the result before and after the request. We can also create a base class for Presenter to bridge the difference between M and V (because it is a common method). Because of the different M and V objects, we also use generics instead
支那
package bule.souv.com.mvp_rxjava_retrofittest_master.base; /** * Description: ** Basic implementation of proxy objects: some basic methods ** @param <V> View interface object (view) concrete business each inherits from IBaseView * @param <T> business request return concrete object * Dc on 2017/2/16 15:07 * [email protected] */ public class BasePresenterImp<V extends IBaseView , T> implements IBaseRequestCallBack<T> { private IBaseView iBaseView = null; // Base class view /** * @descriptoin constructor * @author dc * @param view Business view interface object * @date 2017/2/16 15:12 */ public BasePresenterImp(V view) { this.iBaseView = view; } /** * @descriptoin progress * @author dc * @date 2017/2/16 15:13 */ @override public void beforeRequest() { iBaseView.showProgress(); } /** * @descriptoin Request exception Display exception information * @author dc * @param throwable Exception information * @date 2017/2/16 15:13 */ @override public void requestError(Throwable throwable) { iBaseView.loadDataError(throwable); iBaseView.disimissProgress(); // Request error, Progress * @author dc * @date 2017/2/16 15:14 */ @override public void Description progress * @author dc * @date 2017/2/16 15:14 */ @override public void Description requestComplete() { iBaseView.disimissProgress(); } /** * @descriptoin Request succeeded Get the data after the request succeeded * @author dc * @param callBack data * @date 2017/2/16 15:14 */ @override public void requestSuccess(T callBack) { iBaseView.loadDataSuccess(callBack); }}Copy the code
As you can see in the code, there is a basic implementation of the popbox before loading, a callback to the UI if loading succeeds, an error message to the UI if loading fails, a popbox closing when loading completes, etc. (that’s why we define a base class).
Here we use two generic types V and T, where V represents different views and T represents different objects. By passing different V’s and T’s to different presenters, you can bridge different view V’s and different model M’s through the base class
- Implement CommentPresenterImp for the CommentPresenter interface
支那
public class CommentPresenterImp extends BasePresenterImp<CommentView,WeatherInfoBean> implements CommentPresenter { // Passing the generics V and T as CommentView and CommentInfoBean, respectively, to bridge the gap between the two. privateCommentModelImp commentModelImp = null; /** * @descriptoin constructor * @param view Business view interface object * @author dc * @date 2017/2/16 15:12 */ publicCommentPresenterImp(CommentrView view, Context context) { super(view); this.context = context; this.commentModelImp = new CommentrModelImp(context); } @Override public void loadComment(String questionid ) { commentModelImp.loadComment(questionid, this); }}Copy the code
In the class definition code we inherit the base class BasePresenterImp and pass in the generics V and T as CommentView and CommentInfoBean to bridge the two
And because we implement the IBaseCallBack callback method in BasePresenterImp, we call different methods in BasePresenterImp through the callback interface after the Model request, and we handle view V’s interface in different methods. Thus, P establishes a bridge between M’s data processing and V’s view display processing
An implementation of an Activity or Fragment
The code handling here is very simple, because the benefits of MVP relate to the benefits of separating activity M and V.
支那
package bule.souv.com.mvp_rxjava_retrofittest_master; import android.app.ProgressDialog; import android.os.Bundle; import android.support.design.widget.FloatingActionButton; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.View; import android.widget.Button; import android.widget.TextView; import bule.souv.com.mvp_rxjava_retrofittest_master.bean.WeatherInfoBean; import bule.souv.com.mvp_rxjava_retrofittest_master.presenter.WeatherPresenterImp; import bule.souv.com.mvp_rxjava_retrofittest_master.view.WeatherView; import butterknife.Bind; import butterknife.ButterKnife; import butterknife.OnClick; public class MainActivity extends AppCompatActivity implements WeatherView{ @Bind(R.id.toolbar) Toolbar toolbar; @Bind(R.id.main_getweather_temp_btn) Button mainGetweatherTempBtn; @Bind(R.id.main_showweather_temp_tv) TextView mainShowweatherTempTv; @Bind(R.id.fab) FloatingActionButton fab; /** / private WeatherPresenterImp WeatherPresenterImp = null; private ProgressDialog progressDialog = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); setSupportActionBar(toolbar); init(); } /** * @descriptoin click to get temperature * @author * @param * @date 2017/2/16 15:52 * @return */ @OnClick(R.id.main_getweather_temp_btn) public void setOnClickRequestWeatherBtn(){ WeatherPresenterImp. LoadWeather (" c5bb749112664353af44bc99ed263857 ", "changsha"); } /** * @descriptoin initializer * @author dc * @date 2017/2/16 15:44 */ private void init(){weatherPresenterImp = new WeatherPresenterImp(this,this); progressDialog = new ProgressDialog(MainActivity.this); // progressDialog.setTitle(); ProgressDialog. SetMessage (" is requesting access to data, please wait!!!!!!" ); } @Override public void showProgress() { if(progressDialog ! = null && ! progressDialog.isShowing()){ progressDialog.show(); } } @Override public void disimissProgress() { if(progressDialog ! = null && progressDialog.isShowing()){ progressDialog.dismiss(); } } @Override public void loadDataSuccess(WeatherInfoBean tData) { String temperature = tData.getResult().getRealtime().getWeather().getTemperature(); mainShowweatherTempTv.setVisibility(View.VISIBLE); MainShowweatherTempTv. SetText (" the current temperature is: "+ +" ℃ temperature); } @Override public void loadDataError(Throwable throwable) { String errorMsg = throwable.getMessage(); mainShowweatherTempTv.setVisibility(View.VISIBLE); mainShowweatherTempTv.setText(errorMsg); } @Override protected void onStop() { super.onStop(); / / in the exit after the cancellation of the subscribe weatherPresenterImp. UnSubscribe (); }}Copy the code