詳解Android封裝一個(gè)全局的BaseActivity
1.前言
- 對(duì)于一個(gè)Android開發(fā)者來說,每一個(gè)頁面都繼承一個(gè)單獨(dú)的系統(tǒng)Activity,有時(shí)候會(huì)帶來很多不必要的困擾。比如:每一個(gè)頁面會(huì)有重復(fù)的代碼,閱讀起來麻煩;每一次寫新的頁面功能總要打開原來的頁面代碼拷貝一部分過來;有時(shí)候代碼調(diào)試排查問題也不方便等等。
- 如果你的項(xiàng)目里面沒有將Activity都繼承自一個(gè)自己封裝的BaseActivity、或者針對(duì)自己封裝的BaseActivity覺得還不夠完善的,這篇博客可能會(huì)對(duì)你有幫助!
2.特點(diǎn)
- 封裝:將所有Activity都用到的一部分代碼封裝到一個(gè)統(tǒng)一管理的Activity類(后面全部起名叫BaseActivity),然后由這個(gè)BaseActivity繼承自Android系統(tǒng)的AppCompatActivity(一般是這個(gè))。
- 繼承:頁面上用到的Activity都繼承自我們的自己BaseActivity,BaseActivity封裝的方法在Activity內(nèi)直接調(diào)用。
3.代碼及說明
3.1.優(yōu)缺點(diǎn)
- 優(yōu)點(diǎn):減少了代碼的重復(fù),提高了寫代碼的效率、以及提高了代碼的維護(hù)性
- 缺點(diǎn):不要任何代碼都放在BaseActivity,那樣可能會(huì)導(dǎo)致BaseActivity過于臃腫,不利于代碼的閱讀和維護(hù),甚至出現(xiàn)App奔潰
下面會(huì)討論哪些代碼應(yīng)該放在BaseActivity里面,哪些需要謹(jǐn)慎
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)一將一個(gè)activity添加到一個(gè)集合里面 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"); } /** * 顯示一個(gè)Fragment */ public void showFragment(Fragment fragment) { if (fragment != null && fragment.isHidden()) { FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction(); fragmentTransaction.show(fragment); fragmentTransaction.commit(); } } /** * 隱藏一個(gè)Fragment */ public void hideFragment(Fragment fragment) { if (fragment != null && !fragment.isHidden()) { FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction(); fragmentTransaction.hide(fragment); fragmentTransaction.commit(); } } //這是一個(gè)設(shè)置toolbar標(biāo)題欄的方法,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); } //給子類提供一個(gè)獲取activity對(duì)象的方式 public Activity getActivity() { return this; } //一個(gè)彈窗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相關(guān)的邏輯,可以根據(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("賬號(hào)已在其他地方登錄,請(qǐng)退出重新登錄!") .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)整布局(子類若有需要可以單獨(dú)復(fù)寫) public void onAdjustLayout() { } //下面這5個(gè)方法是子類必須實(shí)現(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.注意點(diǎn)
- 在BaseActivity的每個(gè)生命周期內(nèi)都有l(wèi)og日志,這里是方便觀察執(zhí)行到activity的哪個(gè)生命周期,logcat也可以簡單封裝一下,統(tǒng)一控制日志是否打印。
- BaseActivity并不適合每一個(gè)頁面的Activity,比如進(jìn)入應(yīng)用的閃屏頁面,就可以考慮不繼承BaseActivity,因?yàn)檫@個(gè)頁面通常不需要寫太多代碼?;蛘哌€有其他特殊的業(yè)務(wù)場景下。
- 需要注意一個(gè)Dialog彈窗問題,在BaseActivity里面,每次show一個(gè)dialog的時(shí)候我都是創(chuàng)建一個(gè)新的對(duì)象,那么就要注意dialog在未關(guān)閉之前不能再去show,否則可能會(huì)導(dǎo)致dialog出現(xiàn)異常。但是不要在onDestory方法里面去隱藏dialog彈窗,因?yàn)樵贏頁面進(jìn)入B頁面的時(shí)候,會(huì)先執(zhí)行到B頁面生命周期的onCreate、onStart、onResume三個(gè)方法,然后再執(zhí)行A頁面的onStop可能還有onDestory方法,所以等B頁面加載完成再去銷毀A頁面是錯(cuò)誤的。
- 有時(shí)候?yàn)榱朔奖憧赡苡腥藭?huì)把請(qǐng)求Android中權(quán)限檢測的方法放在BaseActivity里面,這樣并不是特別合適,因?yàn)樗欣^承自BaseActivity的頁面都會(huì)去檢測權(quán)限,這樣會(huì)導(dǎo)致用戶體驗(yàn)差,所以建議用到權(quán)限的地方再去請(qǐng)求,最好自己封裝一個(gè)工具類,用起來方便一點(diǎn)。
- BaseActivity的封裝并不強(qiáng)求子類必須實(shí)現(xiàn)activity生命周期相關(guān)的方法,除了幾個(gè)抽象方法(我認(rèn)為子類需要復(fù)寫的,可以根據(jù)業(yè)務(wù)自己定),必要的話可以自己復(fù)寫。
4.總結(jié)
不是很復(fù)雜,寫的也比較詳細(xì),也基本適用于絕大部分的場景。可能還有其他需要注意的細(xì)節(jié)回頭想起來再補(bǔ)上。
以上就是詳解Android封裝一個(gè)全局的BaseActivity的詳細(xì)內(nèi)容,更多關(guān)于Android封裝BaseActivity的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Android startActivityForResult的基本用法詳解
- Android activity實(shí)現(xiàn)延時(shí)跳轉(zhuǎn)功能
- Android Studio如何為Activity添加自定義注解信息
- 剖析Android Activity側(cè)滑返回的實(shí)現(xiàn)原理
- 詳解Android中的ActivityThread和APP啟動(dòng)過程
- Android后臺(tái)啟動(dòng)Activity的實(shí)現(xiàn)示例
- 詳解Android Activity中的幾種監(jiān)聽器和實(shí)現(xiàn)方式
- Android ActivityManager使用案例詳解
相關(guān)文章
Android自定義組件獲取本地圖片和相機(jī)拍照?qǐng)D片
這篇文章主要為大家詳細(xì)介紹了Android自定義組件獲取本地圖片和相機(jī)拍照?qǐng)D片的相關(guān)資料,非常炫酷的效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-01-01Android中判斷l(xiāng)istview是否滑動(dòng)到頂部和底部的實(shí)現(xiàn)方法
下面小編就為大家分享一篇Android中判斷l(xiāng)istview是否滑動(dòng)到頂部和底部的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2017-11-11Flutter底部不規(guī)則導(dǎo)航的實(shí)現(xiàn)過程
這篇文章主要給大家介紹了關(guān)于Flutter底部不規(guī)則導(dǎo)航的實(shí)現(xiàn)過程,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Flutter具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08Android藍(lán)牙通信之搜索藍(lán)牙設(shè)備
這篇文章主要介紹了Android藍(lán)牙通信之搜索藍(lán)牙設(shè)備,需要的朋友可以參考下2017-09-09Android控件實(shí)現(xiàn)直播App點(diǎn)贊飄心動(dòng)畫
這篇文章主要為大家詳細(xì)介紹了FlowLikeView控件實(shí)現(xiàn)直播App特效之點(diǎn)贊飄心動(dòng)畫,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-03-03Android開發(fā)實(shí)現(xiàn)AlertDialog中View的控件設(shè)置監(jiān)聽功能分析
這篇文章主要介紹了Android開發(fā)實(shí)現(xiàn)AlertDialog中View的控件設(shè)置監(jiān)聽功能,結(jié)合實(shí)例形式分析了Android針對(duì)AlertDialog中的控件使用View進(jìn)行監(jiān)聽的相關(guān)操作技巧,需要的朋友可以參考下2017-11-11Android5.0以上實(shí)現(xiàn)全透明的狀態(tài)欄方法(仿網(wǎng)易云界面)
下面小編就為大家分享一篇Android5.0以上實(shí)現(xiàn)全透明的狀態(tài)欄方法(仿網(wǎng)易云界面),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-01-01Android TextView實(shí)現(xiàn)跑馬燈效果的方法
這篇文章主要介紹了Android TextView跑馬燈效果實(shí)現(xiàn)方法,涉及Android布局文件中相關(guān)屬性的設(shè)置技巧,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-01-01