안 드 로 이 드 Rxjava 2.0 + Retrofit 2.0 + Mvp 패키지 직접 가 져 가서 간단 한 데모 로 3 분 동안 철저하게 습득
https://blog.csdn.net/WHB20081815/article/details/68948856
mvp, MVC 의 차이 점
MVP 의 장단 점
1. MVP 구조 에서 View 와 Model 간 의 결합 을 해제 하여 서로 접근 할 수 없 게 하고 핵심 적 인 업무 논 리 는 모두 Presenter 에 집중 된다.
MVP 모드 는 Activity 의 비 즈 니스 논 리 를 모두 분리 해 Activity 가 UI 논리 로 만 처리 하도록 하고, Android API 와 무관 한 모든 비 즈 니스 논 리 는 Presenter 층 에서 수행한다.
2. 결합 감소, 유지 보수 용이
MVP 는 코드 의 간결 함 을 실현 하 는 동시에 대량의 인터페이스, 클래스 를 추가 하여 관리 하기 가 불편 하 다
Model 에서 한 단계 작업 을 할 때 얻 은 결 과 는 Presenter 를 통 해 View 로 전 달 될 때 View 가 인용 한 빈 포인터 이상 이 발생 합 니 다.
Presenter 와 View 는 서로 인용 을 가지 고 있 으 며, 제때에 제거 하지 않 으 면 메모리 누 출 이 발생 하기 쉽다.
MVP 모드 적용
2.1 모델 층 설명 과 구체 적 인 코드
view 층 에 보 여 주 려 는 데이터 와 구체 적 인 로그 인 업무 논리 처리 의 실현 을 제공 합 니 다.
package com.nsu.edu.androidmvpdemo.login;
/**
* Created by Anthony on 2016/2/15.
* Class Note: , LoginModelImpl. MVP Model
*/
public interface LoginModel {
void login(String username, String password, OnLoginFinishedListener listener);
}
来源: https://www.jianshu.com/p/9d40b298eca9
package com.nsu.edu.androidmvpdemo.login;
import android.os.Handler;
import android.text.TextUtils;
/**
* Created by Anthony on 2016/2/15.
* Class Note: (2s), ,
*/
public class LoginModelImpl implements LoginModel {
@Override
public void login(final String username, final String password, final OnLoginFinishedListener listener) {
new Handler().postDelayed(new Runnable() {
@Override public void run() {
boolean error = false;
if (TextUtils.isEmpty(username)){
listener.onUsernameError();//model listener
error = true;
}
if (TextUtils.isEmpty(password)){
listener.onPasswordError();
error = true;
}
if (!error){
listener.onSuccess();
}
}
}, 2000);
}
}
2.2 view 계층 설명 과 구체 적 인 코드
데 이 터 를 표시 하고 우호 적 인 인터페이스 를 제공 하여 사용자 와 상호작용 을 하면 됩 니 다.MVP 에서 Activity 와 Fragment, View 의 하위 클래스 는 이 층 에 나타난다. Activity 는 보통 UI 보 기 를 불 러 오고 감청 을 설정 한 다음 에 Presenter 가 처리 하 는 작업 을 하기 때문에 해당 Presenter 의 인용 을 가 져 야 한다.이 층 에서 해 야 할 작업 은 매번 상응하는 상호작용 이 있 을 때마다 presenter 와 관련 된 방법 을 호출 하면 된다.(예 를 들 어 button 클릭)
package com.nsu.edu.androidmvpdemo.login;
/**
* Created by Anthony on 2016/2/15.
* Class Note: View , activity
*/
public interface LoginView {
void showProgress();
void hideProgress();
void setUsernameError();
void setPasswordError();
void navigateToHome();
}
package com.nsu.edu.androidmvpdemo.login;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Toast;
import com.nsu.edu.androidmvpdemo.R;
/**
* Created by Anthony on 2016/2/15.
* Class Note:MVP View activity, activity
*/
public class LoginActivity extends Activity implements LoginView, View.OnClickListener {
private ProgressBar progressBar;
private EditText username;
private EditText password;
private LoginPresenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
progressBar = (ProgressBar) findViewById(R.id.progress);
username = (EditText) findViewById(R.id.username);
password = (EditText) findViewById(R.id.password);
findViewById(R.id.button).setOnClickListener(this);
presenter = new LoginPresenterImpl(this);
}
@Override
protected void onDestroy() {
presenter.onDestroy();
super.onDestroy();
}
@Override
public void showProgress() {
progressBar.setVisibility(View.VISIBLE);
}
@Override
public void hideProgress() {
progressBar.setVisibility(View.GONE);
}
@Override
public void setUsernameError() {
username.setError(getString(R.string.username_error));
}
@Override
public void setPasswordError() {
password.setError(getString(R.string.password_error));
}
@Override
public void navigateToHome() {
// TODO startActivity(new Intent(this, MainActivity.class));
Toast.makeText(this,"login success",Toast.LENGTH_SHORT).show();
// finish();
}
@Override
public void onClick(View v) {
presenter.validateCredentials(username.getText().toString(), password.getText().toString());
}
}
2.3 presenter 계층 설명 과 구체 적 인 코드
Presenter 는 view 와 model 의 중간 층 역할 을 하고 있다.model 층 의 데 이 터 를 가 져 와 view 층 을 구축 합 니 다.view 층 UI 의 피드백 명령 을 받 은 후 처리 논 리 를 나 누 어 model 층 에 업무 수행 을 맡 길 수도 있 습 니 다.그것 도 View 층 의 각종 조작 을 결정 할 수 있다.
package com.nsu.edu.androidmvpdemo.login;
/**
* Created by Anthony on 2016/2/15.
* Class Note: Presenter , LoginPresenterImpl, , view
*/
public interface LoginPresenter {
void validateCredentials(String username, String password);
void onDestroy();
}
package com.nsu.edu.androidmvpdemo.login;
/**
* Created by Anthony on 2016/2/15.
* Class Note:
* 1 presenter 。 Model View 。
* 2 presenter OnLoginFinishedListener,
* Presenter , Model , View ,
* Model View 。 LoginPresenterImpl ,
* LoginPresenterImpl View Model Model View ?
*/
public class LoginPresenterImpl implements LoginPresenter, OnLoginFinishedListener {
private LoginView loginView;
private LoginModel loginModel;
public LoginPresenterImpl(LoginView loginView) {
this.loginView = loginView;
this.loginModel = new LoginModelImpl();
}
@Override
public void validateCredentials(String username, String password) {
if (loginView != null) {
loginView.showProgress();
}
loginModel.login(username, password, this);
}
@Override
public void onDestroy() {
loginView = null;
}
@Override
public void onUsernameError() {
if (loginView != null) {
loginView.setUsernameError();
loginView.hideProgress();
}
}
@Override
public void onPasswordError() {
if (loginView != null) {
loginView.setPasswordError();
loginView.hideProgress();
}
}
@Override
public void onSuccess() {
if (loginView != null) {
loginView.navigateToHome();
}
}
}
1 Activity 는 UI 초기 화 된 것 을 만 들 었 고 LoginPresenter 의 인용 과 LoginView 의 인 터 페 이 스 를 예화 해 야 합 니 다. 감청 인터페이스 동작 2 로그 인 단 추 를 누 르 면 로그 인 이 벤트 를 받 을 수 있 습 니 다. onClick 에서 받 으 면 LoginPresenter 의 인용 을 통 해 LoginPresenter 에 맡 깁 니 다.Login Presenter 는 로그 인 논 리 를 받 아들 이면 로그 인 3 을 알 수 있 습 니 다. 그리고 Login Presenter 는 진행 상황 을 표시 하고 논 리 를 우리 의 Model 에 맡 깁 니 다. 즉, 이 안의 Login Model 입 니 다. (Login Model 의 실현 류 Login Model Impl) 은 OnLogin Finished Listener, 즉 Login Presenter 자체 가 우리 에 게 전달 하 는 Model (Login Model) 입 니 다.4 LoginModel 이 논 리 를 처리 한 후, 결 과 는 OnLoginFinished Listener 리 셋 을 통 해 LoginPresenter 5 LoginPresenter 에 결 과 를 view 층 의 Activity 에 되 돌려 주 고, 마지막 activity 는 결 과 를 표시 합 니 다.
MVP 총괄:
presenter 패키지 view 와 Model
Activity 에는 presenter 와 view 가 포함 되 어 있 습 니 다.
화면 음악 p 더 좋 은 쓰기:
https://www.jianshu.com/p/063126f807d0
RxJava 2.0 + Retrofit 2.0 결합 사용
1 //rxjava +retrofit
implementation 'io.reactivex.rxjava2:rxjava:2.1.1'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
implementation 'com.squareup.retrofit2:converter-scalars:2.3.0'
implementation 'com. squareup. retrofit 2: adapter - rxjava 2: 2.3.0' / / 협조 rxjava 2
implementation 'com. squareup. okhtp 3: logging - interceptor: 3.8.1' / / 차단기
1. RetrofitClient 클 라 이언 트 구축.
public static RetrofitClient getInstance(Context context, String url) {
if (context != null) {
mContext = context;
}
sNewInstance = new RetrofitClient(context, url);
return sNewInstance;
}
private RetrofitClient(Context context) {
this(context, null);
}
private RetrofitClient(Context context, String url) {
if (TextUtils.isEmpty(url)) {
url = baseUrl;
}
okHttpClient = new OkHttpClient.Builder()
.addNetworkInterceptor(
new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.HEADERS))
.cookieJar(new NovateCookieManger(context))
.addInterceptor(new BaseInterceptor(mContext))
.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.build();
Retrofit retrofit = new Retrofit.Builder()
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl(url)
.build();
apiService = retrofit.create(ApiService.class);
}
2.
ApiService
API , , 。
/**
* Created by Tamic on 2016-07-08.
*/
public interface ApiService {
public static final String Base_URL = "http://ip.taobao.com/";
/**
*
*/
@GET("service/getIpInfo.php/")
Observable getData(@Query("ip") String ip);
@GET("{url}")
Observable executeGet(
@Path("url") String url,
@QueryMap Map maps);
@POST("{url}")
Observable executePost(
@Path("url") String url,
@QueryMap Map maps);
@Multipart
@POST("{url}")
Observable upLoadFile(
@Path("url") String url,
@Part("image\\\\"; filename=\\"image.jpg") RequestBody avatar);
@POST("{url}")
Observable uploadFiles(
@Path("url") String url,
@Path("headers") Map headers,
@Part("filename") String description,
@PartMap() Map maps);
@Streaming
@GET
Observable downloadFile(@Url String fileUrl);
}
public void getData(Subscriber subscriber, String ip) {
apiService.getData(ip)
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);
}
public void get(String url, Map headers, Map parameters, Subscriber subscriber) {
apiService.executeGet(url, headers, parameters)
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);
}
public void post(String url, Map headers, Map parameters, Subscriber subscriber) {
apiService.executePost(url, headers, parameters)
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);
}
, api , rxJava Transformer
Observable.Transformer schedulersTransformer() {
return new Observable.Transformer() {
@Override
public Object call(Object observable) {
return ((Observable) observable).subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
};
}
1
api :
public Subscription getData(Subscriber subscriber, String ip) {
return apiService.getData(ip)
.compose(schedulersTransformer())
.subscribe(subscriber);
}
RX 의 Transformer 용법 이 바로 위 에 있 습 니 다.
우 리 는 결 과 를 되 돌려 주 는 것 에 대해 예비 처 리 를 해 야 합 니 다. Default Transformer 를 새로 만 들 면 Observable. Transformer 를 계승 합 니 다. 예비 처 리 는 status 일 뿐 입 니 다.code 는 판단 과 해석 을 하고 서로 다른 오 류 는 서로 다른 오류 정 보 를 되 돌려 줍 니 다.연산 자 copose 가 있 습 니 다.우 리 는 모든 요청 에서 status 를 처리 하기 때문이다.code 와 일부 조작 자 를 사용 합 니 다. 예 를 들 어 observeon 과 subscribeOn 으로 스 레 드 를 전환 합 니 다.RxJava 는 Transformer (변환기) 를 제공 합 니 다. 일반적인 상황 에서 연산 자 copose () 를 사용 하여 이 루어 집 니 다.
여기 서 우 리 는 map 연산 자 를 사용 하여 Observable > 을 Observable 로 내부 에서 status 로 변환 합 니 다.코드 가 사전 처 리 됐 습 니 다.여기 서 상태 코드 가 10000 과 같 지 않 으 면 요청 오류 가 발생 하여 이상 을 던 집 니 다.이 곳 의 ApiException 은 서버 가 되 돌아 오 는 이상 을 처리 하기 위해 사용자 정의 이상 클래스 입 니 다.
public class DefaultTransformer implements Observable.Transformer {
@Override
public Observable call(Observable tObservable) {
return tObservable
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.map(new Func1() {// , code
@Override
public T call(T t) {
if (((BaseEntity)t).getStatus_code() != 10000) {
throw new ApiException(((BaseEntity)t).getStatus_code(), ((BaseEntity)t).getError_msg());
}
return t;
}
});
}
public static DefaultTransformer create() {
return new DefaultTransformer<>();
}
}
来源: https://www.jianshu.com/p/9364a9577c41
3.构建基础拦截器
责任链模式:很明显,在okhttp中的拦截器模块,执行过程用到。OkHttp3 的拦截器链中, 内置了5个默认的拦截器,分别用于重试、请求对象转换、缓存、链接、网络读写(责任链模式:为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。)
Interceptor 的设计是一种分层的思想,每个 Interceptor 就是一层。分层简化了每一层的逻辑,每层只需要关注自己的责任,而各层之间通过约定的接口/协议进行合作(面向接口编程思想),共同完成复杂的任务。
---------------------
本来
RetryAndFollowUpInterceptor:负责重定向。
BridgeInterceptor:负责把用户构造的请求转换为发送给服务器的请求,把服务器返回的响应转换为对用户友好的响应。
CacheInterceptor:负责读取缓存以及更新缓存。
ConnectInterceptor:负责与服务器建立连接。
CallServerInterceptor:负责从服务器读取响应的数据。
包含cookies的管理还有拦截器(自定义拦截器)
1.日志拦截器
2.缓存拦截器
3.网络拦截器:添加下载的头。拦截器
okHttpClient = new OkHttpClient.Builder()
.addNetworkInterceptor(
new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
.cookieJar(new NovateCookieManger(context))
.cache(cache)
.addInterceptor(new BaseInterceptor(headers))
.addInterceptor(new CaheInterceptor(context))
.addNetworkInterceptor(new CaheInterceptor(context))
header, MAP , heder Request 。
/**
* BaseInterceptor,use set okhttp call header
* Created by Tamic on 2016-06-30.
*/
public class BaseInterceptor implements Interceptor {
private Map headers;
public BaseInterceptor(Map headers) {
this.headers = headers;
}
@Override
public Response intercept(Chain chain) throws IOException {
Request.Builder builder = chain.request()
.newBuilder();
if (headers != null && headers.size() > 0) {
Set keys = headers.keySet();
for (String headerKey : keys) {
builder.addHeader(headerKey, headers.get(headerKey)).build();
}
}
return chain.proceed(builder.build());
}
}
마지막 호출 시 다음 과 같 습 니 다:
btn_get.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Map maps = new HashMap();
maps.put("ip", "21.22.11.33");
//"http://ip.taobao.com/service/getIpInfo.php?ip=21.22.11.33";
RetrofitClient.getInstance(MainActivity.this).createBaseApi().get("service/getIpInfo.php"
, maps, new BaseSubscriber(MainActivity.this) {
@Override
public void onError(ResponeThrowable e) {
Log.e("Lyk", e.getMessage());
Toast.makeText(MainActivity.this, e.getMessage(), Toast.LENGTH_LONG).show();
}
@Override
public void onNext(IpResult responseBody) {
Toast.makeText(MainActivity.this, responseBody.toString(), Toast.LENGTH_LONG).show();
}
});
}
});
btn_post.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Map maps = new HashMap();
maps.put("ip", "21.22.11.33");
//"http://ip.taobao.com/service/getIpInfo.php?ip=21.22.11.33";
RetrofitClient.getInstance(MainActivity.this).createBaseApi().post("service/getIpInfo.php"
, maps, new BaseSubscriber(MainActivity.this) {
@Override
public void onError(ResponeThrowable e) {
Log.e("Lyk", e.getMessage());
Toast.makeText(MainActivity.this, e.getMessage(), Toast.LENGTH_LONG).show();
}
@Override
public void onNext(ResponseBody responseBody) {
Toast.makeText(MainActivity.this, responseBody.toString(), Toast.LENGTH_LONG).show();
}
});
}
});
다음은 생명 주 기 를 관리 하 는 거 야.라 이 프 사이클 을 관리 할 수 있 는 전문 라 이브 러 리 가 있 습 니 다.
Rx Lifecycle, 가 보 셔 도 됩 니 다.하지만 우 리 는 이 걸 쓰 지 않 습 니 다. BaseActivity 에 쓰 겠 습 니 다.
public abstract class BaseActivity extends AppCompatActivity {
private CompositeSubscription mCompositeSubscription;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
protected void onDestroy() {
super.onDestroy();
onUnsubscribe();
}
/**
* rx , , detachView
*/
protected void addSubscription(Subscription subscribe) {
if (mCompositeSubscription == null)
mCompositeSubscription = new CompositeSubscription();
mCompositeSubscription.add(subscribe);
}
/**
*
*/
protected void onUnsubscribe() {
if (mCompositeSubscription != null && mCompositeSubscription.hasSubscriptions()) {
mCompositeSubscription.unsubscribe();
}
}
}
데 이 터 를 요청 하 는 곳 에서 addSubscription (Subscription subscribe) 방법 을 호출 합 니 다. activity 가 onDestroy () 에 있 을 때 구독 을 취소 합 니 다.
RxJava + Retrofit 2.0 프로젝트 실전 완벽 패키지
참고 블 로그:
https://blog.csdn.net/silenceoo/article/details/75037576
베 스 트
https://blog.csdn.net/u013651026/article/details/79294396
사실 Retrofit 의 전통 적 인 API 호출 은 okHTTP 기능 과 사용 에 있어 본질 적 인 차이 가 없고 RxJava 와 결합 하여 사용 하 는 것 이 강하 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
디자인 모델 의 공장 모델, 단일 모델자바 는 23 가지 디자인 모델 (프로 그래 밍 사상/프로 그래 밍 방식) 이 있 습 니 다. 공장 모드 하나의 공장 류 를 만들어 같은 인 터 페 이 스 를 실현 한 일부 종 류 를 인 스 턴 스 로 만 드 는 것...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.