前言
网上有个段子,面试造火箭进去拧螺丝;有时候在公司难免写一个新项目或者一些UI之类;本文简单讲讲一些基类的封装。
1、MVP模式的基类封装
MVP主要定义好Presenter层和View层的接口,在封装一些BaseFragment和BaseActivity。
1.1、 视图View层的封装
简化了视图接口的定义,只拿一个举例子
public interface ErrorMessageView {
void showError(String error);
}
1.2、 Presenter层的封装
Presenter封装有接口定义和抽象类封装
接口定义IPresenter:
// 这里少了个onStart方法,不论需要自行补充即可
public interface IPresenter {
void onCreate();
void onResume();
void onPause();
void onStop();
void onDestroy();
void onActivityResult(Intent intent, int requestCode, int resultCode);
void onNewIntent(Intent intent);
}
抽象基类AbsPresenter封装:
public abstract class AbsPresenter implements IPresenter,
FailedCallback, ApiFailedCallback, CancelCallback {
public final static int API_ALERT_CODE = -1234;
protected Context context;
protected ErrorMessageView errorMessageView;
private MaterialDialog dialog;
public AbsPresenter(Context context, ErrorMessageView view) {
this.context = context;
this.errorMessageView = view;
}
protected String getString(int rid) {
return context.getString(rid);
}
protected String getString(int resId, Object... formatArgs) {
return context.getString(resId, formatArgs);
}
protected int getColor(int rid) {
return context.getResources().getColor(rid);
}
protected void hideLoadingView() {
if (errorMessageView instanceof AlertErrorMessageView) {
((LoadingView) errorMessageView).hideLoading();
}
if (errorMessageView instanceof LoadingMessageView) {
((LoadingMessageView) errorMessageView).hideLoading();
}
}
@Override
public void onFailed(int errCode, String msg) {
hideLoadingView();
if (errCode == API_ALERT_CODE) {
if (errorMessageView instanceof AlertErrorMessageView) {
((AlertErrorMessageView) errorMessageView).alertError(msg);
}
} else {
errorMessageView.showError(msg);
}
}
@Override
public void onApiFailed(int i, String msg) {
hideLoadingView();
if (i == API_ALERT_CODE) {
if (errorMessageView instanceof AlertErrorMessageView) {
((AlertErrorMessageView) errorMessageView).alertError(msg);
}
} else {
errorMessageView.showError(msg);
}
}
@Override
public void onCanceled() {
hideLoadingView();
}
@Override
public void onCreate() {
// do nothing
}
@Override
public void onResume() {
//do nothing
}
@Override
public void onPause() {
//do nothing
}
@Override
public void onStop() {
//do nothing
}
@Override
public void onDestroy() {
//do nothing
}
@Override
public void onActivityResult(Intent intent, int requestCode, int resultCode) {
//do nothing
}
@Override
public void onNewIntent(Intent intent) {
//do nothing
}
}
自动绑定生命周期基类AbsLifePresenter封装:
public abstract class AbsLifePresenter extends AbsPresenter implements LifecycleObserver {
protected LifecycleOwner mLifecycleOwner;
protected CoroutineSupport mCoroutineSupport = new CoroutineSupport();
public AbsLifePresenter(Context context, ErrorMessageView view, LifecycleOwner lifecycleOwner) {
super(context, view);
this.mLifecycleOwner = ObjectHelper.requireNonNull(lifecycleOwner,"LifecycleOwner can not be null in AbsLifePresenter");
mLifecycleOwner.getLifecycle().addObserver(this);
}
protected <T> AutoDisposeConverter<T> bindLifecycle() {
return autoDisposable(
RxLifecycleInterop.from(AndroidLifecycle.createLifecycleProvider(mLifecycleOwner)));
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
@CallSuper
@Override
public void onDestroy() {
mCoroutineSupport.destroy();
}
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
@Override
public void onCreate() {
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
@Override
public void onPause() {
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
@Override
public void onResume() {
//do nothing
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
protected void onStart() {
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
@Override
public void onStop() {
//do nothing
}
}
1.3、BaseActivity的简单封装
这里简化了视图View的定义
public abstract class BasePlatformActivity extends FragmentActivity
implements ErrorMessageView{
protected CoroutineSupport mCoroutineSupport = new CoroutineSupport();
/**
* 这个成员变量是用做onNewIntent和onActivityResult用
*/
private IPresenter mIPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(getContentView());
init();
HiLogger.i("ActivityLifeCircle " + this.getClass().getSimpleName() + " onCreate");
}
/**
* call this method can get onActivityResult and onNewIntent callBack(option)
*
* @param iPresenter 主要生命周期方法的回掉接口
*/
public void setIPresenter(IPresenter iPresenter) {
this.mIPresenter = iPresenter;
}
@Override
protected void onRestart() {
super.onRestart();
HiLogger.i("ActivityLifeCircle " + this.getClass().getSimpleName() + " onRestart");
}
@Override
protected void onStart() {
super.onStart();
HiLogger.i("ActivityLifeCircle " + this.getClass().getSimpleName() + " onStart");
}
@Override
protected void onDestroy() {
super.onDestroy();
HiLogger.i("ActivityLifeCircle " + this.getClass().getSimpleName() + " onDestroy");
mCoroutineSupport.destroy();
}
protected abstract int getContentView();
protected void init() {
//do nothing
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if (mIPresenter != null) {
mIPresenter.onNewIntent(intent);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (mIPresenter != null) {
mIPresenter.onActivityResult(data, requestCode, resultCode);
}
}
/**
* 返回一个 Rx Converter ,自动在OnDestroy时中断Rx事件流
*
* @param <T>
* @return
*/
protected <T> AutoDisposeConverter<T> bindLifecycle() {
return autoDisposable(
RxLifecycleInterop.from(AndroidLifecycle.createLifecycleProvider(this)));
}
protected void toast(String msg) {
if (TextUtils.isEmpty(msg)) return;
ToastMaster.showToast(this, msg, Gravity.NO_GRAVITY, Toast.LENGTH_LONG);
}
@Override
public void showError(String error) {
toast(error);
}
}
2、MVVM的封装
MVVM对基类的封装主要包含了View,ViewModel以及对应的BaseFragment(以Fragment举例)
2.1、ViewModel的封装
open class BaseViewModel : ViewModel(), CoroutineScope {
private val coroutineDelegate = lazy { CoroutineSupport() }
private val coroutine by coroutineDelegate
var data = Bundle()
//toast
val toast = MutableLiveData<Event<String?>>()
//加载进度框
val flower = MutableLiveData<Event<Boolean>>()
//页面跳转
val jump = MutableLiveData<Event2<KClass<*>?, Bundle?>>()
//页面跳转并获取结果
val jumpForResult = MutableLiveData<Event3<KClass<*>?, Bundle?, Int?>>()
//ViewModel中的activity代码块
val activityBlock = MutableLiveData<Event<(FragmentActivity) -> Unit>>()
//ViewModel中的activity代码块
val activityForeverBlock = MutableLiveData<Event<(FragmentActivity) -> Unit>>()
//ViewModel中的Fragment代码块
val fragmentBlock = MutableLiveData<Event<(Fragment) -> Unit>>()
//关闭页面回参
val finishResult = MutableLiveData<Event2<Int?, Bundle?>>()
//关闭页面
val finish = MutableLiveData<Event2<Boolean, Boolean?>>()
//token 失效
val tokenInvalid = MutableLiveData<Event<Boolean>>()
fun internalOnStarted() {
onStarted()
}
open fun onStarted() = Unit
override val coroutineContext: CoroutineContext
get() = coroutine.coroutineContext
override fun onCleared() {
super.onCleared()
hideLoading()
if (coroutineDelegate.isInitialized()) {
coroutine.destroy()
}
}
fun showToast(text: String?) {
toast.postValue(Event(text))
}
fun showLoading() {
flower.postValue(Event(true))
}
fun hideLoading() {
flower.postValue(Event(false))
}
fun <T : Activity> startActivity(cls: KClass<T>, data: Bundle? = null) {
jump.postValue(Event2(cls, data))
}
fun <T : Activity> startActivityForResult(cls: KClass<T>, requestCode: Int, data: Bundle? = null) {
jumpForResult.postValue(Event3(cls, data, requestCode))
}
fun useActivityBlock(sync: Boolean = false, block: (FragmentActivity) -> Unit) {
if (sync) {
activityBlock.value = Event(block)
} else {
activityBlock.postValue(Event(block))
}
}
fun userActivityForeverBlock(block: (FragmentActivity) -> Unit) {
activityForeverBlock.postValue(Event(block))
}
fun useFragmentBlock(sync: Boolean = false, block: (Fragment) -> Unit) {
if (sync) {
fragmentBlock.value = Event(block)
} else {
fragmentBlock.postValue(Event(block))
}
}
fun setResult(resultCode: Int?, data: Bundle?) {
finishResult.postValue(Event2(resultCode, data))
}
fun finish(finishHostAct: Boolean? = null) {
finish.postValue(Event2(true, finishHostAct))
}
fun delayAction(timeMillis: Long = 500L, func: suspend CoroutineScope.() -> Unit) {
launch {
delay(timeMillis)
func.invoke(this)
}
}
fun launchIO(func: suspend CoroutineScope.() -> Unit) {
launch(Dispatchers.IO, block = func)
}
fun launchWithoutView(func: suspend CoroutineScope.() -> Unit) {
BikeGlobalMainScope.launch(block = func)
}
fun cancelChildren() {
if (coroutineDelegate.isInitialized()) {
coroutine.cancelChildren()
}
}
}
// 辅助类Event示例
open class Event<out T>(private val content: T) {
@Suppress("MemberVisibilityCanBePrivate")
var hasBeenHandled = false
private set // Allow external read but not write
/**
* Returns the content and prevents its use again.
*/
fun getContentIfNotHandled(): T? {
return if (hasBeenHandled) {
null
} else {
hasBeenHandled = true
content
}
}
/**
* Returns the content, even if it's already been handled.
*/
fun peekContent(): T = content
}
2.2、视图层BaseView的封装
这里需要注意的是,BaseView定义辅助的扩展方法
interface BaseBikeView {
fun init(fragment: Fragment) {
getBaseBikeViewProvider().fragment = fragment
getBaseBikeViewProvider().context = fragment.context
}
fun init(activity: AppCompatActivity) {
getBaseBikeViewProvider().activity = activity
getBaseBikeViewProvider().context = activity
}
fun getBaseBikeViewProvider(): BaseBikeViewProvider
fun getBaseActivity(): FragmentActivity? {
return getBaseBikeViewProvider().activity
?: getBaseBikeViewProvider().fragment?.activity as? FragmentActivity
}
fun getBaseFragment(): Fragment? {
return getBaseBikeViewProvider().fragment
}
fun getContext(): Context? {
return getBaseBikeViewProvider().context
}
fun getViewModel(): BaseBikeViewModel? {
return getBaseBikeViewProvider().viewModel
}
fun injectViewModel(viewModel: BaseBikeViewModel) {
getBaseBikeViewProvider().fragment?.apply {
setupExt(this, viewModel)
arguments?.let {
viewModel.data.putAll(it)
}
viewModel.internalOnStarted()
}
getBaseBikeViewProvider().activity?.apply {
setupExt(this, viewModel)
intent.extras?.let {
viewModel.data.putAll(it)
}
viewModel.internalOnStarted()
}
}
fun setupExt(lifecycleOwner: LifecycleOwner, viewModel: BaseBikeViewModel) {
setupToast(lifecycleOwner, viewModel.toast)
setupFlower(lifecycleOwner, viewModel.flower)
setupJump(lifecycleOwner, viewModel.jump)
setupJumpForResult(lifecycleOwner, viewModel.jumpForResult)
setupActivityCallback(lifecycleOwner, viewModel.activityBlock)
setupActivityForeverCallback(lifecycleOwner, viewModel.activityForeverBlock)
setupFragmentCallback(lifecycleOwner, viewModel.fragmentBlock)
setupFinishResult(lifecycleOwner, viewModel.finishResult)
setupFinish(lifecycleOwner, viewModel.finish)
setupTokenInvalid(lifecycleOwner, viewModel.tokenInvalid)
}
}
辅助扩展类分析
fun BaseBikeView.setupToast(
lifecycleOwner: LifecycleOwner,
toastEvent: LiveData<Event<String?>>
) {
if (toastEvent.hasObservers()) {
return
}
toastEvent.observe(lifecycleOwner, EventObserver {
it ?: return@EventObserver
try {
val ctx = getContext() ?: return@EventObserver
HMUIToast.toast(ctx, it)
} catch (e: Exception) {
e.printStackTrace()
}
})
}
fun BaseBikeView.setupFlower(
lifecycleOwner: LifecycleOwner,
flowerEvent: LiveData<Event<Boolean>>) {
if (flowerEvent.hasObservers()) {
return
}
flowerEvent.observe(lifecycleOwner, EventObserver {
if (it) {
getBaseBikeViewProvider().loadingDialog?.show()
} else {
getBaseBikeViewProvider().loadingDialog?.hide()
}
})
}
2.3、BaseFragment初步封装
open class BaseBikeFragment : Fragment(), BaseBikeView, BaseViewModelInterface {
// 暂时没什么用处
private val viewProvider = BaseBikeViewProvider()
override fun getBaseBikeViewProvider(): BaseBikeViewProvider {
return viewProvider
}
override fun getContext(): Context? {
return activity
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
this.init(this)
}
protected fun <T> LiveData<T>.observe(call: (T) -> Unit) {
this.observe(this@BaseBikeFragment, Observer {
call.invoke(it)
})
}
override fun getActivityContext(): AppCompatActivity? {
activity?.let {
return activity as AppCompatActivity
}
return null
}
override fun getFragmentInstance(): Fragment? {
return this
}
override fun isActivityContext(): Boolean {
return false
}
override fun showLoading(msg: String) {
}
override fun hideLoading() {
}
override fun showToast(msg: String) {
activity?.let {
HMUIToast.toast(it, msg)
}
}
override fun getLifecycleOwner(): LifecycleOwner {
return this
}
}
3、MVVM的使用示范
具体某个Fragment
class GlobalNotificationFragment : BaseBikeFragment(){
private lateinit var viewModel: GlobalNotificationViewModel
override fun onActivityCreated(savedInstanceState: Bundle?) {
viewModel = ViewModelProviders.of(this).get(GlobalNotificationViewModel::class.java)
.reverseInject(this)
viewModel.notificationData.observe(this, Observer {
if (it != null) {
...
}
})
viewModel.payResult.observe(this, Observer {
if (it != null) {
...
}
})
// 类似接口获取数据
}
}
// 具体ViewModel的示例
class GlobalNotificationViewModel : BaseBikeViewModel() {
private val globalRepository = GlobalNotificationRepository()
val notificationData = MutableLiveData<NotificationInfo?>()
val payResult = MutableLiveData<CardPayMgrV2.Result?>()
val rideCardNoticeResult = MutableLiveData<BikeRideCardNotice?>()
/**
* 获取全局通知栏
*/
fun getNotification(resource:Int?, from:String?) {
launch {
val response = globalRepository.getNotification(resource = resource,from = from)
val data = response.data
notificationData.postValue(data)
}
}
fun globalNotifyUpdate(resource: Int?, notificationCode: Int?) {
launch {
globalRepository.globalNotifyUpdate(resource = resource,notificationCode = notificationCode)
}
}
fun buyCard(ext: PaymentCombineWayVO?) {
launch {
val response = globalRepository.buyCard(viewModel = this@GlobalNotificationViewModel,pkgsResp = ext?.pkgsResp,pkgGroup = ext?.pkgGroup,pkg = ext?.pkg)
payResult.postValue(response)
}
}
fun loadData(pageFrom: Int?) {
launch {
if (UserManager.isNotLogin()) {
return@launch
}
val accountInfo = BikeAccountCheck.getInstance().getBikeAccountInfo(
if (pageFrom == GlobalNotificationFragment.PAGE_FROM_CONFIRM) {
BikeAccountCheckRequest.FROM_OPEN_LOCK
} else if (pageFrom == GlobalNotificationFragment.PAGE_FROM_HOME) {
BikeAccountCheckRequest.FROM_BANNER
} else {
BikeAccountCheckRequest.FROM_NONE
},
false
)
rideCardNoticeResult?.postValue(accountInfo?.rideCardGuideInfo)
}
}
}
总结
- 其实MVVM使用起来并不复杂,其实也是通过post和observer的方式更好的分离了数据与UI;
- 初步接触这种方式编写的同学可能感到陌生,多联系几次就好。