都會(huì)需要有用到BaseActivity,從最開始的initData、initView,到后來需要承載監(jiān)聽推送、監(jiān)聽網(wǎng)絡(luò)變化的廣播、延遲鎖定等等各種需求,BaseActivity的功能越來越雜,越來越密集。相對(duì)實(shí)際的頁(yè)面上的功能需求,基類的封裝經(jīng)過這樣長(zhǎng)時(shí)間的無腦堆砌,到最后看起來會(huì)更匪夷所思。所以從一開始,Base的封裝就要足夠清晰、穩(wěn)健、可擴(kuò)展。
AndroidBase
我的思路是分層繼承,每一層只做和這一層功能相關(guān)的事,變動(dòng)修改單一功能都是清晰的,同時(shí)在最后的一層功能又是完整的。
AppCompatActivity
?????????????|
BaseViewActivity
?????????????|
BaseFunctionsActivity
?????????????|
BaseViewModelActivity
?????????????|
BaseMVPActivity
?????????????|
BaseToolbarActivity
1.BaseViewActivity(View層)
主要代碼:
public abstract class BaseViewActivity<VB extends ViewBinding> extends AppCompatActivity
{
private View rootView;
protected VB vBinding;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setRequestedOrientation(getScreenOrientation());//豎屏
vBinding = ViewBindingCreator.createViewBinding(getClass(), getLayoutInflater());
rootView = generateContentView(vBinding == null ? getContentView() : vBinding.getRoot());
setContentView(rootView);
}
protected View getContentView()
{
return null;
}
protected View generateContentView(View contentView)
{
return contentView;
}
protected int getScreenOrientation()
{
return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
}
public void showLoadingDialog()
{
}
public void hideLoadingDialog()
{
}
}
ViewBindingCreator主要代碼:
@SuppressWarnings("unchecked")
public static <VB extends ViewBinding> VB createViewBinding(Class targetClass,
LayoutInflater layoutInflater)
{
Type type = targetClass.getGenericSuperclass();
if (type instanceof ParameterizedType)
{
try
{
Type[] types = ((ParameterizedType) type).getActualTypeArguments();
for (Type type1 : types)
{
if (type1.getTypeName()
.endsWith("Binding"))
{
Method method = ((Class<VB>) type1).getMethod("inflate",
LayoutInflater.class);
return (VB) method.invoke(null, layoutInflater);
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
} return null;
}
public abstract class BaseViewFragment<VB extends ViewBinding> extends Fragment
{
protected VB vBinding;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState)
{
if (vBinding == null)
{
vBinding = ViewBindingCreator.createViewBinding(getClass(), inflater);
View rootView = generateContentView(
vBinding == null ? getContentView() : vBinding.getRoot());
rootView.setBackgroundColor(getResources().getColor(R.color.colorBackgroundTint));
onCreateView(rootView);
}
return vBinding.getRoot();
}
protected abstract void onCreateView(View rootView);
protected View getContentView()
{
return null;
}
protected View generateContentView(View contentView)
{
return contentView;
}
protected void setStatusBarTextDark(boolean isStatusBarTextDark)
{
Activity activity = getActivity();
if (activity instanceof BaseViewActivity)
{
((BaseViewActivity) activity).setStatusBarTextDark(isStatusBarTextDark);
}
}
protected void showLoadingDialog()
{
Activity activity = getActivity();
if (activity instanceof BaseViewActivity)
{
((BaseViewActivity) activity).showLoadingDialog();
}
}
protected void hideLoadingDialog()
{
Activity activity = getActivity();
if (activity instanceof BaseViewActivity)
{
((BaseViewActivity) activity).hideLoadingDialog();
}
}
}
繼承自AppCompatActivity不用說什么了。用ViewModel也是因?yàn)橹坝肂utterKnife,更新了Android Studio4.0之后提示R.id.xxxxx不再是靜態(tài)常量,所以推薦使用ViewBinding的方式,ButterKnife官方也說了不再維護(hù),轉(zhuǎn)用ViewBinding。相對(duì)ButterKnife就是少了那個(gè)對(duì)輸入框 點(diǎn)擊事件的注解方式寫法。我在另一個(gè)文章吐槽過。也還行吧,官方都推薦了 ,應(yīng)該不會(huì)有太大問題。BaseViewActivity內(nèi)主要通過ViewBinding或者getContentView獲取頁(yè)面內(nèi)容View,優(yōu)先看有沒有ViewBinding,沒有的話再用getContentView。ViewBinding這塊用了反射去調(diào)inflate方法來創(chuàng)建對(duì)象。反射是不好,但是為了可以偷懶避免在每個(gè)具體xxxActivity里都寫一遍xxxViewBinding.inflate,只需要在泛型聲明一下xxxViewBinding就可以了。還提供了一個(gè)generateContentView方法,便于子類重載后擴(kuò)充contentView,例如BaseToolbarActivity就是實(shí)現(xiàn)了這個(gè)方法,對(duì)contentView進(jìn)一步包裝后再返回。
在這個(gè)類內(nèi)也可以封裝loadingDialog,Toast什么有關(guān)View的基礎(chǔ)功能。
同時(shí)在寫具體業(yè)務(wù)的Activity或者Fragment時(shí),不需要重載什么新的方法,只需要傳一個(gè)泛型ViewBinding就可以了,減少寫代碼的負(fù)擔(dān)。
2.BaseFunctionsActivity(基礎(chǔ)功能層)
主要代碼:
public abstract class BaseFunctionsActivity<VB extends ViewBinding> extends BaseViewActivity<VB>
{
public static ArrayList<Class<? extends BaseActivityFunction>> functionsClasses = new ArrayList<>();
private LinkedHashMap<String, BaseActivityFunction> functions = new LinkedHashMap<>();
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
for (Class<? extends BaseActivityFunction> functionClass : functionsClasses)
{
try
{
functions.put(functionClass.getName(), functionClass.newInstance());
}
catch (IllegalAccessException | InstantiationException e)
{
e.printStackTrace();
}
}
for (BaseActivityFunction baseActivityFunction : functions.values())
{
baseActivityFunction.onActivityCreated(this, savedInstanceState);
}
}
@Override
protected void onNewIntent(Intent intent)
{
super.onNewIntent(intent);
}
@Override
protected void onSaveInstanceState(@NonNull Bundle outState)
{
super.onSaveInstanceState(outState);
for (BaseActivityFunction baseActivityFunction : functions.values())
{
baseActivityFunction.onActivitySaveInstanceState(this, outState);
}
}
@Override
protected void onStart()
{
super.onStart();
for (BaseActivityFunction baseActivityFunction : functions.values())
{
baseActivityFunction.onActivityStarted(this);
}
}
@Override
protected void onRestart()
{
super.onRestart();
for (BaseActivityFunction baseActivityFunction : functions.values())
{
baseActivityFunction.onActivityRestarted(this);
}
}
@Override
protected void onResume()
{
super.onResume();
for (BaseActivityFunction baseActivityFunction : functions.values())
{
baseActivityFunction.onActivityResumed(this);
}
}
@Override
protected void onPause()
{
super.onPause();
for (BaseActivityFunction baseActivityFunction : functions.values())
{
baseActivityFunction.onActivityPaused(this);
}
}
@Override
protected void onStop()
{
super.onStop();
for (BaseActivityFunction baseActivityFunction : functions.values())
{
baseActivityFunction.onActivityStopped(this);
}
}
@Override
protected void onDestroy()
{
super.onDestroy();
Iterator<BaseActivityFunction> iterator = functions.values()
.iterator();
while (iterator.hasNext())
{
BaseActivityFunction baseActivityFunction = iterator.next();
baseActivityFunction.onActivityDestroyed(this);
baseActivityFunction = null;
iterator.remove();
}
functions = null;
}
@Override
public void onBackPressed()
{
boolean canBackPressed = true;
for (BaseActivityFunction value : functions.values())
{
if (!value.onBeforeBackPressed(this))
{
canBackPressed = false;
}
}
if (canBackPressed)
{
super.onBackPressed();
}
}
@Override
public void finish()
{
super.finish();
for (BaseActivityFunction value : functions.values())
{
value.onFinish(this);
}
}
public BaseActivityFunction getFunction(Class<? extends BaseActivityFunction> fClass)
{
return functions.get(fClass.getName());
}
}
public abstract class BaseActivityFunction implements Application.ActivityLifecycleCallbacks
{
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState)
{
}
@Override
public void onActivityStarted(Activity activity)
{
}
public void onActivityRestarted(Activity activity)
{
}
@Override
public void onActivityResumed(Activity activity)
{
}
@Override
public void onActivityPaused(Activity activity)
{
}
@Override
public void onActivityStopped(Activity activity)
{
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState)
{
}
@Override
public void onActivityDestroyed(Activity activity)
{
}
public void onFinish(Activity activity)
{
}
public boolean onBeforeBackPressed(Activity activity)
{
return true;
}
}
因?yàn)樵诤芏鄨?chǎng)景,都需要基類Activity具有一些功能,檢查是否登錄,監(jiān)聽網(wǎng)絡(luò)變化,嵌入友盟推送等等。本基類封裝庫(kù)又是一個(gè)完整的個(gè)體,所以就會(huì)出現(xiàn)尷尬的情況,基類是A->B->C->D->XXXXX這樣的繼承關(guān)系,但是我又需要在B和C之間插入一個(gè)繼承B1,所以基于此需求,BaseFunctionsActivity通過實(shí)現(xiàn)類似ActivityCallback的方式,提供給外部嵌入內(nèi)部的機(jī)會(huì),通過繼承BaseActivityFunction來實(shí)現(xiàn)不同功能模塊。
比如我想讓整個(gè)應(yīng)用的所有Activity能監(jiān)聽網(wǎng)絡(luò)變化,并Toast提示到界面上,我就只需要?jiǎng)?chuàng)建一個(gè)NetChangeActivityFunction,實(shí)現(xiàn)監(jiān)聽網(wǎng)絡(luò)變化的廣播,把NetChangeActivityFunction.class添加到BaseFunctionsActivity的靜態(tài)functionsClasses中,這樣每個(gè)Activity就具有了NetChangeActivityFunction的功能。如果某一個(gè)具體Activity想調(diào)用NetChangeActivityFunction中的方法時(shí),用getFunction方法可以獲取到當(dāng)前Activity里已經(jīng)實(shí)現(xiàn)的BaseActivityFunction具體對(duì)象,就可以調(diào)用到方法,變量同理。
同時(shí)也提供了對(duì)onBackPressed的攔截,因?yàn)橛泻芏鄨?chǎng)景,需要在onBackPressed時(shí)判斷一些邏輯,再?zèng)Q定是否繼續(xù)執(zhí)行。這塊的重點(diǎn)設(shè)計(jì)的邏輯是,如果一個(gè)Activity有多個(gè)Function,只要其中有一個(gè)Function判定為false就不會(huì)執(zhí)行super.onBackPressed();但是每一個(gè)Function的onBackPressed都會(huì)執(zhí)行一次。暫時(shí)考慮對(duì)每個(gè)Function都公平一點(diǎn),避免出現(xiàn)到某一個(gè)Function的onBackPressed就終止了后面的執(zhí)行。
這樣的在一個(gè)Activity里注入多個(gè)Function的方式有一個(gè)缺點(diǎn)就是每一個(gè)Activity都承載了多個(gè)的Function對(duì)象,如果BaseFunctions很多的話,相對(duì)直接繼承多層Activity的方式,會(huì)占用更多內(nèi)存。
3.BaseViewModelActivity(ViewModel層)
主要代碼:
public abstract class BaseViewModelActivity<VB extends ViewBinding> extends BaseFunctionsActivity<VB>
{
protected final void setViewModelHolder(@NonNull IViewModelHolder iViewModelHolder)
{
iViewModelHolder.setIViewModelOwners(new IViewModelOwners()
{
@Override
public ViewModelStoreOwner getActivityViewModelStoreOwner()
{
return BaseViewModelActivity.this;
}
@Override
public ViewModelStoreOwner getFragmentViewModelStoreOwner()
{
return null;
}
@Override
public LifecycleOwner getActivityLifecycleOwner()
{
return BaseViewModelActivity.this;
}
@Override
public LifecycleOwner getFragmentLifecycleOwner()
{
return null;
}
});
}
}
public interface IViewModelHolder
{
void setIViewModelOwners(IViewModelOwners iViewModel);
void onViewModelLoaded();
}
public interface IViewModelOwners
{
ViewModelStoreOwner getActivityViewModelStoreOwner();
ViewModelStoreOwner getFragmentViewModelStoreOwner();
LifecycleOwner getActivityLifecycleOwner();
LifecycleOwner getFragmentLifecycleOwner();
}
public class BaseViewModelHolder implements IViewModelHolder
{
private IViewModelOwners iViewModelOwners;
private ViewModelProvider activityViewModelProvider;
private ViewModelProvider fragmentViewModelProvider;
@Override
public final void setIViewModelOwners(IViewModelOwners iViewModel)
{
this.iViewModelOwners = iViewModel;
onViewModelLoaded();
}
@Override
public void onViewModelLoaded()
{
}
protected final <VM extends ViewModel> VM getActivityViewModel(Class<VM> vmClass)
{
if (activityViewModelProvider == null)
{
activityViewModelProvider = new ViewModelProvider(
iViewModelOwners.getActivityViewModelStoreOwner(),
new ViewModelProvider.NewInstanceFactory());
}
return activityViewModelProvider.get(vmClass);
}
protected final <VM extends ViewModel> VM getFragmentViewModel(Class<VM> vmClass)
{
if (fragmentViewModelProvider == null)
{
fragmentViewModelProvider = new ViewModelProvider(
iViewModelOwners.getFragmentViewModelStoreOwner(),
new ViewModelProvider.NewInstanceFactory());
}
return fragmentViewModelProvider.get(vmClass);
}
protected final <T> void observeActivityLiveData(LiveData<T> liveData, Observer<T> observer)
{
liveData.observe(iViewModelOwners.getActivityLifecycleOwner(), observer);
}
protected final <T> void observeFragmentLiveData(LiveData<T> liveData, Observer<T> observer)
{
liveData.observe(iViewModelOwners.getFragmentLifecycleOwner(), observer);
}
}
ViewModel這塊也是嘗試了很多種方式,目前保持一個(gè)還算合適的狀態(tài),但是總感覺也不是最好的狀態(tài)。因?yàn)閷?duì)ViewModel和LiveData的學(xué)習(xí)也是近期才開始的,沒有太多的應(yīng)用場(chǎng)景可能理解的不是完全到位。
ViewModel層整體的思路是,因?yàn)閂iewModel需要ViewModelStore才能創(chuàng)建,LiveData又需要LifeCycle,這兩個(gè)需要都集中在ComponentActivity和Fragment這兩個(gè)宿主中,但是ViewModel的創(chuàng)建又不能直接持有宿主的引用,ViewModel的使用場(chǎng)景絕大部分又應(yīng)該都是在Presenter的內(nèi)部。在一個(gè)宿主中可能存在多個(gè)ViewModel,ViewModel就要發(fā)源于宿主,在Presenter中被引用和使用。還有個(gè)限制是不希望ViewModel層高于MVP層,因?yàn)橄M鸐VP層是具體使用場(chǎng)景中比較主要的,整體的架構(gòu)還是圍繞MVP的,ViewModel相關(guān)的只是附加提供的功能。
因?yàn)锳ctivity和Fragment都具有ViewModelStoreOwner和LifeCycleOwner的屬性,所以把他們兩個(gè)類里總計(jì)四個(gè)屬性:ActivityViewModelStoreOwner、ActivityLifeCycleOwner、FragmentViewModelStoreOwner和FragmentLifeCycleOwner抽象為一個(gè)新的對(duì)象IViewModelOwners(這個(gè)名字不太妥,之后得改)。這樣的新對(duì)象就是脫離了Activity和Fragment的限制的,是超越了他們的。為什么一定要拆分成四個(gè)方法而不是兩個(gè),是因?yàn)橛械臅r(shí)候需要在Fragment里用到Fragment所附著的Activity的ViewModel,所以只能拆分開。
在BaseViewModelHolder中,通過IViewModelOwners接口在Activity和Fragment中獲取到ViewModelStoreOwner和LifeCycleOwner,可以創(chuàng)建出ViewModelProvider,再通過對(duì)應(yīng)的activityViewModelProvider或者fragmentViewModelProvider創(chuàng)建出需要的ViewModel。LiveData的觀測(cè)也是發(fā)在BaseViewModelHolder中。之后讓BasePresenter繼承自BaseViewModelHolder就可以獲得到對(duì)應(yīng)的創(chuàng)建ViewModel和觀測(cè)LiveData功能了。
BaseMVPActivity(MVP層)
主要代碼:
public abstract class BaseMVPActivity<Presenter extends BaseContract.Presenter, VB extends ViewBinding> extends BaseViewModelActivity<VB> implements BaseContract.View
{
protected Presenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
presenter = createPresenter();
if (presenter != null)
{
setViewModelHolder(presenter);
}
}
@Override
public void showLoading()
{
showLoadingDialog();
}
@Override
public void hideLoading()
{
hideLoadingDialog();
}
@Override
public void message(String message)
{
ToastUtil.toast(message);
}
protected Presenter createPresenter()
{
return null;
}
@Override
protected void onDestroy()
{
super.onDestroy();
if (presenter != null)
{
presenter.detachView();
}
}
}
public interface BaseContract
{
interface View
{
void showLoading();
void hideLoading();
void message(String message);
}
interface Presenter extends IViewModelHolder
{
boolean viewNotNull();
void detachView();
}
}
public abstract class BasePresenter<View extends BaseContract.View> extends BaseViewModelHolder implements BaseContract.Presenter
{
protected View view;
protected BasePresenter(View view)
{
this.view = view;
}
@Override
public boolean viewNotNull()
{
return this.view != null;
}
@Override
public void detachView()
{
this.view = null;
}
protected <VM extends ViewModel> VM getViewModel(Class<VM> vmClass)
{
if (view instanceof Fragment)
{
return getFragmentViewModel(vmClass);
}
return getActivityViewModel(vmClass);
}
protected <T> void observeLiveData(LiveData<T> liveData, Observer<T> observer)
{
if (view instanceof Fragment)
{
observeFragmentLiveData(liveData, getMVPObserver(observer));
}
else
{
observeActivityLiveData(liveData, getMVPObserver(observer));
}
}
private <T> Observer<T> getMVPObserver(Observer<T> observer)
{
return t -> {
if (viewNotNull())
{
observer.onChanged(t);
}
};
}
}
MVP的封裝還是比較基礎(chǔ)的,BaseContract內(nèi)含View和Presenter的接口,Activity持有Presenter的引用,Presenter持有View的引用,同時(shí)BasePresenter繼承了BaseViewModelHolder,也就有了M層的功能,但是又相對(duì)BaseContract的這一套是獨(dú)立的,ViewModel相關(guān)并不與MVP強(qiáng)相關(guān)。同時(shí)對(duì)獲取ViewModel做了進(jìn)一步封裝,減少BasePresenter子類使用ViewModel時(shí)的判斷邏輯。BaseMVPActivity還是和BaseViewActivity一樣,在繼承沒有強(qiáng)制需要實(shí)現(xiàn)的方法,增加了Presenter的泛型,自主去實(shí)現(xiàn)createPresenter方法,實(shí)現(xiàn)了之后自然就需要讓Activity實(shí)現(xiàn)XXXContract.View的接口。
舉例創(chuàng)建一個(gè)Activity:通過在文件夾右鍵單擊 New->Activity->Empty Activity創(chuàng)建一個(gè)TestActivity,自動(dòng)創(chuàng)建好后只需要把繼承的AppCompatActivity修改為BaseMVPActivity(也可以根據(jù)需要繼承自BaseToolbarActivity)。這時(shí)都不需要實(shí)現(xiàn)任何抽象方法,只需要在BaseMVPActivity上配置泛型就可以,但是Presenter的創(chuàng)建還是要主動(dòng)實(shí)現(xiàn)一個(gè)父類的createPresenter()方法。
這樣寫起代碼來都是順暢的,比如要新建一個(gè)頁(yè)面,就是先新建一個(gè)XXXContract類,想好這個(gè)頁(yè)面可能會(huì)有那些功能和回調(diào),去定義View和Presenter的方法,然后新建一個(gè)XXXPresenter類實(shí)現(xiàn)XXXContract.Presenter接口,可以暫時(shí)不寫具體功能,然后再創(chuàng)建一個(gè)XXXActivity,把XXXViewBinding和XXXPresenter泛型配置好。這時(shí)候可以先去寫XXXViewBinding的布局頁(yè)面,也可以先寫XXXPresenter中的業(yè)務(wù)邏輯。腦袋里想好要改頁(yè)面的東西,那就去關(guān)注xml布局,想改業(yè)務(wù)邏輯就去XXXModel或者XXXPresenter,相互之間都不干擾。git提交時(shí)也可以一眼看出來這次提交是修改了業(yè)務(wù)還是布局,減少出錯(cuò)。