5、 定义MainPresenter,并继承BasePresenter
public class MainPresenter extends BasePresenter<MainView> { public MainPresenter(MainView baseView) { super(baseView); } /** * 演示 文件上传进度监听 * * @param url */ public void upLoadVideoApi(String url) { HashMap<String, RequestBody> params = new HashMap<>(); params.put("fileType", RetrofitUtil.convertToRequestBody("video")); MultipartBody.Part parts = MultipartBody.Part.createFormData("file", new File(url).getName(), new ProgressRequestBody(new File(url),"video/mpeg", baseView)); ApiServer apiServer = ApiRetrofit.getBaseUrlInstance("https://bjlzbt.com/").getApiService(); addFileDisposable(apiServer.getUpload(params, parts), new FileObserver(baseView) { @Override public void onSuccess(Object o) { baseView.onUpLoadImgSuccess((BaseModel<Object>) o); } @Override public void onError(String msg) { if (baseView != null) { baseView.showError(msg); } } }); } }
6、 在Activity中进行网络请求,如下
public class MainActivity extends BaseActivity<MainPresenter> implements MainView { @Override protected MainPresenter createPresenter() { return new MainPresenter(this); } @Override protected int getLayoutId() { return R.layout.activity_main; } @Override protected void initData() { //文件上传 mPresenter.upLoadVideoApi(BaseContent.baseFileName+"ceshi.mp4"); } @Override public void onUpLoadImgSuccess(BaseModel<Object> o) { L.e("文件视频路径==" + o.getResult()); } }
7、 有人会问,说好的进度条去哪了?
进度条已封装到BaseActivity中了,相关代码如下
@Override public void showProgress() { if (progressDialog == null) { progressDialog = new ProgressDialog(this); } progressDialog.getProgressBar().performAnimation(); if (!progressDialog.isShowing()) { progressDialog.show(); } } @Override public void hideProgress() { if (progressDialog != null) { progressDialog.getProgressBar().releaseAnimation(); progressDialog.dismiss(); } } @Override public void onProgress(int progress) { if (progressDialog != null) { progressDialog.updateProgress(progress); } }
六、Retrofit文件下载(含进度条)
1、 FileObserver封装,文件上传下载时所用
如上
2、定义接口
public interface ApiServer { /** * 大文件官方建议用 @Streaming 来进行注解,不然会出现IO异常,小文件可以忽略不注入 */ @Streaming @GET Observable<ResponseBody> downloadFile(@Url String fileUrl); }
3、 定义MainView,并继承BaseView
public interface MainView extends BaseView { void onFileSuccess(File file); }
4、 定义MainPresenter,并继承BasePresenter
public class MainPresenter extends BasePresenter<MainView> { public MainPresenter(MainView baseView) { super(baseView); public void downFile(String url, final String destFileDir, final String destFileName) { ApiServer apiServer = ApiRetrofit.getFileInstance(baseView).getApiService(); Observable<String> observable = apiServer.downloadFile(url).map(new Function<ResponseBody, String>() { @Override public String apply(ResponseBody body) throws Exception { File file = FileUtil.saveFile(destFileDir+destFileName, body); return file.getPath(); } }); addFileDisposable(observable, new FileObserver(baseView) { @Override public void onSuccess(Object o) { baseView.onFileSuccess(new File(o.toString())); } @Override public void onError(String msg) { if (baseView != null) { baseView.showError(msg); } } }); } } }
5、创建Retrofit来实现进度条
说明:本人思路是通过okhttp拦截器拦截来检测文件下载进度,相关代码已放入到创建Retrofit中,详情请看Demo,demo封装为只有文件下载okhttp才会添加ProgressInterceptor下载进度监听,如下所示(okhttp添加)
/** * 文件处理 * * @param httpClientBuilder */ public void initFileClient(OkHttpClient.Builder httpClientBuilder) { /** * 处理文件下载进度展示所需 */ httpClientBuilder.addNetworkInterceptor(new ProgressInterceptor()); } /** * 文件下载进度拦截 */ public class ProgressInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); if (mBaseView != null) { Response response = chain.proceed(request); return response.newBuilder().body(new ProgressResponseBody(response.body(), new ProgressResponseBody.ProgressListener() { @Override public void onProgress(long totalSize, long downSize) { int progress = (int) (downSize * 100 / totalSize); if (mBaseView != null) { mBaseView.onProgress(progress); L.e("文件下载速度 === " + progress); } } })).build(); } else { return chain.proceed(request); } } }
6、 在Activity中进行网络请求,如下
public class MainActivity extends BaseActivity<MainPresenter> implements MainView { @Override protected MainPresenter createPresenter() { return new MainPresenter(this); } @Override protected int getLayoutId() { return R.layout.activity_main; } @Override protected void initData() { //文件上传 String url = "https://bjlzbt.com/upload/default//20190725//c13948258c6ef6a36cbe2d3322b98f5c.mp4"; if (FileUtils.createOrExistsDir(BaseContent.baseFileName)) {//删除此行代码也可以 mPresenter.downFile(url, BaseContent.baseFileName, "ceshi.mp4"); } } @Override public void onUpLoadImgSuccess(BaseModel<Object> o) { L.e("文件视频路径==" + o.getResult()); } }
七、Retrofit,Gson解析,请求返回的类型不统一,假如double返回的是null
现实开发中,往往会遇到后台返回数据格式不规范情况,比如前端字段原本定义为int类型,而数据返回为空,如果用Gson解析会导致解析失败,比如字段定义为double类型,而返回的格式为字符串null,导致解析失败等等(只在后台返回数据格式不规范情况下出现,如果后台返回格式规范并不用考虑此问题)
1、 实现目标
1、格式化数据不规范【格式化int类型数据】
2、格式化数据不规范【格式化Long类型数据】
3、格式化数据不规范【格式化Double类型数据】
4、格式化数据不规范【格式化String类型数据】
5、格式化数据不规范【格式化Null类型数据】
2、 添加格式化工具方法到Gson解析中
if (gson == null) { gson = new GsonBuilder() .registerTypeAdapter(Integer.class, new IntegerDefaultAdapter()) .registerTypeAdapter(int.class, new IntegerDefaultAdapter()) .registerTypeAdapter(Double.class, new DoubleDefaultAdapter()) .registerTypeAdapter(double.class, new DoubleDefaultAdapter()) .registerTypeAdapter(Long.class, new LongDefaultAdapter()) .registerTypeAdapter(long.class, new LongDefaultAdapter()) .registerTypeAdapter(String.class, new StringNullAdapter()) .create(); } return gson; } public ApiRetrofit() { OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder(); httpClientBuilder .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS) .writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS) .readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS) .retryOnConnectionFailure(true);//错误重联 retrofit = new Retrofit.Builder() .baseUrl(BASE_SERVER_URL) .addConverterFactory(GsonConverterFactory.create(buildGson()))//添加json转换框架buildGson()根据需求添加 //支持RxJava2 .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .client(httpClientBuilder.build()) .build(); apiServer = retrofit.create(ApiServer.class); }
3、 对double类型处理,返回“”,或“null”,动态更改为默认值0.00,新建DoubleDefaultAdapter类
public class DoubleDefault0Adapter implements JsonSerializer<Double>, JsonDeserializer<Double> { @Override public Double deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { try { if (json.getAsString().equals("") || json.getAsString().equals("null")) {//定义为double类型,如果后台返回""或者null,则返回0.00 return 0.00; } } catch (Exception ignore) { } try { return json.getAsDouble(); } catch (NumberFormatException e) { throw new JsonSyntaxException(e); } } @Override public JsonElement serialize(Double src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src); } }
4、 对int类型处理,返回“”,或“null”,动态更改为默认值0,新建DoubleDefaultAdapter类
public class IntegerDefaultAdapter implements JsonSerializer<Integer>, JsonDeserializer<Integer> { @Override public Integer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { try { if (json.getAsString().equals("") || json.getAsString().equals("null")) {//定义为int类型,如果后台返回""或者null,则返回0 return 0; } } catch (Exception ignore) { } try { return json.getAsInt(); } catch (NumberFormatException e) { throw new JsonSyntaxException(e); } } @Override public JsonElement serialize(Integer src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src); } }
5、 对Long类型处理,返回“”,或“null”,动态更改为默认值0,新建DoubleDefaultAdapter类
public class LongDefault0Adapter implements JsonSerializer<Long>, JsonDeserializer<Long> { @Override public Long deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { try { if (json.getAsString().equals("") || json.getAsString().equals("null")) {//定义为long类型,如果后台返回""或者null,则返回0 return 0l; } } catch (Exception ignore) { } try { return json.getAsLong(); } catch (NumberFormatException e) { throw new JsonSyntaxException(e); } } @Override public JsonElement serialize(Long src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src); } }
5、 重点说一下String类型
根据上边其他类型处理代码可以看出,String也就是把上述类中代码改成String就可以了,答案是可以的,如下,处理的内容为如果服务器返回字符串类型“null”,我们将其格式化成“”,空类型,但是我们为什么不直接写,请往下看
public class StringDefaultConverter implements JsonSerializer<String>, JsonDeserializer<String> { @Override public String deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { try { if (json.getAsString().equals("null")) { return ""; } } catch (Exception ignore) { } try { return json.getAsJsonPrimitive().getAsString(); } catch (NumberFormatException e) { throw new JsonSyntaxException(e); } } @Override public JsonElement serialize(String src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src); } }
但是有种比较常见的不规范数据返回,为null,不是字符串的"null",是这个null,如果返回null,会进入到上边这个类吗,经过测试,返回null的直接跳过,所以出现了个问题,null到底是什么类型?
通过读源码可知,我们可以自定义TypeAdapter,将其放入facotries中,并且gson在解析json时使用对应的TypeAdapter来的,而我们手动添加的TypeAdapter会优先于预设的TypeAdapter被使用。
于是乎找到了一种其他方法来解决这个问题
新建个类来集成TypeAdapter,这样就便优先于预设的TypeAdapter
public class StringNullAdapter extends TypeAdapter<String> { @Override public String read(JsonReader reader) throws IOException { if (reader.peek() == JsonToken.NULL) { reader.nextNull(); return "";//原先是返回Null,这里改为返回空字符串 } String jsonStr = reader.nextString(); if(jsonStr.equals("null")) { return ""; }else { return jsonStr; } } @Override public void write(JsonWriter writer, String value) throws IOException { if (value == null) { writer.nullValue(); return; } writer.value(value); } }
定义的类型为String,这样为null的情况会都归这个类来处理,但是String的所有情况也会走里边的方法,所以为了同样的类型不执行俩遍,String和null都在此类处理,就没必要写上边那个方法了, 处理所有情况为返回null,或字符串"null",格式化为"" 空
八、Retrofit实现cookie自动化管理
在现实开发中,我们可能会遇到这样的需求,需要保持长登陆状态,登陆失效为服务器判断,在我们不想往接口添加任何参数处理时,我们便想到cookie
最终实现效果为:登录成功后将将服务器返回的cookie保存到本地(每次接口请求成功,更新本地保存Cookie值,目的让本地的cookie值一直为最新的),下次请求接口时将本地最新cookie带上,用来告诉哪个用户与服务器之间的交互
1、 第一种实现方方法(第三方库实现Cookie自动化管理)
(1)依赖第三方库
implementation 'com.github.franmontiel:PersistentCookieJar:v1.0.1'
(2)创建OkHttpClient时添加cookieJar
PersistentCookieJar cookieJar = new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(context)); OkHttpClient okHttpClient = new OkHttpClient().newBuilder() .connectTimeout(10, TimeUnit.SECONDS) .readTimeout(20, TimeUnit.SECONDS) .addInterceptor(new LoginInterceptor()) .cookieJar(cookieJar)// 设置封装好的cookieJar .build();
2、 第二种实现方方法(手写cookie管理类),自我操控性强
(1)创建CookieManger类
public class CookieManger implements CookieJar { private static Context mContext; private static PersistentCookieStore cookieStore; public CookieManger(Context context) { mContext = context; if (cookieStore == null) { cookieStore = new PersistentCookieStore(mContext); } } @Override public void saveFromResponse(HttpUrl url, List<Cookie> cookies) { if (cookies != null && cookies.size() > 0) { for (Cookie item : cookies) { cookieStore.add(url, item); if (item.name() != null && !TextUtils.isEmpty(item.name()) && item.value() != null && !TextUtils.isEmpty(item.value())) { /*保存cookie到sp地方 可能会用到 */ // PrefUtils.setString(mContext, "cookie_name", item.name()); // PrefUtils.setString(mContext, "cookie_value", item.value()); } } } } @Override public List<Cookie> loadForRequest(HttpUrl url) { List<Cookie> cookies = cookieStore.get(url); for (int i = 0; i < cookies.size(); i++) { Log.e("", "拿出来的cookies name()==" + cookies.get(i).name()); Log.e("", "拿出来的cookies value()==" + cookies.get(i).value()); } return cookies; } }
(2)创建OkHttpCookies类
public class OkHttpCookies implements Serializable { private transient final Cookie cookies; private transient Cookie clientCookies; public OkHttpCookies(Cookie cookies) { this.cookies = cookies; } public Cookie getCookies() { Cookie bestCookies = cookies; if (clientCookies != null) { bestCookies = clientCookies; } return bestCookies; } private void writeObject(ObjectOutputStream out) throws IOException { out.writeObject(cookies.name()); out.writeObject(cookies.value()); out.writeLong(cookies.expiresAt()); out.writeObject(cookies.domain()); out.writeObject(cookies.path()); out.writeBoolean(cookies.secure()); out.writeBoolean(cookies.httpOnly()); out.writeBoolean(cookies.hostOnly()); out.writeBoolean(cookies.persistent()); } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { String name = (String) in.readObject(); String value = (String) in.readObject(); long expiresAt = in.readLong(); String domain = (String) in.readObject(); String path = (String) in.readObject(); boolean secure = in.readBoolean(); boolean httpOnly = in.readBoolean(); boolean hostOnly = in.readBoolean(); boolean persistent = in.readBoolean(); Cookie.Builder builder = new Cookie.Builder(); builder = builder.name(name); builder = builder.value(value); builder = builder.expiresAt(expiresAt); builder = hostOnly ? builder.hostOnlyDomain(domain) : builder.domain(domain); builder = builder.path(path); builder = secure ? builder.secure() : builder; builder = httpOnly ? builder.httpOnly() : builder; clientCookies =builder.build(); } }
(3)创建PersistentCookieStore类
public class PersistentCookieStore { private static final String LOG_TAG = "PersistentCookieStore"; private static final String COOKIE_PREFS = "Cookies_Prefs"; private final Map<String, ConcurrentHashMap<String, Cookie>> cookies; private final SharedPreferences cookiePrefs; public PersistentCookieStore(Context context) { cookiePrefs = context.getSharedPreferences(COOKIE_PREFS, 0); cookies = new HashMap<>(); //将持久化的cookies缓存到内存中 即map cookies Map<String, ?> prefsMap = cookiePrefs.getAll(); for (Map.Entry<String, ?> entry : prefsMap.entrySet()) { String[] cookieNames = TextUtils.split((String) entry.getValue(), ","); for (String name : cookieNames) { String encodedCookie = cookiePrefs.getString(name, null); if (encodedCookie != null) { Cookie decodedCookie = decodeCookie(encodedCookie); if (decodedCookie != null) { if (!cookies.containsKey(entry.getKey())) { cookies.put(entry.getKey(), new ConcurrentHashMap<String, Cookie>()); } cookies.get(entry.getKey()).put(name, decodedCookie); } } } } } protected String getCookieToken(Cookie cookie) { return cookie.name() + "@" + cookie.domain(); } public void add(HttpUrl url, Cookie cookie) { String name = getCookieToken(cookie); //将cookies缓存到内存中 如果缓存过期 就重置此cookie if (!cookie.persistent()) { if (!cookies.containsKey(url.host())) { cookies.put(url.host(), new ConcurrentHashMap<String, Cookie>()); } cookies.get(url.host()).put(name, cookie); } else { if (cookies.containsKey(url.host())) { cookies.get(url.host()).remove(name); } } //讲cookies持久化到本地 SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); prefsWriter.putString(url.host(), TextUtils.join(",", cookies.get(url.host()).keySet())); prefsWriter.putString(name, encodeCookie(new OkHttpCookies(cookie))); prefsWriter.apply(); } public List<Cookie> get(HttpUrl url) { ArrayList<Cookie> ret = new ArrayList<>(); if (cookies.containsKey(url.host())) { ret.addAll(cookies.get(url.host()).values()); } return ret; } public boolean removeAll() { SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); prefsWriter.clear(); prefsWriter.apply(); cookies.clear(); return true; } public boolean remove(HttpUrl url, Cookie cookie) { String name = getCookieToken(cookie); if (cookies.containsKey(url.host()) && cookies.get(url.host()).containsKey(name)) { cookies.get(url.host()).remove(name); SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); if (cookiePrefs.contains(name)) { prefsWriter.remove(name); } prefsWriter.putString(url.host(), TextUtils.join(",", cookies.get(url.host()).keySet())); prefsWriter.apply(); return true; } else { return false; } } public List<Cookie> getCookies() { ArrayList<Cookie> ret = new ArrayList<>(); for (String key : cookies.keySet()) { ret.addAll(cookies.get(key).values()); } return ret; } /** * cookies 序列化成 string * * @param cookie 要序列化的cookie * @return 序列化之后的string */ protected String encodeCookie(OkHttpCookies cookie) { if (cookie == null) { return null; } ByteArrayOutputStream os = new ByteArrayOutputStream(); try { ObjectOutputStream outputStream = new ObjectOutputStream(os); outputStream.writeObject(cookie); } catch (IOException e) { Log.d(LOG_TAG, "IOException in encodeCookie", e); return null; } return byteArrayToHexString(os.toByteArray()); } /** * 将字符串反序列化成cookies * * @param cookieString cookies string * @return cookie object */ protected Cookie decodeCookie(String cookieString) { byte[] bytes = hexStringToByteArray(cookieString); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); Cookie cookie = null; try { ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); cookie = ((OkHttpCookies) objectInputStream.readObject()).getCookies(); } catch (IOException e) { Log.d(LOG_TAG, "IOException in decodeCookie", e); } catch (ClassNotFoundException e) { Log.d(LOG_TAG, "ClassNotFoundException in decodeCookie", e); } return cookie; } /** * 二进制数组转十六进制字符串 * * @param bytes byte array to be converted * @return string containing hex values */ protected String byteArrayToHexString(byte[] bytes) { StringBuilder sb = new StringBuilder(bytes.length * 2); for (byte element : bytes) { int v = element & 0xff; if (v < 16) { sb.append('0'); } sb.append(Integer.toHexString(v)); } return sb.toString().toUpperCase(Locale.US); } /** * 十六进制字符串转二进制数组 * * @param hexString string of hex-encoded values * @return decoded byte array */ protected byte[] hexStringToByteArray(String hexString) { int len = hexString.length(); byte[] data = new byte[len / 2]; for (int i = 0; i < len; i += 2) { data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character.digit(hexString.charAt(i + 1), 16)); } return data; } }
(4)创建OkHttpClient时添加cookieJar
OkHttpClient okHttpClient = new OkHttpClient().newBuilder() .connectTimeout(10, TimeUnit.SECONDS) .readTimeout(20, TimeUnit.SECONDS) .addInterceptor(new LoginInterceptor()) .cookieJar(new CookieManger (context))// 设置封装好的cookieJar .build();
九、路由判断第二种解决方案(文章为旧版,只提供思路)
上述文章提到了路由这个概念,其实自己命名的,实际意义和这个此比较契合,本文章目的只服务器下发数据,当我们得到的值代表数据正常,(比如code=0数据正常),我们会正常执行我们的解析数据并处理显示数据内容等操作,如果服务器下发的数据为异常信息,前端只需要个提示操作,这样我们就没必要执行解析+显示等操作,所以我们会想到怎样可以一次性判断,终身不用管走向呢?
1、 第一种判断方法,在Rxjava的OnNext中判断
@Override public void onNext(BaseModel<T> o) { T t = o.getData(); try { /* if (t!=null){ L.e("返回数据="+o.toString()); }else { L.e("返回数据=null"); }*/ if (view != null) { view.hideLoading(); } if (o.getErrcode() == mSuccessCode) { onSuccess(t, o.getMsg(), o.getErrcode()); } else { view.onErrorCode(o); } } catch (Exception e) { e.printStackTrace(); onError(e.toString()); } }
当我们执行到OnNext方法中,此时已经执行了Gson解析代码,所以我们是否可以将判断提前到Gson解析时候判断呢? 请看第二种方法
2、 第二种判断方法,Gson解析期间判断
如果想通过Gson解析期间判断,这样必然会设计到Gson源码如果走向,我们通过更改源码来自定义操作,通过阅读源码我们会发现解析数据会涉及到三个类,GsonConverterFactory
,GsonRequestBodyConverter
,GsonResponseBodyConverter
这三个类,我们需要重写这个三个类,阅读代码会返现主要执行解析代码在GsonResponseBodyConverter
中,所以我们的目标便是这里。
思路:Gosn解析数据时,如果出现服务器下发非正常标识,此刻我们已判断服务器返回数据不是我们需要展示的,那我们解析到这一步已不用再向下解析,可以通过抛异常来释放当前任务代码如下
@Override public T convert(ResponseBody value) throws IOException { String response = value.string(); BaseResult re = gson.fromJson(response, BaseResult.class); //关注的重点,自定义响应码中非0的情况,一律抛出ApiException异常。 //这样,我们就成功的将该异常交给onError()去处理了。 if (re.getCode() != BaseContent.basecode) { value.close(); throw new ApiException(re.getCode(), re.getMessage()); } MediaType mediaType = value.contentType(); Charset charset = mediaType != null ? mediaType.charset(UTF_8) : UTF_8; ByteArrayInputStream bis = new ByteArrayInputStream(response.getBytes()); InputStreamReader reader = new InputStreamReader(bis, charset); JsonReader jsonReader = gson.newJsonReader(reader); try { return adapter.read(jsonReader); } finally { value.close(); } }
异常已成功抛出,那异常信息到哪里了呢?答案是到Rxjava的OnError中,异常我们抛的是自定义实体类ApiException
,内含code,message,那我们到Rxjava中OnError获取到异常信息 e,e instanceof ApiException
通过分析异常是否为我们自定义实体类来判断下一步如何操作,此方法为路由的第二种判断,示例如下
@Override public void onError(Throwable e) { if (view != null) { view.hideLoading(); } if (e instanceof HttpException) { // HTTP错误 onException(BAD_NETWORK, ""); } else if (e instanceof ConnectException || e instanceof UnknownHostException) { // 连接错误 onException(CONNECT_ERROR, ""); } else if (e instanceof InterruptedIOException) { // 连接超时 onException(CONNECT_TIMEOUT, ""); } else if (e instanceof JsonParseException || e instanceof JSONException || e instanceof ParseException) { // 解析错误 onException(PARSE_ERROR, ""); e.printStackTrace(); //这里 } else if (e instanceof ApiException) { ApiException exception = (ApiException) e; int code = exception.getErrorCode(); switch (code) { //未登录(此处只是案例 供理解) case CONNECT_NOT_LOGIN: view.onErrorCode(new BaseModel(exception.getMessage(), code)); onException(CONNECT_NOT_LOGIN, ""); break; //其他不等于0 的所有状态 default: onException(OTHER_MESSAGE, exception.getMessage()); view.onErrorCode(new BaseModel(exception.getMessage(), code)); break; } } else { if (e != null) { onError(e.toString()); } else { onError("未知错误"); } } }
十、Retrofit配置及各情况处理(缓存拦截、日志打印、替换接口内容、参数添加等
十一、后记
一、问:这样封装每个Activity对应一个Presenter,有些接口会多次用不想多次写
答:onCreate随便写
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); MainPresenter1 presenter1 = new MainPresenter1(this); presenter.getTextApi(); MainPresenter2 presenter2 = new MainPresenter2(this); presenter2.getTextApi(); MainPresenter3 presenter3 = new MainPresenter3(this); presenter3getTextApi(); }
二、问:有人问dialog加载圈封装的不够好,这样每个接口都得显示加载圈,不想实现都不行
答:BaseActivity和BaseFragment中都有这俩个方法
//显示加载进度框回调 @Override public void showLoading() { showLoadingDialog(); } //隐藏进度框回调 @Override public void hideLoading() { closeLoadingDialog(); }
如果说我本页面都不想显示Loading动画,那就在对应的Activity重写下父类的方法,比如
@Override public void showLoading() { // super.showLoading(); //将super去掉 就不会显示Loading动画了 }
如果我们需要显示就在对应的Fragment调用请求方法之后手动掉一下父类的显示Loading方法,如下:
mPresenter.collectApi("id"); showLoadingDialog();
三、问:假如接口返回1001,代表重写登录或者token失效,我想在对应activity拿到状态或者做统一操作
答:可以在BaseActivity判断跳页面
//BaseActivity代码 @Override public void onErrorCode(BaseModel model) { if (model.getErrcode() == 1001) { startLogin(); } } private void startLogin() { startActivity(LoginActivity.class); }
如果想在对应Activity操作,那就在对应Activity重写此方法
//对应Activity代码 @Override public void onErrorCode(BaseModel model) { //super.onErrorCode(model); if (model.getErrcode()==1001){ //............................................ }else if (model.getErrcode()==1002){ //............................................ } }
github地址:https://github.com/LPTim/MVP-Retrofit2-okhttp3-Rxjava