Android 基类BaseActivity的封装

摘要
本篇总结了前人写的BaseActivity,自己在开发过程中也添添补补,删删改改,现在总结下。

本篇很多知识借鉴和学习了知乎上iYng大大的回答,先感谢一波。顺便上原文链接:
https://www.zhihu.com/question/47045239/answer/105086885

正文
一般来说,不同的项目的BaseActivity不尽相同,根据不同的业务逻辑和功能需求,会有很多区别。这里总结了一些,如下:

视图相关
一般的Activity里都会用到很多的findViewById这个方法,而且每次都要强制类型转换,这样会显得很繁琐,如果在BaseActivity里封装好,就能省事:

protected <T extends View> T findView(int id) {
    return (T) findViewById(id);
}

这样只要是继承了BaseActivity就能轻松使用LinearLayout llContent = findView(R.id.ll_content);,免去了诸多类型转换的麻烦。

然后说起视图,一般的Activity里都会需要初始化视图和数据,所以可以暴露两个方法initView()和initData():

ublic abstract void initData();
public abstract void initView();

然后在setContentView里去调用,一般都是先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()了,逻辑也能清晰点,不然什么东西都放在onCreate里,就很乱了;

用户模块(业务相关【可选】)
不过一般的app,只要是有登录的,就会有用户模块,也会根据用户标识id去进行一些网络操作,所以用户模块可以在BaseActivity中暴露一些方法,比如用户id的获取:

public int getUid() {
    if (UserManager().getUid() != null) {
        if (UserManager().getUid().equals("")) {
            return 0 ;
        }
    }
    return Integer.parseInt(UserManager().getUid()) ;
}

这里就是返回了SharedPreference里存储的用户id,在用户id大量被使用的场景下,这样的封装还是很有必要的,使用起来也更便捷。当然如果只是纯展示的app就不一定需要了,或许显得多余。

界面间跳转传参
很多时候,Activity之间都会传参,所以可以封装一个参数处理的函数initParam(),在BaseActivity的onCreate里去判断是否有参数传过来;

@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) {

}

这个方法并不是必须重写的,因为传参也没有想象中那么多,并不需要强制重写这个方法。

调试和吐司

一般会在Application类里去定义一个isDebug来判断是否开启调试(开发者模式):

public class TApplication extends Application {

    public static boolean isDebug = true ;
    public static String APP_NAME  ;
}

在BaseActivity里,我们可以把isDebug作为总开关,然后控制是否显示调试信息:

public void TLog(String msg) {
    if (isDebug) {
        Log.d(APP_NAME, msg);
    }
}

这样一键关闭调试,不用去一个个删项目里的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就是一个Toast封装类,里面的内容估计大家都懂。然后这样一来,所有子类在使用时,只需要潇洒写一句toast("xxxx")就行了,当然也可以一并封装Toast.LENGTH_LONG和Toast.LENGTH_SHORT,按需封装吧。

其他
软键盘
有的app里,用户输入的情景会比较多,这个时候,软键盘的隐藏就用的多了,用户输入完之后,或者用户点击屏幕空白处,都应该去隐藏软键盘,这样的话,可以考虑在BaseActivity里写隐藏的方法:

/**
 * 隐藏软件盘
 */
public void hideSoftInput() {
    InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
    if (getCurrentFocus() != null) {
        imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
    }
}

/**
 * 点击软键盘之外的空白处,隐藏软件盘
 * @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);
    }
    // 必不可少,否则所有的组件都不会有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个方法也是很实用的。dispatchTouchEvent方法不需要手动调用,只要是有点击事件,并且点击在软键盘和EditText区域外,就会隐藏软键盘。

防止快速点击
有时候,用户(特别是测试猿)会疯狂的点击app,这一举动的原因和意义不明,但是我们可以设置防止快速点击给app造成的伤害和负担:

private boolean fastClick() {
    long lastClick = 0;
    if (System.currentTimeMillis() - lastClick <= 1000) {
        return false;
    }
    lastClick = System.currentTimeMillis();
    return true;
}

这样在1秒之内只会响应一次,麻麻再也不用担心我手抽筋乱点了。
那么怎么用呢?举个栗子,可以在onClick接口里去判断下嘛:

/** View点击 **/
public abstract void widgetClick(View v);

@Override
public void onClick(View v) {
    if (fastClick())
        widgetClick(v);
}

页面跳转:startActivity、startActivityForResult
这个也是可选的,可以封装下,达到每次跳转不需要传this或者XXXXX.this这种参数:

public void startActivity(Class<?> clz) {
    startActivity(clz, null);
}

/**
 *携带数据的页面跳转
 * @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);
}

这些方法还是很便捷的,使用时可以简单的使用startActivity(MainActivity.class);,也可以传Bundle参数。

是否允许全屏
设置一个成员变量mAllowFullScreen

/** 是否允许全屏 **/
private boolean mAllowFullScreen = true;

通过在BaseActivity的onCreate方法里判断mAllowFullScreen来设置是否允许全屏:

if (mAllowFullScreen) {
            this.getWindow().setFlags(
                    WindowManager.LayoutParams.FLAG_FULLSCREEN,
                    WindowManager.LayoutParams.FLAG_FULLSCREEN);
            requestWindowFeature(Window.FEATURE_NO_TITLE);
        }

然后给子类暴露一个方法来设置mAllowFullScreen:

 public void setAllowFullScreen(boolean allowFullScreen) {
    this.mAllowFullScreen = allowFullScreen;
}

设置沉浸式状态栏
跟设置全屏一样一样的:

/** 是否沉浸状态栏 **/
private boolean isSetStatusBar = true;

然后BaseActivity的onCreate里:

if (isSetStatusBar) {
            steepStatusBar();
        }

然后定义steepStatusBar()方法,用来设置沉浸式状态栏:

private void steepStatusBar() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        // 透明状态栏
        getWindow().addFlags(
                WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        // 透明导航栏
        getWindow().addFlags(
                WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
    }
}

这里就要判断系统版本了。只有在KITKAT以上才有作用。
最后给子类暴露方法,设置 isSetStatusBar的值:

/**
 * 是否设置沉浸状态栏
 * @param isSetStatusBar
 */
public void setSteepStatusBar(boolean isSetStatusBar) {
    this.isSetStatusBar = isSetStatusBar;
}

设置是否允许屏幕旋转
跟前面两种思路一样,通过判断变量,在onCreate里设置咯:

/** 是否禁止旋转屏幕 **/
private boolean isAllowScreenRoate = false;

BaseActivity里的onCreate方法:

if (!isAllowScreenRoate) {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        } else {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        }

最后暴露方法设置isAllowScreenRoate的值:

public void setScreenRoate(boolean isAllowScreenRoate) {
    this.isAllowScreenRoate = isAllowScreenRoate;
}

总结
上面的这些方法大都是比较常用的,有些虽然不是很常用,但是写了也会方便一点,把这篇文章当做一个汇总,然后按需使用呗。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容