首先列一下本篇文章要實(shí)現(xiàn)的功能
1.對(duì)服務(wù)器返回的數(shù)據(jù)進(jìn)行預(yù)處理
2.請(qǐng)求時(shí)帶上加載對(duì)話框医舆,對(duì)話框取消同時(shí)取消請(qǐng)求
一下以個(gè)人公司返回?cái)?shù)據(jù)為例,先上返回實(shí)體:
這里加一句如果返回分頁(yè)數(shù)據(jù)也是要被BaseModel包裹的 BaseModel<PageModel<T>> T可以是所有對(duì)象這個(gè)你們應(yīng)該懂得,分頁(yè)的話T一般是List<你的對(duì)象>夭拌。
接下來(lái)舉個(gè)例子
1.創(chuàng)建Retrofit 數(shù)據(jù)請(qǐng)求類(lèi)
public class SystemApi {
//超時(shí)時(shí)間
public static final int DEFAULT_TIMEOUT = 10;
private static Retrofit provideRetrofit() {
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BuildConfig.SERVER_HOST)//服務(wù)器項(xiàng)目地址
.addConverterFactory(JsonConverterFactory.create())//數(shù)據(jù)轉(zhuǎn)換器饺蚊,重寫(xiě)了下面有代碼
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(client)
.build();
return retrofit;
}
public static SystemApiService provideService() {
return provideRetrofit().create(SystemApiService.class);
}
}
2.數(shù)據(jù)轉(zhuǎn)換器重寫(xiě) 實(shí)現(xiàn)指哪打哪的效果 我要什么結(jié)果就什么結(jié)果 不給就報(bào)錯(cuò)去吧!H病狞换!自帶的不滿足我,具體什么原因忘記了,反正就重寫(xiě)了舟肉。
public class JsonConverterFactory extends Converter.Factory {
private final Gson gson;
private JsonConverterFactory(Gson gson) {
if (gson == null)
throw new NullPointerException("gson == null");
this.gson = gson;
}
public static JsonConverterFactory create() {
return create(new Gson());
}
public static JsonConverterFactory create(Gson gson) {
return new JsonConverterFactory(gson);
}
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new JsonResponseBodyConverter<>(gson, adapter);
}
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new JsonRequestBodyConverter<>(gson, adapter);
}
}
接下來(lái)實(shí)現(xiàn) response和request轉(zhuǎn)換
final class JsonRequestBodyConverter<T> implements Converter<T, RequestBody> {
private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8");
private static final Charset UTF_8 = Charset.forName("UTF-8");
private final Gson gson;
private final TypeAdapter<T> adapter;
JsonRequestBodyConverter(Gson gson, TypeAdapter<T> adapter) {
this.gson = gson;
this.adapter = adapter;
}
@Override
public RequestBody convert(T value) throws IOException {
Buffer buffer = new Buffer();
Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
JsonWriter jsonWriter = gson.newJsonWriter(writer);
adapter.write(jsonWriter, value);
jsonWriter.close();
return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
}
}
public final class JsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
private final Gson gson;
private final TypeAdapter<T> adapter;
public final static String JSON_ERROR_STR = "數(shù)據(jù)結(jié)構(gòu)異常!";
JsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
this.gson = gson;
this.adapter = adapter;
}
@Override
public T convert(ResponseBody value) throws IOException {
String response = value.string();
if (BuildConfig.DEBUG) {
LogUtil.i("NetData", response);
}
try {
InputStream inputStream = new ByteArrayInputStream(response.getBytes());
Reader reader = new InputStreamReader(inputStream);
JsonReader jsonReader = gson.newJsonReader(reader);
T t = adapter.read(jsonReader);
return t;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(JSON_ERROR_STR);
} finally {
value.close();
}
}
}
到這里底層的數(shù)據(jù)請(qǐng)求轉(zhuǎn)換就完成了修噪,接下來(lái)我們用 RxJava2 方式去請(qǐng)求一個(gè)接口
public interface SystemApiService {
//去服務(wù)器驗(yàn)證賬號(hào)是否存在,這里就不j介紹更多返回結(jié)果了路媚,反正如果是登陸就返回Observable<BaseModel<UserInfo>>黄琼,
//如果是獲取用戶(hù)列表分頁(yè)就是Observable<PageModel<List<UserInfo>>>
@FormUrlEncoded
@POST("authUserName")
Observable<BaseModel<Boolean>> authUserName(@FieldMap Map<String, Object> params);
}
接下來(lái)關(guān)鍵代碼來(lái)了,結(jié)果預(yù)處理整慎,不多少說(shuō)直接上代碼脏款,我這前面不寫(xiě)文章的围苫,寫(xiě)了你們也看不懂。
public class RxHelper {
/**
* 對(duì)結(jié)果進(jìn)行預(yù)處理
*
* @param <T>
* @return
*/
public static final <T> ObservableTransformer<BaseModel<T>, T> applySchedulers() {
return new ObservableTransformer<BaseModel<T>, T>() {
@Override
public ObservableSource apply(Observable upstream) {
return upstream.flatMap(new Function<BaseModel<T>, Observable<T>>() {
@Override
public Observable<T> apply(BaseModel<T> result) {
if (result.ifSuccess()) {//檢查是否掉接口成功了
return createData(result.getData());//成功撤师,剝?nèi)∥覀円臄?shù)據(jù)剂府,把BaseModel丟掉
} else {
return Observable.error(new Exception(result.getMsg()));//出錯(cuò)就返回服務(wù)器錯(cuò)誤
}
}
}).subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
};
}
/**
* 創(chuàng)建成功的數(shù)據(jù)
*
* @param data
* @param <T>
* @return
*/
private static <T> Observable<T> createData(final T data) {
return Observable.create(new ObservableOnSubscribe<T>() {
@Override
public void subscribe(@NonNull ObservableEmitter<T> subscriber) throws Exception {
try {
subscriber.onNext(data);
subscriber.onComplete();
} catch (Exception e) {
subscriber.onError(e);
}
}
});
}
}
預(yù)處理就這么完了,我語(yǔ)言組織能力幾乎為0剃盾,代碼總看的來(lái)吧腺占。
開(kāi)始下一步,對(duì)話框顯示痒谴。怎么弄衰伯,很簡(jiǎn)單繼續(xù)看代碼,要我描述做不到积蔚,最多代碼給你們稍微注釋下
//實(shí)現(xiàn)Observer類(lèi)嚎研,把里面用不到的方法這里全處理掉 我們只處理結(jié)果 成功/失敗
public abstract class RxSubscribe<T> implements Observer<T> {
private Context mContext;
private ProgressDialog dialog;
private String msg;
private boolean isShow = false;
public RxSubscribe(Context context) {
this.mContext = context;
}
public RxSubscribe(Context context, boolean isShow) {
this.mContext = context;
this.isShow = isShow;
msg = mContext.getString(R.string.dialog_message_loading);
}
public RxSubscribe(Context context, int msgResId) {
this.mContext = context;
isShow = true;
msg = mContext.getString(msgResId);
}
@Override
public void onComplete() {
if (isShow) {
if (dialog != null)
dialog.dismiss();
}
}
@Override
public void onSubscribe(@NonNull final Disposable d) {
if (isShow) {
dialog = new ProgressDialog(mContext);
dialog.setMessage(msg);
dialog.setIndeterminate(true);
dialog.setCanceledOnTouchOutside(false);
dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialogInterface) {
// 對(duì)話框取消 直接停止執(zhí)行請(qǐng)求
if (!d.isDisposed()) {
d.dispose();
}
}
});
dialog.show();
}
}
@Override
public void onNext(T t) {
_onNext(t);
}
@Override
public void onError(Throwable e) {
Log.i("onError",e.getMessage() );
//把底層的一些錯(cuò)誤翻譯一下用戶(hù)看不來(lái)
if (e.getMessage() == null || e.getMessage().isEmpty()) {//未知錯(cuò)誤
_onError(mContext.getString(R.string.error_unknown));
} else if (e.getMessage().contains("Failed to connect to") ||
e.getMessage().contains("failed to connect to")) {//連接服務(wù)器失敗
if (!SystemUtil.isNetworkAvailable(mContext)) {//沒(méi)網(wǎng)絡(luò)
_onError(mContext.getString(R.string.error_bad_network));
} else {//真的沒(méi)連接上服務(wù)器
_onError(mContext.getString(R.string.error_connect_server));
}
} else if (e.getMessage().contains("timed out") || e.getMessage().contains("timeout")) {
//超時(shí)了
_onError(mContext.getString(R.string.error_connect_server_timeout));
}else if (e.getMessage().contains("500")) {
//服務(wù)器內(nèi)部錯(cuò)誤
_onError(mContext.getString(R.string.error_connect_server_timeout));
} else {
_onError(e.getMessage());
}
if (isShow) {
if (dialog != null)
dialog.dismiss();
}
}
//成功
protected abstract void _onNext(T t);
//失敗
protected abstract void _onError(String message);
}
基礎(chǔ)的處理全部完成 最后我們的代碼就是請(qǐng)求接口好了
/**
* Created by 王汗三
* Date 2017/7/14.
*/
public class RegisterPresenter extends BasePresenter {
private RegisterActivity activity;
public RegisterPresenter(RegisterActivity activity) {
super(activity);
this.activity = activity;
}
public void authUserName(String username) {
params.put("username", username);
SystemApi.provideService().authUserName(params).compose(RxHelper.<Boolean>applySchedulers()).subscribe(new RxSubscribe<Boolean>(activity, R.string.dialog_message_auth) {
@Override
protected void _onNext(Boolean isExits) {
if (isExits) {
IToast.show(context, "用戶(hù)名已被別家熊孩子搶走了!");
} else {
activity.gotoNext();
}
}
@Override
protected void _onError(String message) {
IToast.show(context, message);
}
});
}
}
好了差不多完成了库倘,最后給大家附帶給上傳文件的 看?? 不多說(shuō)
//上傳文件加參數(shù)
@Multipart
@POST("PostThreads")
Observable<BaseModel<String>> uploadPost(@Part List<MultipartBody.Part> parts);
在帶上個(gè)工具類(lèi)
public class MultipartBodyUtil {
public static List<MultipartBody.Part> files2Parts(Map<String, String> fileMaps,
MediaType imageType) {
List<MultipartBody.Part> parts = new ArrayList<>();
for (Map.Entry<String, String> entry : fileMaps.entrySet()) {
File file = new File(entry.getValue());
RequestBody requestBody = RequestBody.create(imageType, file);
// 將RequestBody封裝成MultipartBody.Part類(lèi)型(同樣是okhttp的)
MultipartBody.Part part = MultipartBody.Part.
createFormData(entry.getKey(), file.getName(), requestBody);
// 添加進(jìn)集合
parts.add(part);
}
return parts;
}
/**
* 直接添加文本類(lèi)型的Part到的MultipartBody的Part集合中
*
* @param parts Part集合
* @param key 參數(shù)名(name屬性)
* @param value 文本內(nèi)容
*/
public static void addTextPart(List<MultipartBody.Part> parts,
String key, String value) {
if(value!=null) {
RequestBody requestBody = RequestBody.create(MediaType.parse("text/plain;charset=utf-8"), value);
MultipartBody.Part part = MultipartBody.Part.createFormData(key, null, requestBody);
parts.add(part);
}
}
}
最后請(qǐng)求
/**
* Created by 王汗三
* Date 2017/2/7.
*/
public class SentPostPresenter extends BasePresenter {
SentPostActivity activity;
public SentPostPresenter(SentPostActivity activity) {
super(activity);
this.activity = activity;
}
public void uploadPost(String travelID, String forumId, String title, List<EditData> editDataList) {
Map<String, String> fileMaps = new HashMap<>();
for (int i = 0; i < editDataList.size(); i++) {
if (editDataList.get(i).getImagePath() != null && !editDataList.get(i).getImagePath().isEmpty()) {
fileMaps.put("file" + (i + 1), editDataList.get(i).getImagePath());
}
}
List<MultipartBody.Part> parts = MultipartBodyUtil.files2Parts(fileMaps, MediaType.parse("image/*;charset=utf-8"));
addBasePart(parts);//這個(gè)是我們項(xiàng)目必傳參數(shù) 你們可以不用管
MultipartBodyUtil.addTextPart(parts, "eventId", travelID);
MultipartBodyUtil.addTextPart(parts, "forumId", forumId);
MultipartBodyUtil.addTextPart(parts, "title", title);
String content=new JsonResolver<List<EditData>>() {
}.toJson(editDataList);
MultipartBodyUtil.addTextPart(parts, "content", content);
SystemApi.provideService().uploadPost(parts).compose(RxHelper.<String>handleResult()).subscribe(new RxSubscribe<String>(activity, R.string.dialog_message_submit) {
@Override
protected void _onNext(String s) {
IToast.show(activity, "發(fā)表成功");
activity.setResult(Activity.RESULT_OK);
activity.finish();
}
@Override
protected void _onError(String message) {
Log.i("_onError",message);
IToast.show(activity, message);
}
});
}
}
這篇文章就到這里 別人說(shuō)授人以魚(yú)不如授人以漁临扮,但是我只會(huì)授魚(yú),吃著魚(yú)領(lǐng)悟吧教翩! 看不懂去看看Rxjava和泛型基礎(chǔ)杆勇。
本文引用第三方庫(kù):
compile 'io.reactivex.rxjava2:rxjava:2.0.7'
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.okio:okio:1.13.0'
compile 'com.squareup.okhttp3:okhttp:3.8.1'
compile 'com.google.code.gson:gson:2.8.0'