详解Android封装一个全局的BaseActivity
作者:还吹着风、 发布时间:2022-09-16 07:05:23
1.前言
对于一个Android开发者来说,每一个页面都继承一个单独的系统Activity,有时候会带来很多不必要的困扰。比如:每一个页面会有重复的代码,阅读起来麻烦;每一次写新的页面功能总要打开原来的页面代码拷贝一部分过来;有时候代码调试排查问题也不方便等等。
如果你的项目里面没有将Activity都继承自一个自己封装的BaseActivity、或者针对自己封装的BaseActivity觉得还不够完善的,这篇博客可能会对你有帮助!
2.特点
封装:将所有Activity都用到的一部分代码封装到一个统一管理的Activity类(后面全部起名叫BaseActivity),然后由这个BaseActivity继承自Android系统的AppCompatActivity(一般是这个)。
继承:页面上用到的Activity都继承自我们的自己BaseActivity,BaseActivity封装的方法在Activity内直接调用。
3.代码及说明
3.1.优缺点
优点:减少了代码的重复,提高了写代码的效率、以及提高了代码的维护性
缺点:不要任何代码都放在BaseActivity,那样可能会导致BaseActivity过于臃肿,不利于代码的阅读和维护,甚至出现App奔溃
下面会讨论哪些代码应该放在BaseActivity里面,哪些需要谨慎
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;
//统一将一个activity添加到一个集合里面
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");
}
/**
* 显示一个Fragment
*/
public void showFragment(Fragment fragment) {
if (fragment != null && fragment.isHidden()) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.show(fragment);
fragmentTransaction.commit();
}
}
/**
* 隐藏一个Fragment
*/
public void hideFragment(Fragment fragment) {
if (fragment != null && !fragment.isHidden()) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.hide(fragment);
fragmentTransaction.commit();
}
}
//这是一个设置toolbar标题栏的方法,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();
}
});
}
}
//子类直接调用展示toast
public void showToast(String s) {
ToastUtil.showToast(this, s);
}
//给子类提供一个获取activity对象的方式
public Activity getActivity() {
return this;
}
//一个弹窗loading库 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相关的逻辑,可以根据自己的退出做具体的处理
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("账号已在其他地方登录,请退出重新登录!")
.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前调整布局(子类若有需要可以单独复写)
public void onAdjustLayout() {
}
//下面这5个方法是子类必须实现的,分别是layout布局、toolbar、mvp的persenter初始化、
//onCreate内的initData、以及页面销毁的onDestroyActivity(可以根据自己的需要添加)
public abstract int setContentLayout();
public abstract void initToolBar();
public abstract void initPresenter();
public abstract void initData(Bundle savedInstanceState);
public abstract void onDestroyActivity();
}
3.3.注意点
在BaseActivity的每个生命周期内都有log日志,这里是方便观察执行到activity的哪个生命周期,logcat也可以简单封装一下,统一控制日志是否打印。
BaseActivity并不适合每一个页面的Activity,比如进入应用的闪屏页面,就可以考虑不继承BaseActivity,因为这个页面通常不需要写太多代码。或者还有其他特殊的业务场景下。
需要注意一个Dialog弹窗问题,在BaseActivity里面,每次show一个dialog的时候我都是创建一个新的对象,那么就要注意dialog在未关闭之前不能再去show,否则可能会导致dialog出现异常。但是不要在onDestory方法里面去隐藏dialog弹窗,因为在A页面进入B页面的时候,会先执行到B页面生命周期的onCreate、onStart、onResume三个方法,然后再执行A页面的onStop可能还有onDestory方法,所以等B页面加载完成再去销毁A页面是错误的。
有时候为了方便可能有人会把请求Android中权限检测的方法放在BaseActivity里面,这样并不是特别合适,因为所有继承自BaseActivity的页面都会去检测权限,这样会导致用户体验差,所以建议用到权限的地方再去请求,最好自己封装一个工具类,用起来方便一点。
BaseActivity的封装并不强求子类必须实现activity生命周期相关的方法,除了几个抽象方法(我认为子类需要复写的,可以根据业务自己定),必要的话可以自己复写。
4.总结
不是很复杂,写的也比较详细,也基本适用于绝大部分的场景。可能还有其他需要注意的细节回头想起来再补上。
来源:https://blog.csdn.net/fanhenghao/article/details/115511240


猜你喜欢
- 本文实例为大家分享了Unity实现俄罗斯方块的具体代码,供大家参考,具体内容如下一、使用SpriteRenderer作为小方块图片,创建7种
- 破解流程破解Android程序流程:反编译—>分析–>修改–>回编译–>签名,这些都是在命令行中操作,当然也有集成了
- 1:首先我们看一下数据库的表:这里的pid就是代表他的父节点id,如果没有父节点,那么pid就是0,上面的表就可以看作是一个tree结构,那
- 前言相对来说呢,jpg格式的相对来说容易破解一点,当然也取决于你的干扰元素,元素越复杂,破解也就难度越高,有的加的多,人都识别不出来了,何况
- 我们的spring cloud微服务一般是打成jar包发布的,Linux下启动jar包和windows下一样,都是java -jar 包名,
- mac版本:点击Finder,在应用程序中找到android studio----->Contents文件夹----->bin文
- 在官方的这篇文档中为大家介绍了如何使用Java开启Azure Windows虚拟机的诊断设置这篇文章呢,为大家介绍一下如何使用Java开启L
- 创建项目在主界面的左侧菜单选 新建在向导中选择 输入项目名称,类型选择 构建一个自由风格的软件项目点确定进入项目的配置界面源码管理 选择gi
- 简单介绍快速排序(Quicksort) 是对 冒泡排序的一种改进。基本思想快速排序算法通过多次比较和交换来实现排序,其排序流程如下:(1)首
- 算数运算操作符重载在kotlin中我定义一个类data class Point(val x: Int, val y: Int)然后实例化两个
- 方式一:基于现有控件进行扩展,如基于button进行扩展,UI可直接用xmal进行编辑设计,逻辑用xaml.cs进行编辑方法二:直接创建wp
- 摘要:这个问题算是老生常谈了,我也是一段时间没弄过了,所以感觉有些忘了,就记录一下。一、后端通过shiro在session中存储数据://
- 前言相信大家在使用spring的项目中,前台传递参数到后台是经常遇到的事, 我们必须熟练掌握一些常用的参数传递方式和注解的使用,本文将给大家
- 实例如下:Enumeration rnames=request.getParameterNames();for (Enumeration e
- 用Java代码模拟卖100张火车票问题:四个售票窗口同时售票且不能卖出同一张火车票。代码如下。package lesson;public c
- 面试官:sychronized关键字有哪些特性?应聘者:可以用来修饰方法;可以用来修饰代码块;可以用来修饰静态方法;可以保证线程安全;支持锁
- Unity中的PostProcessScene:深入解析与实用案例在Unity游戏开发中,我们经常需要对场景进行后处理,以实现更丰富的视觉效
- 第一:写Cookies Response.Cookies["UserName"].Value="Guest&q
- 场景:同一个用户在2秒内对同一URL的提交视为重复提交。思考逻辑:1.从数据库方面考虑,数据设计的时候,某些数据有没有唯一性,如果有唯一性,
- 你好,我是小黄,一名独角兽企业的Java开发工程师。感谢茫茫人海中我们能够相遇,俗话说:当你的才华和能力,不足以支撑你的梦想的时候,请静下心