摘要
本篇總結(jié)了前人寫的BaseActivity螟蒸,自己在開發(fā)過程中也添添補(bǔ)補(bǔ)政溃,刪刪改改,現(xiàn)在總結(jié)下留储。
本篇很多知識(shí)借鑒和學(xué)習(xí)了知乎上iYng大大的回答翼抠,先感謝一波。順便上原文鏈接:
https://www.zhihu.com/question/47045239/answer/105086885
正文
一般來說获讳,不同的項(xiàng)目的BaseActivity不盡相同阴颖,根據(jù)不同的業(yè)務(wù)邏輯和功能需求,會(huì)有很多區(qū)別丐膝。這里總結(jié)了一些量愧,如下:
視圖相關(guān)
一般的Activity里都會(huì)用到很多的findViewById這個(gè)方法钾菊,而且每次都要強(qiáng)制類型轉(zhuǎn)換,這樣會(huì)顯得很繁瑣侠畔,如果在BaseActivity里封裝好结缚,就能省事:
protected <T extends View> T findView(int id) {
return (T) findViewById(id);
}
這樣只要是繼承了BaseActivity就能輕松使用LinearLayout llContent = findView(R.id.ll_content);,免去了諸多類型轉(zhuǎn)換的麻煩软棺。
然后說起視圖红竭,一般的Activity里都會(huì)需要初始化視圖和數(shù)據(jù),所以可以暴露兩個(gè)方法initView()和initData():
ublic abstract void initData();
public abstract void initView();
然后在setContentView里去調(diào)用喘落,一般都是先initView茵宪,然后再initData:
@Override
public void setContentView(@LayoutRes int layoutResID) {
super.setContentView(layoutResID);
initView();
initData();
}
@Override
public void setContentView(View view) {
super.setContentView(view);
initView();
initData();
}
這樣子類里都必須重寫initView()和initData()了,邏輯也能清晰點(diǎn)瘦棋,不然什么東西都放在onCreate里稀火,就很亂了;
用戶模塊(業(yè)務(wù)相關(guān)【可選】)
不過一般的app赌朋,只要是有登錄的凰狞,就會(huì)有用戶模塊,也會(huì)根據(jù)用戶標(biāo)識(shí)id去進(jìn)行一些網(wǎng)絡(luò)操作沛慢,所以用戶模塊可以在BaseActivity中暴露一些方法赡若,比如用戶id的獲取:
public int getUid() {
if (UserManager().getUid() != null) {
if (UserManager().getUid().equals("")) {
return 0 ;
}
}
return Integer.parseInt(UserManager().getUid()) ;
}
這里就是返回了SharedPreference里存儲(chǔ)的用戶id团甲,在用戶id大量被使用的場景下逾冬,這樣的封裝還是很有必要的,使用起來也更便捷躺苦。當(dāng)然如果只是純展示的app就不一定需要了身腻,或許顯得多余。
界面間跳轉(zhuǎn)傳參
很多時(shí)候匹厘,Activity之間都會(huì)傳參嘀趟,所以可以封裝一個(gè)參數(shù)處理的函數(shù)initParam(),在BaseActivity的onCreate里去判斷是否有參數(shù)傳過來愈诚;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
......
if (savedInstanceState != null) {
initParam(savedInstanceState);
} else if (getIntent() != null && getIntent().getExtras() != null) {
initParam(getIntent().getExtras());
}
}
然后把initParam()方法暴露給子類:
protected void initParam(Bundle bundle) {
}
這個(gè)方法并不是必須重寫的去件,因?yàn)閭鲄⒁矝]有想象中那么多,并不需要強(qiáng)制重寫這個(gè)方法扰路。
調(diào)試和吐司
一般會(huì)在Application類里去定義一個(gè)isDebug來判斷是否開啟調(diào)試(開發(fā)者模式):
public class TApplication extends Application {
public static boolean isDebug = true ;
public static String APP_NAME ;
}
在BaseActivity里,我們可以把isDebug作為總開關(guān)倔叼,然后控制是否顯示調(diào)試信息:
public void TLog(String msg) {
if (isDebug) {
Log.d(APP_NAME, msg);
}
}
這樣一鍵關(guān)閉調(diào)試汗唱,不用去一個(gè)個(gè)刪項(xiàng)目里的Log信息,是不是很贊丈攒?
每次Toast哩罪,都用Toast.makeText(...).show();是不是很煩授霸?那么可以在BaseActivity里封裝下,比如:
public void toast(String text) {
ToastUtils.show(text);
}
public void toast(int resId) {
ToastUtils.show(String.valueOf(resId));
}
這里ToastUtils就是一個(gè)Toast封裝類际插,里面的內(nèi)容估計(jì)大家都懂碘耳。然后這樣一來,所有子類在使用時(shí)框弛,只需要瀟灑寫一句toast("xxxx")就行了辛辨,當(dāng)然也可以一并封裝Toast.LENGTH_LONG和Toast.LENGTH_SHORT,按需封裝吧瑟枫。
其他
軟鍵盤
有的app里斗搞,用戶輸入的情景會(huì)比較多,這個(gè)時(shí)候慷妙,軟鍵盤的隱藏就用的多了僻焚,用戶輸入完之后,或者用戶點(diǎn)擊屏幕空白處膝擂,都應(yīng)該去隱藏軟鍵盤虑啤,這樣的話,可以考慮在BaseActivity里寫隱藏的方法:
/**
* 隱藏軟件盤
*/
public void hideSoftInput() {
InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
if (getCurrentFocus() != null) {
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
}
}
/**
* 點(diǎn)擊軟鍵盤之外的空白處架馋,隱藏軟件盤
* @param ev
* @return
*/
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
View v = getCurrentFocus();
if (ToolUtil.isShouldHideInput(v, ev)) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
}
return super.dispatchTouchEvent(ev);
}
// 必不可少狞山,否則所有的組件都不會(huì)有TouchEvent了
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
/**
* 顯示軟鍵盤
*/
public void showInputMethod(){
if (getCurrentFocus() != null){
InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
imm.showSoftInputFromInputMethod(getCurrentFocus().getWindowToken(),0);
}
}
上面3個(gè)方法也是很實(shí)用的。dispatchTouchEvent方法不需要手動(dòng)調(diào)用绩蜻,只要是有點(diǎn)擊事件铣墨,并且點(diǎn)擊在軟鍵盤和EditText區(qū)域外,就會(huì)隱藏軟鍵盤办绝。
防止快速點(diǎn)擊
有時(shí)候伊约,用戶(特別是測試猿)會(huì)瘋狂的點(diǎn)擊app,這一舉動(dòng)的原因和意義不明孕蝉,但是我們可以設(shè)置防止快速點(diǎn)擊給app造成的傷害和負(fù)擔(dān):
private boolean fastClick() {
long lastClick = 0;
if (System.currentTimeMillis() - lastClick <= 1000) {
return false;
}
lastClick = System.currentTimeMillis();
return true;
}
這樣在1秒之內(nèi)只會(huì)響應(yīng)一次屡律,麻麻再也不用擔(dān)心我手抽筋亂點(diǎn)了。
那么怎么用呢降淮?舉個(gè)栗子超埋,可以在onClick接口里去判斷下嘛:
/** View點(diǎn)擊 **/
public abstract void widgetClick(View v);
@Override
public void onClick(View v) {
if (fastClick())
widgetClick(v);
}
頁面跳轉(zhuǎn):startActivity、startActivityForResult
這個(gè)也是可選的佳鳖,可以封裝下霍殴,達(dá)到每次跳轉(zhuǎn)不需要傳this或者XXXXX.this這種參數(shù):
public void startActivity(Class<?> clz) {
startActivity(clz, null);
}
/**
*攜帶數(shù)據(jù)的頁面跳轉(zhuǎn)
* @param clz
* @param bundle
*/
public void startActivity(Class<?> clz, Bundle bundle) {
Intent intent = new Intent();
intent.setClass(this, clz);
if (bundle != null) {
intent.putExtras(bundle);
}
startActivity(intent);
}
/**
* 含有Bundle通過Class打開編輯界面
*
* @param cls
* @param bundle
* @param requestCode
*/
public void startActivityForResult(Class<?> cls, Bundle bundle,
int requestCode) {
Intent intent = new Intent();
intent.setClass(this, cls);
if (bundle != null) {
intent.putExtras(bundle);
}
startActivityForResult(intent, requestCode);
}
這些方法還是很便捷的,使用時(shí)可以簡單的使用startActivity(MainActivity.class);系吩,也可以傳Bundle參數(shù)来庭。
是否允許全屏
設(shè)置一個(gè)成員變量mAllowFullScreen
/** 是否允許全屏 **/
private boolean mAllowFullScreen = true;
通過在BaseActivity的onCreate方法里判斷mAllowFullScreen來設(shè)置是否允許全屏:
if (mAllowFullScreen) {
this.getWindow().setFlags(
WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
requestWindowFeature(Window.FEATURE_NO_TITLE);
}
然后給子類暴露一個(gè)方法來設(shè)置mAllowFullScreen:
public void setAllowFullScreen(boolean allowFullScreen) {
this.mAllowFullScreen = allowFullScreen;
}
設(shè)置沉浸式狀態(tài)欄
跟設(shè)置全屏一樣一樣的:
/** 是否沉浸狀態(tài)欄 **/
private boolean isSetStatusBar = true;
然后BaseActivity的onCreate里:
if (isSetStatusBar) {
steepStatusBar();
}
然后定義steepStatusBar()方法,用來設(shè)置沉浸式狀態(tài)欄:
private void steepStatusBar() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// 透明狀態(tài)欄
getWindow().addFlags(
WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
// 透明導(dǎo)航欄
getWindow().addFlags(
WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
}
}
這里就要判斷系統(tǒng)版本了穿挨。只有在KITKAT以上才有作用月弛。
最后給子類暴露方法肴盏,設(shè)置 isSetStatusBar的值:
/**
* 是否設(shè)置沉浸狀態(tài)欄
* @param isSetStatusBar
*/
public void setSteepStatusBar(boolean isSetStatusBar) {
this.isSetStatusBar = isSetStatusBar;
}
設(shè)置是否允許屏幕旋轉(zhuǎn)
跟前面兩種思路一樣,通過判斷變量帽衙,在onCreate里設(shè)置咯:
/** 是否禁止旋轉(zhuǎn)屏幕 **/
private boolean isAllowScreenRoate = false;
BaseActivity里的onCreate方法:
if (!isAllowScreenRoate) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
} else {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
最后暴露方法設(shè)置isAllowScreenRoate的值:
public void setScreenRoate(boolean isAllowScreenRoate) {
this.isAllowScreenRoate = isAllowScreenRoate;
}
總結(jié)
上面的這些方法大都是比較常用的菜皂,有些雖然不是很常用,但是寫了也會(huì)方便一點(diǎn)厉萝,把這篇文章當(dāng)做一個(gè)匯總恍飘,然后按需使用唄。