Android 基类BaseActivity的封装

来源:互联网 发布:中国能源研究会 知乎 编辑:程序博客网 时间:2024/06/08 19:47

转自:http://blog.csdn.net/black_dreamer/article/details/69666961

摘要

本篇总结了前人写的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);}
  • 1
  • 2
  • 3
  • 4

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

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

public abstract void initData();public abstract void initView();
  • 1
  • 2
  • 3
  • 4

然后在setContentView里去调用,一般都是先initView,然后再initData:

 @Overridepublic void setContentView(@LayoutRes int layoutResID) {    super.setContentView(layoutResID);    initView();    initData();}@Overridepublic void setContentView(View view) {    super.setContentView(view);    initView();    initData();}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

这样子类里都必须重写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()) ;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

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

界面间跳转传参

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

@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    ......    if (savedInstanceState != null) {            initParam(savedInstanceState);        } else if (getIntent() != null && getIntent().getExtras() != null) {            initParam(getIntent().getExtras());    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

然后把initParam()方法暴露给子类:

protected void initParam(Bundle bundle) {}
  • 1
  • 2
  • 3
  • 4

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

调试和吐司

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

public class TApplication extends Application {    public static boolean isDebug = true ;    public static String APP_NAME  ;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

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

public void TLog(String msg) {    if (isDebug) {        Log.d(APP_NAME, msg);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

这样一键关闭调试,不用去一个个删项目里的Log信息,是不是很赞?

每次Toast,都用Toast.makeText(...).show();是不是很烦?那么可以在BaseActivity里封装下,比如:

public void toast(String text) {    ToastUtils.show(text);}public void toast(int resId) {    ToastUtils.show(String.valueOf(resId));}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

这里ToastUtils就是一个Toast封装类,里面的内容估计大家都懂。然后这样一来,所有子类在使用时,只需要潇洒写一句toast("xxxx")就行了,当然也可以一并封装Toast.LENGTH_LONGToast.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 */@Overridepublic 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);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

上面3个方法也是很实用的。dispatchTouchEvent方法不需要手动调用,只要是有点击事件,并且点击在软键盘和EditText区域外,就会隐藏软键盘。

防止快速点击

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

 private boolean fastClick() {    long lastClick = 0;    if (System.currentTimeMillis() - lastClick <= 1000) {        return false;    }    lastClick = System.currentTimeMillis();    return true;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

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

/** View点击 **/public abstract void widgetClick(View v);@Overridepublic void onClick(View v) {    if (fastClick())        widgetClick(v);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

这个写法的话,就是子类必须重写widgetClick(View v)这个方法,其实就是onClick外面又封装了一层。使用的时候,把widgetClick当做onClick就行。个人不喜欢BaseActivity里写一堆abstract方法,所以这个widgetClick可以酌情参考。

页面跳转: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);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

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

是否允许全屏

设置一个成员变量mAllowFullScreen:

/** 是否允许全屏 **/private boolean mAllowFullScreen = true;
  • 1
  • 2
  • 3

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

if (mAllowFullScreen) {            this.getWindow().setFlags(                    WindowManager.LayoutParams.FLAG_FULLSCREEN,                    WindowManager.LayoutParams.FLAG_FULLSCREEN);            requestWindowFeature(Window.FEATURE_NO_TITLE);        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

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

 public void setAllowFullScreen(boolean allowFullScreen) {    this.mAllowFullScreen = allowFullScreen;}
  • 1
  • 2
  • 3
  • 4

设置沉浸式状态栏

跟设置全屏一样一样的:

/** 是否沉浸状态栏 **/private boolean isSetStatusBar = true;
  • 1
  • 2
  • 3

然后BaseActivity的onCreate里:

if (isSetStatusBar) {            steepStatusBar();        }
  • 1
  • 2
  • 3
  • 4

然后定义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);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

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

/** * 是否设置沉浸状态栏 * @param isSetStatusBar */public void setSteepStatusBar(boolean isSetStatusBar) {    this.isSetStatusBar = isSetStatusBar;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

设置是否允许屏幕旋转

跟前面两种思路一样,通过判断变量,在onCreate里设置咯:

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

BaseActivity里的onCreate方法:

if (!isAllowScreenRoate) {            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);        } else {            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

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

public void setScreenRoate(boolean isAllowScreenRoate) {    this.isAllowScreenRoate = isAllowScreenRoate;}
  • 1
  • 2
  • 3
  • 4

总结

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


原创粉丝点击