詳解Android封裝一個全局的BaseActivity
1.前言
- 對于一個Android開發(fā)者來說,每一個頁面都繼承一個單獨的系統(tǒng)Activity,有時候會帶來很多不必要的困擾。比如:每一個頁面會有重復的代碼,閱讀起來麻煩;每一次寫新的頁面功能總要打開原來的頁面代碼拷貝一部分過來;有時候代碼調(diào)試排查問題也不方便等等。
- 如果你的項目里面沒有將Activity都繼承自一個自己封裝的BaseActivity、或者針對自己封裝的BaseActivity覺得還不夠完善的,這篇博客可能會對你有幫助!
2.特點
- 封裝:將所有Activity都用到的一部分代碼封裝到一個統(tǒng)一管理的Activity類(后面全部起名叫BaseActivity),然后由這個BaseActivity繼承自Android系統(tǒng)的AppCompatActivity(一般是這個)。
- 繼承:頁面上用到的Activity都繼承自我們的自己BaseActivity,BaseActivity封裝的方法在Activity內(nèi)直接調(diào)用。
3.代碼及說明
3.1.優(yōu)缺點
- 優(yōu)點:減少了代碼的重復,提高了寫代碼的效率、以及提高了代碼的維護性
- 缺點:不要任何代碼都放在BaseActivity,那樣可能會導致BaseActivity過于臃腫,不利于代碼的閱讀和維護,甚至出現(xiàn)App奔潰
下面會討論哪些代碼應該放在BaseActivity里面,哪些需要謹慎
3.2.代碼
下面我貼一份我自己封裝的BaseActivity,在代碼中和代碼下面做了解釋:
public abstract class BaseActivity extends AppCompatActivity {
public Activity mActivity;
private Unbinder mUnbinder;
private static float sNoncompatDensity;
private static float sNoncompatScaledDensity;
private MaterialDialog mDialog;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
onAdjustLayout();
setContentView(setContentLayout());
//這里的是初始化綁定ButterKnife,在onDestory做了銷毀
mUnbinder = ButterKnife.bind(this);
this.mActivity = this;
//統(tǒng)一將一個activity添加到一個集合里面
AppManager.getInstance().addActivity(mActivity);
initToolBar();
initPresenter();
initData(savedInstanceState);
Log.e("app", this.getClass().getSimpleName() + "------onCreate");
}
@Override
protected void onStart() {
super.onStart();
Log.e("app", this.getClass().getSimpleName() + "------onStart");
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Log.e("app", this.getClass().getSimpleName() + "------onRestoreInstanceState");
}
@Override
protected void onRestart() {
super.onRestart();
Log.e("app", this.getClass().getSimpleName() + "------onRestart");
}
@Override
protected void onResume() {
super.onResume();
Log.e("app", this.getClass().getSimpleName() + "------onResume");
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.e("app", this.getClass().getSimpleName() + "------onSaveInstanceState");
}
@Override
protected void onPause() {
super.onPause();
Log.e("app", this.getClass().getSimpleName() + "------onPause");
}
@Override
protected void onStop() {
super.onStop();
Log.e("app", this.getClass().getSimpleName() + "------onStop");
}
@Override
protected void onDestroy() {
super.onDestroy();
onDestroyActivity();
mUnbinder.unbind();
Log.e("app", this.getClass().getSimpleName() + "------onDestroy");
}
/**
* 顯示一個Fragment
*/
public void showFragment(Fragment fragment) {
if (fragment != null && fragment.isHidden()) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.show(fragment);
fragmentTransaction.commit();
}
}
/**
* 隱藏一個Fragment
*/
public void hideFragment(Fragment fragment) {
if (fragment != null && !fragment.isHidden()) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.hide(fragment);
fragmentTransaction.commit();
}
}
//這是一個設置toolbar標題欄的方法,ToolBarOptions類主要是持有一些id
public void setToolBar(int toolBarId, ToolBarOptions options) {
Toolbar toolbar = findViewById(toolBarId);
if (options.titleId != 0) {
toolbar.setTitle(options.titleId);
} else {
toolbar.setTitle("");
}
if (!TextUtils.isEmpty(options.titleString)) {
toolbar.setTitle(options.titleString);
}
if (options.backgroundColor != 0) {
toolbar.setBackgroundResource(options.backgroundColor);
}
if (options.logoId != 0) {
toolbar.setLogo(options.logoId);
}
setSupportActionBar(toolbar);
if (options.isNeedNavigate) {
toolbar.setNavigationIcon(options.navigateId);
toolbar.setContentInsetStartWithNavigation(0);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!AppUtils.isNotFastClick()) {
return;
}
onNavigateUpClicked();
}
});
}
}
//子類直接調(diào)用展示toast
public void showToast(String s) {
ToastUtil.showToast(this, s);
}
//給子類提供一個獲取activity對象的方式
public Activity getActivity() {
return this;
}
//一個彈窗l(fā)oading庫 github地址:
//implementation 'com.afollestad.material-dialogs:core:0.9.6.0'
public void showLoading(String loadDesc) {
mDialog = new MaterialDialog.Builder(this)
.progress(true, -1)
.content(loadDesc)
.canceledOnTouchOutside(false)
.cancelable(false)
.show();
}
public void showLoading(int resId) {
mDialog = new MaterialDialog.Builder(this)
.progress(true, -1)
.content(getString(resId))
.canceledOnTouchOutside(false)
.cancelable(false)
.show();
}
public void showLoading() {
mDialog = new MaterialDialog.Builder(this)
.progress(true, -1)
.content("加載中...")
.canceledOnTouchOutside(false)
.cancelable(false)
.show();
}
public void hideLoading() {
if (mDialog != null) {
mDialog.dismiss();
}
}
//這里是退出app相關的邏輯,可以根據(jù)自己的退出做具體的處理
public void exitLogin() {
SharedPreferenceUtils.getInstance(mActivity).put(Constant.KEY_LOGIN_TOKEN, "");
if (mDialog != null) {
mDialog.hide();
mDialog = null;
}
mDialog = new MaterialDialog.Builder(this)
.canceledOnTouchOutside(false)
.title("提示")
.content("賬號已在其他地方登錄,請退出重新登錄!")
.positiveText("確定")
.onPositive(new MaterialDialog.SingleButtonCallback() {
@Override
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
AppManager.getInstance().finishAllActivity();
Intent intent = new Intent(mActivity, LoginActivity.class);
startActivity(intent);
finish();
}
}).show();
}
private void onNavigateUpClicked() {
onBackPressed();
}
//開始contentLayout前調(diào)整布局(子類若有需要可以單獨復寫)
public void onAdjustLayout() {
}
//下面這5個方法是子類必須實現(xiàn)的,分別是layout布局、toolbar、mvp的persenter初始化、
//onCreate內(nèi)的initData、以及頁面銷毀的onDestroyActivity(可以根據(jù)自己的需要添加)
public abstract int setContentLayout();
public abstract void initToolBar();
public abstract void initPresenter();
public abstract void initData(Bundle savedInstanceState);
public abstract void onDestroyActivity();
}
3.3.注意點
- 在BaseActivity的每個生命周期內(nèi)都有l(wèi)og日志,這里是方便觀察執(zhí)行到activity的哪個生命周期,logcat也可以簡單封裝一下,統(tǒng)一控制日志是否打印。
- BaseActivity并不適合每一個頁面的Activity,比如進入應用的閃屏頁面,就可以考慮不繼承BaseActivity,因為這個頁面通常不需要寫太多代碼?;蛘哌€有其他特殊的業(yè)務場景下。
- 需要注意一個Dialog彈窗問題,在BaseActivity里面,每次show一個dialog的時候我都是創(chuàng)建一個新的對象,那么就要注意dialog在未關閉之前不能再去show,否則可能會導致dialog出現(xiàn)異常。但是不要在onDestory方法里面去隱藏dialog彈窗,因為在A頁面進入B頁面的時候,會先執(zhí)行到B頁面生命周期的onCreate、onStart、onResume三個方法,然后再執(zhí)行A頁面的onStop可能還有onDestory方法,所以等B頁面加載完成再去銷毀A頁面是錯誤的。
- 有時候為了方便可能有人會把請求Android中權限檢測的方法放在BaseActivity里面,這樣并不是特別合適,因為所有繼承自BaseActivity的頁面都會去檢測權限,這樣會導致用戶體驗差,所以建議用到權限的地方再去請求,最好自己封裝一個工具類,用起來方便一點。
- BaseActivity的封裝并不強求子類必須實現(xiàn)activity生命周期相關的方法,除了幾個抽象方法(我認為子類需要復寫的,可以根據(jù)業(yè)務自己定),必要的話可以自己復寫。
4.總結
不是很復雜,寫的也比較詳細,也基本適用于絕大部分的場景??赡苓€有其他需要注意的細節(jié)回頭想起來再補上。
以上就是詳解Android封裝一個全局的BaseActivity的詳細內(nèi)容,更多關于Android封裝BaseActivity的資料請關注腳本之家其它相關文章!
相關文章
Android中判斷l(xiāng)istview是否滑動到頂部和底部的實現(xiàn)方法
下面小編就為大家分享一篇Android中判斷l(xiāng)istview是否滑動到頂部和底部的實現(xiàn)方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2017-11-11
Flutter底部不規(guī)則導航的實現(xiàn)過程
這篇文章主要給大家介紹了關于Flutter底部不規(guī)則導航的實現(xiàn)過程,文中通過示例代碼介紹的非常詳細,對大家學習或者使用Flutter具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧2019-08-08
Android開發(fā)實現(xiàn)AlertDialog中View的控件設置監(jiān)聽功能分析
這篇文章主要介紹了Android開發(fā)實現(xiàn)AlertDialog中View的控件設置監(jiān)聽功能,結合實例形式分析了Android針對AlertDialog中的控件使用View進行監(jiān)聽的相關操作技巧,需要的朋友可以參考下2017-11-11
Android5.0以上實現(xiàn)全透明的狀態(tài)欄方法(仿網(wǎng)易云界面)
下面小編就為大家分享一篇Android5.0以上實現(xiàn)全透明的狀態(tài)欄方法(仿網(wǎng)易云界面),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-01-01
Android TextView實現(xiàn)跑馬燈效果的方法
這篇文章主要介紹了Android TextView跑馬燈效果實現(xiàn)方法,涉及Android布局文件中相關屬性的設置技巧,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-01-01

