Android 基類BaseActivity的封裝

摘要
本篇總結(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è)匯總恍飘,然后按需使用唄。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末冀泻,一起剝皮案震驚了整個(gè)濱河市常侣,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌弹渔,老刑警劉巖胳施,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異肢专,居然都是意外死亡舞肆,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門博杖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來椿胯,“玉大人,你說我怎么就攤上這事剃根×ぃ” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵狈醉,是天一觀的道長廉油。 經(jīng)常有香客問我,道長苗傅,這世上最難降的妖魔是什么抒线? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮渣慕,結(jié)果婚禮上嘶炭,老公的妹妹穿的比我還像新娘。我一直安慰自己逊桦,他們只是感情好眨猎,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著强经,像睡著了一般宵呛。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上夕凝,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天宝穗,我揣著相機(jī)與錄音,去河邊找鬼码秉。 笑死逮矛,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的转砖。 我是一名探鬼主播须鼎,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼府蔗!你這毒婦竟也來了晋控?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤姓赤,失蹤者是張志新(化名)和其女友劉穎赡译,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體不铆,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蝌焚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了誓斥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片只洒。...
    茶點(diǎn)故事閱讀 39,696評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖劳坑,靈堂內(nèi)的尸體忽然破棺而出毕谴,到底是詐尸還是另有隱情,我是刑警寧澤距芬,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布涝开,位于F島的核電站,受9級特大地震影響蔑穴,放射性物質(zhì)發(fā)生泄漏忠寻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一存和、第九天 我趴在偏房一處隱蔽的房頂上張望奕剃。 院中可真熱鬧,春花似錦捐腿、人聲如沸纵朋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽操软。三九已至,卻和暖如春宪祥,著一層夾襖步出監(jiān)牢的瞬間聂薪,已是汗流浹背家乘。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留藏澳,地道東北人仁锯。 一個(gè)月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像翔悠,于是被迫代替她去往敵國和親业崖。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容