一. 用到的知識點:
UI—面向對象
數據交互 —MVP模式
網絡圖片加載—–glide
json解析—–gson
http請求—retrofit2+rxjava2
事件總線—-eventbus
註解—DataBinding
二.目錄結構
biz ————————— 業務模塊
bridge ———————— 底層功能實現跟UI層的銜接層
capabilities —————— 底層功能具體實現
constant ——————— 常量
ui —————————— 界面
util —————————— 業務層公共方法
view ————————— 自定義view實現
三.解析
1.UI層
用到面向對象的封裝BaseActivity爲基類,同時BaseActivity實現三個接口,分別爲CreateInit,PublishActivityCallBack, PresentationLayerFunc,三個接口的作用依次是:界面初始化,頁面跳轉封裝,頁面交互封裝。PresentationLayerFunc的具體實現是在PresentationLayerFuncHelper裏面,BaseActivity類會初始化該類,把複雜的功能實現抽象出去,輕量化基類。
BaseActivity代碼如下所示:
/**
* * 備註:
* 1.XXActivity 繼承 BaseActivity,當頁面存在 Presenter 時,具體 Activity 需要調用 setPresenter(P... presenter)
* 2.支持一個 Activity 存在多個 Presenter
*
* @param <T>
* @param <V>
* @param <P> Data:2018/12/18
* @author yong
*/
public abstract class BaseActivity<T, V extends IMvpView, P extends BasePresenter<V>> extends RxAppCompatActivity implements
CreateInit.CreateInitActivity<V, P>, PublishActivityCallBack, PresentationLayerFunc, IMvpView<T>, View.OnClickListener {
protected ActivityMvpDelegate mvpDelegate;
private PresentationLayerFuncHelper presentationLayerFuncHelper;
public final String TAG = this.getClass().getSimpleName();
/**
* Context對象
*/
protected static Context mContext;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getMvpDelegate().onCreate(savedInstanceState);
presentationLayerFuncHelper = new PresentationLayerFuncHelper(this);
setContentView(savedInstanceState);
mContext = this;
Constants.isStartFragmen = false;
initData();
initListeners();
MyApplication.mApplication.addActivity(this);
EventBus.getDefault().register(this);
}
/**
* 注入View
*
* @return
*/
@Override
public V[] createView() {
V[] views = null;
P[] pArray = createPresenter();
if (pArray != null) {
views = (V[]) new IMvpView[pArray.length];
for (int i = 0; i < pArray.length; i++) {
views[i] = (V) this;
}
}
return views;
}
/**
* 關聯Activity的生命週期
*
* @return
*/
@NonNull
protected ActivityMvpDelegate<V, P> getMvpDelegate() {
if (mvpDelegate == null) {
mvpDelegate = new ActivityMvpDelegateImpl(this, this);
}
return mvpDelegate;
}
/**
* 事件線
*
* @param eventModel
*/
@Subscribe
public void onEventMainThread(T eventModel) {
}
/**
* 鏈接Presenter
*
* @return
*/
@Override
public P[] createPresenter() {
return getPresenterArray();
}
/**
* 獲取 Presenter 數組
*/
public abstract P[] getPresenterArray();
/**
* 網絡請求的錯誤信息,已在請求中處理提示Toast
* 如果有特殊處理需重寫
*
* @param action 區分不同事件
* @param code 錯誤碼
* @param msg 錯誤信息
*/
@Override
public void onError(String action, int code, String msg) {
}
/**
* 配合DataBinding點擊事件監聽
* 添加防止重複點擊
* 有點擊事件只需重寫
*
* @param v
*/
@Override
public void onClick(View v) {
if (Tools.isDoubleClick()) return;
}
@Override
protected void onResume() {
MyApplication.mApplication.currentActivityName = this.getClass().getName();
getMvpDelegate().onResume();
super.onResume();
}
@Override
public void startActivity(Class<?> openClass, Bundle bundle) {
Intent intent = new Intent(this, openClass);
if (null != bundle)
intent.putExtras(bundle);
startActivity(intent);
}
@Override
public void openActivityForResult(Class<?> openClass, int requestCode, Bundle bundle) {
Intent intent = new Intent(this, openClass);
if (null != bundle)
intent.putExtras(bundle);
startActivityForResult(intent, requestCode);
}
@Override
public void setResultOk(Bundle bundle) {
Intent intent = new Intent();
if (bundle != null) ;
intent.putExtras(bundle);
setResult(RESULT_OK, intent);
finish();
}
@Override
public void showToast(String msg) {
presentationLayerFuncHelper.showToast(msg);
}
@Override
public void showSoftKeyboard(View focusView) {
presentationLayerFuncHelper.showSoftKeyboard(focusView);
}
@Override
public void hideSoftKeyboard() {
presentationLayerFuncHelper.hideSoftKeyboard();
}
@Override
protected void onDestroy() {
getMvpDelegate().onDestroy();
MyApplication.mApplication.deleteActivity(this);
EventBus.getDefault().unregister(this);
Constants.isStartFragmen = true;
super.onDestroy();
}
@Override
public void finish() {
try {
presentationLayerFuncHelper.hideSoftKeyboard();
} catch (Exception e) {
LogUtil.E("finish 輸入法錯誤");
}
super.finish();
}
//監聽點擊事件 實現點擊頁面上除EditView外的位置隱藏輸入法
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
try {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
View v = getCurrentFocus();
if (isShouldHideKeyboard(v, ev)) {
presentationLayerFuncHelper.hideKeyboard(v.getWindowToken());
}
}
} catch (Exception e) {
LogUtil.E("dispatchTouchEvent 輸入法錯誤");
}
return super.dispatchTouchEvent(ev);
}
/**
* 根據EditText所在座標和用戶點擊的座標相對比,來判斷是否隱藏鍵盤,因爲當用戶點擊EditText時則不能隱藏
*
* @param v
* @param event
* @return
*/
private boolean isShouldHideKeyboard(View v, MotionEvent event) {
if (v != null && (v instanceof EditText)) {
int[] l = {0, 0};
v.getLocationInWindow(l);
int left = l[0],
top = l[1],
bottom = top + v.getHeight(),
right = left + v.getWidth();
if (event.getX() > left && event.getX() < right
&& event.getY() > top && event.getY() < bottom) {
// 點擊EditText的事件,忽略它。
return false;
} else {
return true;
}
}
// 如果焦點不是EditText則忽略,這個發生在視圖剛繪製完,第一個焦點不在EditText上,和用戶用軌跡球選擇其他的焦點
return false;
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
getMvpDelegate().onSaveInstanceState(outState);
}
@Override
protected void onPause() {
super.onPause();
getMvpDelegate().onPause();
}
@Override
protected void onStart() {
super.onStart();
getMvpDelegate().onStart();
}
@Override
protected void onStop() {
super.onStop();
getMvpDelegate().onStop();
}
@Override
protected void onRestart() {
super.onRestart();
getMvpDelegate().onRestart();
}
@Override
public void onContentChanged() {
super.onContentChanged();
getMvpDelegate().onContentChanged();
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
getMvpDelegate().onPostCreate(savedInstanceState);
}
}
PresentationLayerFuncHelper代碼如下所示:
/**
* <頁面基礎公共功能實現>
* Data:2018/12/18
*
* @author yong
*/
public class PresentationLayerFuncHelper implements PresentationLayerFunc {
private Context context;
public PresentationLayerFuncHelper(Context context) {
this.context = context;
}
/**
* Toast提示
*
* @param msg
*/
@Override
public void showToast(String msg) {
ToastUtil.makeTextShort(context, msg);
}
/**
* 顯示軟鍵盤
*
* @param focusView
*/
@Override
public void showSoftKeyboard(View focusView) {
((Activity) context).getWindow().getDecorView().postDelayed(new Runnable() {
@Override
public void run() {
InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
focusView.requestFocus();
imm.showSoftInput(focusView, 0);
}
}
}, 100);
}
/**
* 隱藏軟鍵盤
*/
@Override
public void hideSoftKeyboard() {
if ((context == null || ((Activity) context).getWindow() == null)) {
return;
}
View view = ((Activity) context).getWindow().peekDecorView();
if (view == null || view.getWindowToken() == null) {
return;
}
InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm == null) {
return;
}
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
/**
* 獲取InputMethodManager,隱藏軟鍵盤
*
* @param token
*/
public void hideKeyboard(IBinder token) {
if (token != null) {
InputMethodManager im = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
if (im != null) {
im.hideSoftInputFromWindow(token, InputMethodManager.HIDE_NOT_ALWAYS);
}
}
}
}
三個接口,分別爲CreateInit, PublishActivityCallBack, PresentationLayerFunc代碼如下所示:
/**
* <公共方法抽象>
* Data:2018/12/18
*
* @author yong
*/
public interface CreateInit<V extends IMvpView, P extends Presenter> {
interface CreateInitActivity<V extends IMvpView, P extends Presenter> extends CreateInit<V, P> {
/**
* 設置佈局文件
*/
void setContentView(Bundle savedInstanceState);
}
interface CreateInitFragment<V extends IMvpView, P extends Presenter> extends CreateInit<V, P> {
/**
* 設置佈局文件
*/
View initView(LayoutInflater inflater);
}
/**
* 連接P層
*
* @return
*/
P[] createPresenter();
/**
* 注入view
*
* @return
*/
V[] createView();
/**
* 初始化數據
*/
void initData();
/**
* 增加按鈕點擊事件
*/
void initListeners();
}
/**
* <頁面跳轉封裝>
* Data:2018/12/18
*
* @author yong
*/
public interface PublishActivityCallBack {
/**
* 打開新界面
*
* @param openClass 新開頁面
* @param bundle 參數
*/
void startActivity(Class<?> openClass, Bundle bundle);
/**
* 打開新界面,期待返回
*
* @param openClass 新界面
* @param requestCode 請求碼
* @param bundle 參數
*/
void openActivityForResult(Class<?> openClass, int requestCode, Bundle bundle);
/**
* 返回到上個頁面
*
* @param bundle 參數
*/
void setResultOk(Bundle bundle);
}
/**
* <頁面基礎公共功能抽象>
* Data:2018/12/18
*
* @author yong
*/
public interface PresentationLayerFunc {
/**
* 彈出消息
*
* @param msg
*/
void showToast(String msg);
/**
* 顯示軟鍵盤
*
* @param focusView
*/
void showSoftKeyboard(View focusView);
/**
* 隱藏軟鍵盤
*/
void hideSoftKeyboard();
}
界面只要繼承BaseLoadActivity,而BaseLoadActivity繼承BaseActivity:BaseLoadActivity是帶空頁面額錯誤顯示頁面
/**
* <功能詳細描述>
* 泛型傳入
* 1、網絡請求實體類:如果有多個實體類可以傳入Object或是通過BaseListMode中set、get方法設置
* 2、自動生成ViewDataBinding
* <p>
* Data:2018/12/18
*
* @author yong
*/
public class MainActivity extends BaseLoadActivity<LoginModel, ActivityMainBinding> {
private LoginPresenter presenter = new LoginPresenter(this);
@Override
public int getLayout() {
return R.layout.activity_main;
}
@Override
public void onSuccess(String action, LoginModel data) {
mLoadBinding.text.setText(SharedPrefManager.getUser().getString(SharedPrefUser.USER_NAME, ""));
mLoadBinding.text1.setText(data.getNickName());
mLoadBinding.bt.setText(action);
}
@Override
public void initListeners() {
mLoadBinding.bt.setOnClickListener(this);
}
@Override
public void initData() {
// presenter.login("", "123456");
}
@Override
public BasePresenter<IMvpView<LoginModel>>[] getPresenterArray() {
return new BasePresenter[]{presenter};
}
@Override
public void onClick(View v) {
super.onClick(v);
}
}
2.數據交互層
Presenter與View交互是通過接口:成功,失敗(如有特需處理可以使用此方法)。
/**
* <功能詳細描述>
* <p>
* Data:2018/12/18
*
* @author yong
* <p>
* action 方式: 考慮多個請求時 根據 action 區分處理
*/
public interface IMvpView<T> {
/**
* 網絡請求的錯誤信息,已在請求中處理提示Toast
*
* @param action 區分不同事件
* @param code 錯誤碼
* @param msg 錯誤信息
*/
@UiThread
void onError(String action, int code, String msg);
/**
* 成功返回結果
*
* @param action 區分不同事件
* @param data 數據
*/
@UiThread
void onSuccess(String action, T data);
}
LoginPresenter 爲登錄的業務實現類:1、業務處理。2.通知頁面數據刷新。Presenter與頁面交互是通過接口實現的,通過繼承基類BasePresenter,從而實現接口attachView(V view),view是個泛型,MainActivity會實現這個接口,在初始化LoginPresenter 的時候,會把自身傳過來loginPresenter.attachView(this),這段代碼是在onCreate中,Presenter通知頁面刷新。在使用BaseModelObserver或是BaseListModelObserver時提供兩個構造器,多參數可以提示加載彈窗和設置點擊返回鍵是否消失加載窗。
/**
* <基礎業務類>
* <p>
* Data:2018/12/18
*
* @author yong
*/
public interface Presenter<V> {
/**
* 將 View 添加到當前 Presenter
*
* @param view
*/
@UiThread
void attachView(@NonNull V view);
/**
* 將 View 從 Presenter 中移除
*/
@UiThread
void detachView();
/**
* 銷燬 V 實例
*/
@UiThread
void destroy();
}
/**
* <基礎業務類>
* <p>
* Data:2018/12/18
*
* @author yong
*/
public abstract class BasePresenter<V extends IMvpView> implements Presenter<V> {
private WeakReference<V> viewRef;
private SecurityManager securityManager;
private RetrofitHttp.Builder retrofitHttp;
/**
* 獲取 View
*
* @return
*/
@UiThread
public V getMvpView() {
return viewRef == null ? null : viewRef.get();
}
/**
* 判斷View是否已經添加
*
* @return
*/
@UiThread
public boolean isViewAttached() {
return viewRef != null && viewRef.get() != null;
}
/**
* 綁定 View
*
* @param view
*/
@UiThread
@Override
public void attachView(V view) {
viewRef = new WeakReference<>(view);
}
/**
* 移除 View
*/
@Override
public void detachView() {
if (viewRef != null) {
viewRef.clear();
viewRef = null;
}
}
@Override
public void destroy() {
}
/**
* MD5加密
*/
public SecurityManager getSecurityManager() {
if (securityManager == null)
securityManager = BridgeFactory.getBridge(Bridges.SECURITY);
return securityManager;
}
/**
* 網絡請求
*/
public RetrofitHttp.Builder getRetrofitHttp() {
if (retrofitHttp == null)
retrofitHttp = BridgeFactory.getBridge(Bridges.HTTP);
retrofitHttp.clear();
retrofitHttp.lifecycle((LifecycleProvider) getMvpView());
return retrofitHttp;
}
}
/**
* <功能詳細描述>
* <p>
* Data:2018/12/18
*
* @author yong
*/
public class LoginPresenter extends BasePresenter<IMvpView<LoginModel>> {
private Context context;
public LoginPresenter(Context context) {
this.context = context;
}
public void login(String userid, String pwd) {
if (!isViewAttached()) return;
Map<String, Object> map = new HashMap<>();
map.put("userid", userid);
map.put("pwd", pwd);
getRetrofitHttp().post().apiUrl(UrlConstans.LOGIN)
.addParameter(map).build()
.request(new BaseModelObserver<LoginModel>(context) {//BaseListModelObserver:返回數據List集合
@Override
public void onSuccess(String action, LoginModel value) {
getMvpView().onSuccess(action, value);
}
@Override
public void onError(String action, int code, String desc) {//有需要需重寫
super.onError(action, code, desc);
getMvpView().onError(action, code, desc);
}
});
}
}
3.網絡層
/**
* Http請求類
* <p>
* Data:2018/12/18
*
* @author yong
*/
public class RetrofitHttp {
/*請求方式*/
private Method method;
/*請求參數*/
private Map<String, Object> parameter;
/*header*/
private Map<String, Object> header;
/*LifecycleProvider*/
private LifecycleProvider lifecycle;
/*ActivityEvent*/
private ActivityEvent activityEvent;
/*FragmentEvent*/
private FragmentEvent fragmentEvent;
/*HttpObserver*/
private HttpObserver httpObserver;
/*標識請求的TAG*/
private String tag;
/*文件map*/
private Map<String, File> fileMap;
/*上傳文件回調*/
private UploadObserver uploadCallback;
/*基礎URL*/
private String baseUrl;
/*apiUrl*/
private String apiUrl;
/*String參數*/
String bodyString;
/*是否強制JSON格式*/
boolean isJson;
/*構造函數*/
private RetrofitHttp(Builder builder) {
this.parameter = builder.parameter;
this.header = builder.header;
this.lifecycle = builder.lifecycle;
this.activityEvent = builder.activityEvent;
this.fragmentEvent = builder.fragmentEvent;
this.tag = builder.tag;
this.fileMap = builder.fileMap;
this.baseUrl = builder.baseUrl;
this.apiUrl = builder.apiUrl;
this.isJson = builder.isJson;
this.bodyString = builder.bodyString;
this.method = builder.method;
}
/*普通Http請求*/
public void request(HttpObserver httpObserver) {
this.httpObserver = httpObserver;
if (httpObserver == null) {
throw new NullPointerException("HttpObserver must not null!");
} else {
doRequest();
}
}
/*上傳文件請求*/
public void upload(UploadObserver uploadCallback) {
this.uploadCallback = uploadCallback;
if (uploadCallback == null) {
throw new NullPointerException("UploadObserver must not null!");
} else {
doUpload();
}
}
/*執行請求*/
private void doRequest() {
/*設置請求唯一標識*/
httpObserver.setTag(TextUtils.isEmpty(tag) ? disposeApiUrl() : tag);
/*header處理*/
disposeHeader();
/*Parameter處理*/
disposeParameter();
/*請求方式處理*/
Observable apiObservable = disposeApiObservable();
/* 被觀察者 httpObservable */
HttpObservable httpObservable = new HttpObservable.Builder(apiObservable)
.baseObserver(httpObserver)
.lifecycleProvider(lifecycle)
.activityEvent(activityEvent)
.fragmentEvent(fragmentEvent)
.build();
/* 觀察者 httpObserver */
/*設置監聽*/
httpObservable.observe().subscribe(httpObserver);
}
/*執行文件上傳*/
private void doUpload() {
/*設置請求唯一標識*/
uploadCallback.setTag(TextUtils.isEmpty(tag) ? disposeApiUrl() : tag);
/*header處理*/
disposeHeader();
/*Parameter處理*/
disposeParameter();
/*處理文件集合*/
List<MultipartBody.Part> fileList = new ArrayList<>();
if (fileMap != null && fileMap.size() > 0) {
int size = fileMap.size();
int index = 1;
File file;
RequestBody requestBody;
for (String key : fileMap.keySet()) {
file = fileMap.get(key);
requestBody = RequestBody.create(MediaType.parse("multipart/form-data"), file);
MultipartBody.Part part = MultipartBody.Part.createFormData(key, file.getName(), new UploadRequestBody(requestBody, file, index, size, uploadCallback));
fileList.add(part);
index++;
}
}
/*請求處理*/
Observable apiObservable = RetrofitUtils.get().getRetrofit(getBaseUrl(), header).create(Api.class).upload(disposeApiUrl(), parameter, header, fileList);
/* 被觀察者 httpObservable */
HttpObservable httpObservable = new HttpObservable.Builder(apiObservable)
.baseObserver(uploadCallback)
.lifecycleProvider(lifecycle)
.activityEvent(activityEvent)
.fragmentEvent(fragmentEvent)
.build();
/* 觀察者 uploadCallback */
/*設置監聽*/
httpObservable.observe().subscribe(uploadCallback);
}
/*獲取基礎URL*/
private String getBaseUrl() {
//如果沒有重新指定URL則是用默認配置
return TextUtils.isEmpty(baseUrl) ? Configure.get().getBaseUrl() : baseUrl;
}
/*ApiUrl處理*/
private String disposeApiUrl() {
return TextUtils.isEmpty(apiUrl) ? "" : apiUrl;
}
/*處理Header*/
private void disposeHeader() {
/*header空處理*/
if (header == null) {
header = new TreeMap<>();
}
//添加基礎 Header
Map<String, Object> baseHeader = Configure.get().getBaseHeader();
if (baseHeader != null && baseHeader.size() > 0) {
header.putAll(baseHeader);
}
if (!header.isEmpty()) {
//處理header中文或者換行符出錯問題
for (String key : header.keySet()) {
header.put(key, RequestUtils.getHeaderValueEncoded(header.get(key)));
}
}
}
/*處理 Parameter*/
private void disposeParameter() {
/*空處理*/
if (parameter == null) {
parameter = new TreeMap<>();
}
//添加基礎 Parameter
Map<String, Object> baseParameter = Configure.get().getBaseParameter();
if (baseParameter != null && baseParameter.size() > 0) {
parameter.putAll(baseParameter);
}
}
/*處理ApiObservable*/
private Observable disposeApiObservable() {
Observable apiObservable = null;
/*是否JSON格式提交參數*/
boolean hasBodyString = !TextUtils.isEmpty(bodyString);
RequestBody requestBody = null;
if (hasBodyString) {
String mediaType = isJson ? "application/json; charset=utf-8" : "text/plain;charset=utf-8";
requestBody = RequestBody.create(okhttp3.MediaType.parse(mediaType), bodyString);
}
/*Api接口*/
Api apiService = RetrofitUtils.get().getRetrofit(getBaseUrl(), header).create(Api.class);
/*未指定默認POST*/
if (method == null) method = Method.POST;
switch (method) {
case GET:
apiObservable = apiService.get(disposeApiUrl(), parameter, header);
break;
case POST:
if (hasBodyString)
apiObservable = apiService.post(disposeApiUrl(), requestBody, header);
else
apiObservable = apiService.post(disposeApiUrl(), parameter, header);
break;
case DELETE:
apiObservable = apiService.delete(disposeApiUrl(), parameter, header);
break;
case PUT:
apiObservable = apiService.put(disposeApiUrl(), parameter, header);
break;
}
return apiObservable;
}
/**
* Configure配置
*/
public static final class Configure {
/*請求基礎路徑*/
String baseUrl;
/*超時時長*/
long timeout;
/*時間單位*/
TimeUnit timeUnit;
/*全局上下文*/
Context context;
/*全局Handler*/
Handler handler;
/*請求參數*/
Map<String, Object> parameter;
/*header*/
Map<String, Object> header;
/*是否顯示Log*/
boolean showLog;
public static Configure get() {
return Configure.Holder.holder;
}
private static class Holder {
private static Configure holder = new Configure();
}
private Configure() {
timeout = 60;//默認60秒
timeUnit = TimeUnit.SECONDS;//默認秒
showLog = true;//默認打印LOG
}
/*請求基礎路徑*/
public RetrofitHttp.Configure baseUrl(String baseUrl) {
this.baseUrl = baseUrl;
return this;
}
public String getBaseUrl() {
return baseUrl;
}
/*基礎參數*/
public RetrofitHttp.Configure baseParameter(Map<String, Object> parameter) {
this.parameter = parameter;
return this;
}
public Map<String, Object> getBaseParameter() {
return parameter;
}
/*基礎Header*/
public RetrofitHttp.Configure baseHeader(Map<String, Object> header) {
this.header = header;
return this;
}
public Map<String, Object> getBaseHeader() {
return header;
}
/*超時時長*/
public RetrofitHttp.Configure timeout(long timeout) {
this.timeout = timeout;
return this;
}
public long getTimeout() {
return timeout;
}
/*是否顯示LOG*/
public RetrofitHttp.Configure showLog(boolean showLog) {
this.showLog = showLog;
return this;
}
public boolean isShowLog() {
return showLog;
}
/*時間單位*/
public RetrofitHttp.Configure timeUnit(TimeUnit timeUnit) {
this.timeUnit = timeUnit;
return this;
}
public TimeUnit getTimeUnit() {
return timeUnit;
}
/*Handler*/
public Handler getHandler() {
return handler;
}
/*Context*/
public Context getContext() {
return context;
}
/*初始化全局上下文*/
public RetrofitHttp.Configure init(Application app) {
this.context = app.getApplicationContext();
this.handler = new Handler(Looper.getMainLooper());
return this;
}
}
/**
* Builder
* 構造Request所需參數,按需設置
*/
public static class Builder implements BridgeLifeCycleListener {
/*請求方式*/
Method method;
/*請求參數*/
Map<String, Object> parameter;
/*header*/
Map<String, Object> header;
/*LifecycleProvider*/
LifecycleProvider lifecycle;
/*ActivityEvent*/
ActivityEvent activityEvent;
/*FragmentEvent*/
FragmentEvent fragmentEvent;
/*標識請求的TAG*/
String tag;
/*文件map*/
Map<String, File> fileMap;
/*基礎URL*/
String baseUrl;
/*apiUrl*/
String apiUrl;
/*String參數*/
String bodyString;
/*是否強制JSON格式*/
boolean isJson;
private Builder instance;
public Builder getInstanc() {
if (instance == null) {
synchronized (RetrofitHttp.class) {
if (instance == null) {
instance = new Builder();
}
}
}
return instance;
}
/*GET*/
public RetrofitHttp.Builder get() {
this.method = Method.GET;
return this;
}
/*POST*/
public RetrofitHttp.Builder post() {
this.method = Method.POST;
return this;
}
/*DELETE*/
public RetrofitHttp.Builder delete() {
this.method = Method.DELETE;
return this;
}
/*PUT*/
public RetrofitHttp.Builder put() {
this.method = Method.PUT;
return this;
}
/*基礎URL*/
public RetrofitHttp.Builder baseUrl(String baseUrl) {
this.baseUrl = baseUrl;
return this;
}
/*API URL*/
public RetrofitHttp.Builder apiUrl(@NonNull String apiUrl) {
this.apiUrl = apiUrl;
return this;
}
/* 增加 Parameter 不斷疊加參數 包括基礎參數 */
public RetrofitHttp.Builder addParameter(Map<String, Object> parameter) {
if (this.parameter == null) {
this.parameter = new TreeMap<>();
}
this.parameter.putAll(parameter);
return this;
}
/* 增加 Parameter 不斷疊加參數 包括基礎參數 */
public RetrofitHttp.Builder addParameter(String key, Object parameter) {
if (this.parameter == null) {
this.parameter = new TreeMap<>();
}
this.parameter.put(key, parameter);
return this;
}
/*設置 Parameter 會覆蓋 Parameter 包括基礎參數*/
public RetrofitHttp.Builder setParameter(Map<String, Object> parameter) {
this.parameter = parameter;
return this;
}
/* 設置String 類型參數 覆蓋之前設置 isJson:是否強制JSON格式 bodyString設置後Parameter則無效 */
public RetrofitHttp.Builder setBodyString(String bodyString, boolean isJson) {
this.isJson = isJson;
this.bodyString = bodyString;
return this;
}
/* 增加 Header 不斷疊加 Header 包括基礎 Header */
public RetrofitHttp.Builder addHeader(String key, Object header) {
if (this.header == null) {
this.header = new TreeMap<>();
}
this.header.put(key, header);
return this;
}
/* 增加 Header 不斷疊加 Header 包括基礎 Header */
public RetrofitHttp.Builder addHeader(Map<String, Object> header) {
if (this.header == null) {
this.header = new TreeMap<>();
}
this.header.putAll(header);
return this;
}
/*設置 Header 會覆蓋 Header 包括基礎參數*/
public RetrofitHttp.Builder setHeader(Map<String, Object> header) {
this.header = header;
return this;
}
/*LifecycleProvider*/
public RetrofitHttp.Builder lifecycle(LifecycleProvider lifecycle) {
this.lifecycle = lifecycle;
return this;
}
/*ActivityEvent*/
public RetrofitHttp.Builder activityEvent(ActivityEvent activityEvent) {
this.activityEvent = activityEvent;
return this;
}
/*FragmentEvent*/
public RetrofitHttp.Builder fragmentEvent(FragmentEvent fragmentEvent) {
this.fragmentEvent = fragmentEvent;
return this;
}
/*tag*/
public RetrofitHttp.Builder tag(String tag) {
this.tag = tag;
return this;
}
/*文件集合*/
public RetrofitHttp.Builder file(Map<String, File> file) {
this.fileMap = file;
return this;
}
/*一個Key對應多個文件*/
public RetrofitHttp.Builder file(String key, List<File> fileList) {
if (fileMap == null) {
fileMap = new IdentityHashMap();
}
if (fileList != null && fileList.size() > 0) {
for (File file : fileList) {
fileMap.put(new String(key), file);
}
}
return this;
}
public RetrofitHttp.Builder clear() {
this.method = Method.POST;
this.parameter = null;
this.header = null;
this.lifecycle = null;
this.activityEvent = null;
this.fragmentEvent = null;
this.tag = "";
this.fileMap = null;
this.apiUrl = "";
this.bodyString = "";
this.isJson = false;
this.instance = null;
return this;
}
public RetrofitHttp build() {
return new RetrofitHttp(this);
}
@Override
public void initOnApplicationCreate(Context context) {
}
@Override
public void clearOnApplicationQuit() {
clear();
RequestManagerImpl.getInstance().cancelAll();
}
}
}
/**
* Api接口
* <p>
* Data:2018/12/18
*
* @author yong
*/
public interface Api {
/**
* GET 請求
*
* @param url api接口url
* @param parameter 請求參數map
* @param header 請求頭map
* @return
*/
@GET
Observable<JsonElement> get(@Url String url, @QueryMap Map<String, Object> parameter, @HeaderMap Map<String, Object> header);
/**
* POST 請求
*
* @param url api接口url
* @param parameter 請求參數map
* @param header 請求頭map
* @return
*/
@FormUrlEncoded
@POST
Observable<JsonElement> post(@Url String url, @FieldMap Map<String, Object> parameter, @HeaderMap Map<String, Object> header);
/**
* @param requestBody 用於String/JSON格式數據
*/
@POST
Observable<JsonElement> post(@Url String url, @Body RequestBody requestBody, @HeaderMap Map<String, Object> header);
/**
* DELETE 請求
*
* @param url api接口url
* @param parameter 請求參數map
* @param header 請求頭map
* @return
*/
@DELETE
Observable<JsonElement> delete(@Url String url, @QueryMap Map<String, Object> parameter, @HeaderMap Map<String, Object> header);
/**
* PUT 請求
*
* @param url api接口url
* @param parameter 請求參數map
* @param header 請求頭map
* @return
*/
@FormUrlEncoded
@PUT
Observable<JsonElement> put(@Url String url, @FieldMap Map<String, Object> parameter, @HeaderMap Map<String, Object> header);
/**
* 多文件上傳
*
* @param url api接口url
* @param parameter 請求接口參數
* @param header 請求頭map
* @param fileList 文件列表
* @return
* @Multipart 文件上傳註解 multipart/form-data
*/
@Multipart
@POST
Observable<JsonElement> upload(@Url String url, @PartMap Map<String, Object> parameter, @HeaderMap Map<String, Object> header, @Part List<MultipartBody.Part> fileList);
/**
* 斷點續傳下載
*
* @param range 斷點下載範圍 bytes= start - end
* @param url 下載地址
* @return
* @Streaming 防止內容寫入內存, 大文件通過此註解避免OOM
*/
@Streaming
@GET
Observable<ResponseBody> download(@Header("RANGE") String range, @Url String url);
}
4.Bridge層抽象
BridgeFactory用來統一管理基礎功能,類似本地服務的實現原理。 實現了文件,網絡,安全等等管理類的實現,並保存了各類管理類的引用。業務層或者上層調用底層實現時,通過BridgeFactory去訪問,而不是直接的調。
/**
* <中間連接層>
* Data:2018/12/18
*
* @author yong
*/
public class BridgeFactory {
private static BridgeFactory model;
private HashMap<String, Object> mBridges;
private BridgeFactory() {
mBridges = new HashMap<String, Object>();
}
public static void init(Application application) {
model = new BridgeFactory();
model.iniLocalFileStorageManager();
model.initPreferenceManager();
model.initSecurityManager();
model.initUserSession();
model.initOkHttpManager(application);
}
public static void destroy() {
model.mBridges = null;
model = null;
}
/**
* 初始化本地存儲路徑管理類
*/
private void iniLocalFileStorageManager() {
LocalFileStorageManager localFileStorageManager = new LocalFileStorageManager();
model.mBridges.put(Bridges.LOCAL_FILE_STORAGE, localFileStorageManager);
BridgeLifeCycleSetKeeper.getInstance().trustBridgeLifeCycle(localFileStorageManager);
}
/**
* 初始化SharedPreference管理類
*/
private void initPreferenceManager() {
SharedPrefManager sharedPrefManager = new SharedPrefManager();
model.mBridges.put(Bridges.SHARED_PREFERENCE, sharedPrefManager);
BridgeLifeCycleSetKeeper.getInstance().trustBridgeLifeCycle(sharedPrefManager);
}
/**
* 網絡請求管理類
*/
private void initOkHttpManager(Application application) {
RetrofitHttp.Configure.get().baseUrl(UrlConstans.SERVER).init(application);
RetrofitHttp.Builder builder = new RetrofitHttp.Builder().getInstanc();
model.mBridges.put(Bridges.HTTP, builder);
BridgeLifeCycleSetKeeper.getInstance().trustBridgeLifeCycle(builder);
}
/**
* 初始化安全模塊
*/
private void initSecurityManager() {
SecurityManager securityManager = new SecurityManager();
model.mBridges.put(Bridges.SECURITY, securityManager);
BridgeLifeCycleSetKeeper.getInstance().trustBridgeLifeCycle(securityManager);
}
/**
* 初始化用戶信息模塊
*/
private void initUserSession() {
}
/**
* 通過bridgeKey {@link Bridges}來獲取對應的Bridge模塊
*
* @param bridgeKey {@link Bridges}
* @return
*/
@SuppressWarnings("unchecked")
public static <V extends Object> V getBridge(String bridgeKey) {
final Object bridge = model.mBridges.get(bridgeKey);
if (bridge == null) {
throw new NullPointerException("-no defined bridge-");
}
return (V) bridge;
}
}
BridgeLifeCycleListener 接口,實現各個底層功能管理類的統一初始化跟銷燬工作,保持跟app的生命週期一致。
/**
* 如果Bridge層的生命週期和App的生命週期相關(在Application
* onCreate的時候初始化,在用戶雙擊back鍵退出),則實現此接口,屆時統一初始化和銷燬
* Data:2018/12/18
*
* @author yong
*/
public interface BridgeLifeCycleListener {
void initOnApplicationCreate(Context context);
void clearOnApplicationQuit();
}
5.多頁面交互
EventBus是一款針對Android優化的發佈/訂閱事件總線。主要功能是替代Intent,Handler,BroadCast在Fragment,Activity,Service,線程之間傳遞消息。優點是開銷小,代碼更優雅,以及將發送者和接收者解耦。
EventBus.getDefault().register(this);//訂閱事件
EventBus.getDefault().post(object);//發佈事件
EventBus.getDefault().unregister(this);//取消訂閱
Demo下載地址:https://download.csdn.net/download/qq_39735504/10861424
MVP模式封裝框架地址:https://github.com/AgnoiY/MvpLibrary
注意:Demo中提供的登錄接口返回數據類型錯誤,請不要使用,斷點下載的沒有實現的