BaseActivity:统一编写共有逻辑
2017-04-23 10:43
127 查看
转载请注明出处:http://blog.csdn.net/alarmz/article/details/70490679
在上一篇文章NetworkStateView的结尾说到可以在BaseActivity中对NetworkStateView进行统一设置,从而进行界面多状态的加载,那么今天就说一说BaseActivity,在BaseActivity怎么进行NetworkStateView的设置以及BaseActivity的一些其他作用,还没有看过NetworkStaetView的可以先看一下这一篇文章
在项目中,我们在写Activity时一般都不会直接继承AppCompatActivity,而是先写一个基类BaseActivity,让其他的Activity继承BaseActivity,这样就有一个好处,就是我们可以把Activity的共有逻辑写在BaseActivity中,例如NetworkStateView的逻辑,从而不需要在每个Activity都写一遍
下面就对BaseActivity对NetworkStateView以及一些其他共有的逻辑内容进行介绍
定义加载布局,进行共同界面(NetworkStateView)的加载
其实在BaseActivity中,我们可以先给BaseActivity先定义一个布局文件如
定义好布局文件之后,我们需要在BaseActivity中重写
看到这里可能有人会有疑惑,先将
嗯,对
嗯,这样我们就可以统一设置
定义Activity栈,进行Activity的保存
在开发的时候,我们可能会遇到这样的情况,在启动了多个Activity之后需要一次性销毁并退出应用, 又或者是销毁顶部一个或多个Activity,显示指定的Activity,在这样的情形下,我们可以定义一个 Activity栈,在Activity执行
在这样的每次添加和移除操作的共有逻辑,我们就可以在BaseActivity进行书写,只要Activity继承BaseActivity便可以在Activity进行添加移除了
ActivityUtils就是我们定义的Activity栈工具类
定义共有的UI操作
为了方便子类Activity可以执行共有的UI操作,我们可以将共有的UI操作写在BaseActivity中,例如显示Dialog,Toast和Snackbar等
在BaseActivity写了显示Toast,Dialog等的UI操作后,在子类Activity就可以共同调用了,可以减少共有操作的重写,当然了,不写在BaseActivity也是可以,我们可以封装成一个工具类,在需要用的时候再调用工具类的相关方法也是可以的,这就看个人的喜好了,哈哈
友盟消息推送,统计
在项目发布之后,我们可能需要向用户推送消息,需要知道用户在界面的点击次数,异常信息等,以方便我们对产品的改进
由于在每个Activity或Fragment界面我们都要进行统计,所以我们需要让每个Activity或Fragment都要调用到友盟的API,但是如果一个一个Activity或Fragment的去进行调用,是非常繁琐的,特别是如果项目比较大,Activity和Fragment的数量较多,更是不可想象
所以我们应该在BaseActivity的生命周期方法去调用友盟API
ButterKnife,EventBus等
使用过ButterKnife和EventBus的同学都知道,ButterKnife需要进行View的绑定和解绑,而EventBus需要对Activity对象进行注册和反注册,这样我们也不会在每个Activity都去重复进行这一操作,而是在BaseActivity进行
Android6.0运行时权限处理
在Android6.0版本以上,对于一些危险权限,需要用户授权之后才能使用,这也需要调用对危险权限进行申请
在申请危险权限时,需要在Activity中进行代码编写申请,虽然对于权限处理的代码并不是很复杂,但是如果在多个Activity中都需要申请权限,就需要编写很多重复的代码,所以最好就能做一个封装,最简单的封装方法就是将其统一进行设置在BaseActivity中,这样子类Activity能统一调用
在进行封装时,先写一个权限回调接口
在接口中定义两个方法,分别是统一授权和取消授权,定义接口之后,在BaseActvity中定义一个申请权限的方法,该方法的代码如下
可以看到,方法需要有两个参数,分别是需要申请的权限,是一个String数组,另一个则是权限的回调接口,用于在授权或取消授权后能做出相应的处理,接着在方法里面对权限数组进行一个循环判断其是否已经授权,对于没有授权的会添加到List中,可以用于再次申请,在申请之后,需要重写Activity的
这样统一封装在BaseActivity之后,在子类Activity只要调用
在上面的分析知道,基类BaseActivity可以用于处理子类共有的逻辑,这样可以比main重复进行处理同一逻辑,在本篇文章中,讲到的内容还是有限的,对于其他的共有逻辑,可以自行补充
本篇文章的代码已上传到github,在github上对应着BaseProject项目,该项目将会对于在开发中经常需要使用到的例如BaseActivity,BaseFragment,网络请求等进行一些基本封装,方便以后使用,项目将会持续更新,欢迎大家进行star和关注
在上一篇文章NetworkStateView的结尾说到可以在BaseActivity中对NetworkStateView进行统一设置,从而进行界面多状态的加载,那么今天就说一说BaseActivity,在BaseActivity怎么进行NetworkStateView的设置以及BaseActivity的一些其他作用,还没有看过NetworkStaetView的可以先看一下这一篇文章
在项目中,我们在写Activity时一般都不会直接继承AppCompatActivity,而是先写一个基类BaseActivity,让其他的Activity继承BaseActivity,这样就有一个好处,就是我们可以把Activity的共有逻辑写在BaseActivity中,例如NetworkStateView的逻辑,从而不需要在每个Activity都写一遍
下面就对BaseActivity对NetworkStateView以及一些其他共有的逻辑内容进行介绍
定义加载布局,进行共同界面(NetworkStateView)的加载
其实在BaseActivity中,我们可以先给BaseActivity先定义一个布局文件如
activity_base,在
activity_base布局文件中先定义好共同的布局控件如
NetworkStateView,
Toolbar等,并且在最后定义一个
FrameLayout,这个
FrameLayout是关键人物,后面再说他的作用,哈哈
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <include layout="@layout/view_network_state" /> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent"> </FrameLayout> </LinearLayout>
定义好布局文件之后,我们需要在BaseActivity中重写
setContentView方法,让其加载
activity_base的布局文件并进行设置填充,接着再加载子类Activity的布局文件
@SuppressLint("InflateParams") @Override public void setContentView(@LayoutRes int layoutResID) { View view = getLayoutInflater().inflate(R.layout.activity_base, null); //设置填充activity_base布局 super.setContentView(view); if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) { view.setFitsSystemWindows(true); } //加载子类Activity的布局 initDefaultView(layoutResID); }
看到这里可能有人会有疑惑,先将
activity_base的布局设置填充了之后,还怎么进行设置子类Activity的布局文件?哈哈,这个时候上面的
FrameLayout就要发挥作用了,其实这里设置子类Activity的布局并不是直接填充给BaseActivity,而是让其作为一个子View添加到
activity_base中的
FrameLayout中,这样不就让
BaseActivity和子类Activity的布局相结合了,看看
initDefaultView(layoutResID)
private void initDefaultView(int layoutResId) { networkStateView = (NetworkStateView) findViewById(R.id.nsv_state_view); FrameLayout container = (FrameLayout) findViewById(R.id.fl_activity_child_container); View childView = LayoutInflater.from(this).inflate(layoutResId, null); container.addView(childView, 0); }
嗯,对
NetworkStateView进行
findViewById查找,接着定义
NetworkStateView的相关方法之后,我们就能在子类Activity中进行相关调用了
/** * 显示加载中的布局 */ public void showLoadingView() { networkStateView.showLoading(); } /** * 显示加载完成后的布局(即子类Activity的布局) */ public void showContentView() { networkStateView.showSuccess(); } /** * 显示没有网络的布局 */ public void showNoNetworkView() { networkStateView.showNoNetwork(); networkStateView.setOnRefreshListener(this); } /** * 显示没有数据的布局 */ public void showEmptyView() { networkStateView.showEmpty(); networkStateView.setOnRefreshListener(this); } /** * 显示数据错误,网络错误等布局 */ public void showErrorView() { networkStateView.showError(); networkStateView.setOnRefreshListener(this); }
嗯,这样我们就可以统一设置
NetworkStateView了,不过大家可能注意到,这样其实会给每个
Activity增加多了一层
FrameLayout,如果子类Activity本身就是
LinearLayout还会增加多一层,有人可能会觉得影响性能,不过个人认为这样会极大增加便利性,而且对于一层
FrameLayout的影响并不是很大,所以觉得这种方法还是可取的,不过读者可自行考虑
定义Activity栈,进行Activity的保存
在开发的时候,我们可能会遇到这样的情况,在启动了多个Activity之后需要一次性销毁并退出应用, 又或者是销毁顶部一个或多个Activity,显示指定的Activity,在这样的情形下,我们可以定义一个 Activity栈,在Activity执行
onCreate时在栈里添加此Activity,在Activity指定
onDestroy时在Activity栈中移除
在这样的每次添加和移除操作的共有逻辑,我们就可以在BaseActivity进行书写,只要Activity继承BaseActivity便可以在Activity进行添加移除了
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(getLayoutId()); ... ActivityUtils.addActivity(this); } @Override protected void onDestroy() { super.onDestroy(); ... ActivityUtils.removeActivity(this); }
ActivityUtils就是我们定义的Activity栈工具类
public class ActivityUtils { private static Stack<Activity> mActivityStack; /** * 添加一个Activity到堆栈中 * @param activity */ public static void addActivity(Activity activity) { if (null == mActivityStack) { mActivityStack = new Stack<>(); } mActivityStack.add(activity); } /** * 从堆栈中移除指定的Activity * @param activity */ public static void removeActivity(Activity activity) { if (activity != null) { mActivityStack.remove(activity); } } /** * 获取顶部的Activity * @return 顶部的Activity */ public static Activity getTopActivity() { if (mActivityStack.isEmpty()) { return null; } else { return mActivityStack.get(mActivityStack.size() - 1); } } /** * 结束所有的Activity,退出应用 */ public static void removeAllActivity() { if (mActivityStack != null && mActivityStack.size() > 0) { for (Activity activity : mActivityStack) { activity.finish(); } } } }
定义共有的UI操作
为了方便子类Activity可以执行共有的UI操作,我们可以将共有的UI操作写在BaseActivity中,例如显示Dialog,Toast和Snackbar等
private void initDialog() { mDialog = new Dialog(this, R.style.dialog_transparent_style); mDialogContentView = LayoutInflater.from(this).inflate(R.layout.dialog_loading, null); tv_loadText = (TextView) mDialogContentView.findViewById(R.id.tv_loading_text); iv_loadImage = (ImageView) mDialogContentView.findViewById(R.id.iv_load_image); pb_loadProgress = (ProgressBar) mDialogContentView.findViewById(R.id.pb_load_progress); mDialog.setCanceledOnTouchOutside(false); mDialog.setContentView(mDialogContentView); Window window = mDialog.getWindow(); if (null != window) { window.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL); } } public void showProgressDialog() { if (mDialog != null && !mDialog.isShowing()) { pb_loadProgress.setVisibility(View.VISIBLE); iv_loadImage.setVisibility(View.GONE); tv_loadText.setVisibility(View.GONE); mDialog.show(); } } public void showToast(String text) { if (!TextUtils.isEmpty()) { Toast.makeText(App.getApplication(), text, Toast.LENGTH_LONG).show(); } }
在BaseActivity写了显示Toast,Dialog等的UI操作后,在子类Activity就可以共同调用了,可以减少共有操作的重写,当然了,不写在BaseActivity也是可以,我们可以封装成一个工具类,在需要用的时候再调用工具类的相关方法也是可以的,这就看个人的喜好了,哈哈
友盟消息推送,统计
在项目发布之后,我们可能需要向用户推送消息,需要知道用户在界面的点击次数,异常信息等,以方便我们对产品的改进
由于在每个Activity或Fragment界面我们都要进行统计,所以我们需要让每个Activity或Fragment都要调用到友盟的API,但是如果一个一个Activity或Fragment的去进行调用,是非常繁琐的,特别是如果项目比较大,Activity和Fragment的数量较多,更是不可想象
所以我们应该在BaseActivity的生命周期方法去调用友盟API
@Override protected void onResume() { MobclickAgent.onResume(this); } @Override protected void onPause() { MobclickAgent.onPause(this); }
ButterKnife,EventBus等
使用过ButterKnife和EventBus的同学都知道,ButterKnife需要进行View的绑定和解绑,而EventBus需要对Activity对象进行注册和反注册,这样我们也不会在每个Activity都去重复进行这一操作,而是在BaseActivity进行
bind和
unbind的操作,用到EventBus时,也可以在BaseActivity进行注册和反注册
private Unbinder unbinder; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { ... unbinder = ButterKnife.bind(this); EventBus.getDefault().register(this); ActivityUtils.addActivity(this); initDialog(); ... } public void onEventMainThread(BaseEvent event) { ...do... } @Override protected void onDestroy() { super.onDestroy(); unbinder.unbind(); EventBus.getDefault().unregister(this); ActivityUtils.removeActivity(this); }
Android6.0运行时权限处理
在Android6.0版本以上,对于一些危险权限,需要用户授权之后才能使用,这也需要调用对危险权限进行申请
在申请危险权限时,需要在Activity中进行代码编写申请,虽然对于权限处理的代码并不是很复杂,但是如果在多个Activity中都需要申请权限,就需要编写很多重复的代码,所以最好就能做一个封装,最简单的封装方法就是将其统一进行设置在BaseActivity中,这样子类Activity能统一调用
在进行封装时,先写一个权限回调接口
public interface PermissionListener { void onGranted(); void onDenied(List<String> deniedPermissions); }
在接口中定义两个方法,分别是统一授权和取消授权,定义接口之后,在BaseActvity中定义一个申请权限的方法,该方法的代码如下
public static void requestPermissions(String[] permissions, PermissionListener listener) { Activity activity = ActivityUtils.getTopActivity(); if (null == activity) { return; } mPermissionListener = listener; List<String> permissionList = new ArrayList<>(); for (String permission : permissionList) { //权限没有授权 if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) { permissionList.add(permission); } } if (!permissionList.isEmpty()) { ActivityCompat.requestPermissions(activity, permissionList.toArray(new String[permissionList.size()]), CODE_REQUEST_PERMISSION); } else { mPermissionListener.onGranted(); } }
可以看到,方法需要有两个参数,分别是需要申请的权限,是一个String数组,另一个则是权限的回调接口,用于在授权或取消授权后能做出相应的处理,接着在方法里面对权限数组进行一个循环判断其是否已经授权,对于没有授权的会添加到List中,可以用于再次申请,在申请之后,需要重写Activity的
onRequestPermissionsResult方法,判断授权结果
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode) { case CODE_REQUEST_PERMISSION: if (grantResults.length > 0) { List<String> deniedPermissions = new ArrayList<>(); for (int i = 0; i < grantResults.length; i++) { int result = grantResults[i]; if (result != PackageManager.PERMISSION_GRANTED) { String permission = permissions[i]; deniedPermissions.add(permission); } } if (deniedPermissions.isEmpty()) { mPermissionListener.onGranted(); } else { mPermissionListener.onDenied(deniedPermissions); } } break; default: break; } }
这样统一封装在BaseActivity之后,在子类Activity只要调用
requestPermissions方法并传入权限数组和回调接口的参数就能对结果进行对应的处理了
在上面的分析知道,基类BaseActivity可以用于处理子类共有的逻辑,这样可以比main重复进行处理同一逻辑,在本篇文章中,讲到的内容还是有限的,对于其他的共有逻辑,可以自行补充
本篇文章的代码已上传到github,在github上对应着BaseProject项目,该项目将会对于在开发中经常需要使用到的例如BaseActivity,BaseFragment,网络请求等进行一些基本封装,方便以后使用,项目将会持续更新,欢迎大家进行star和关注
相关文章推荐
- BaseActivity:统一编写共有逻辑
- 编写用逻辑扇区号读写软盘的中断例程
- MFC编写程序的时候遇到的一些逻辑错误 持续......
- 编写安全代码:避免奇怪的逻辑引发的bug
- 制定统一业务逻辑基础规则
- Activity实现退出和进入动画和BaseActivity的编写
- python实例编写(6)--引入unittest测试框架,构造测试集批量测试(以微信统一管理平台为例)
- 前端_浅谈页面编写逻辑
- 由是否检验验证码想到的程序出入口统一逻辑
- 如何在UWP中统一处理不同设备间的页面回退逻辑
- 用php编写空心金字塔,主要在于学习它的逻辑与思想
- 化简复杂逻辑,编写紧凑的if条件语句
- Android实训案例(四)——关于Game,2048方块的设计,逻辑,实现,编写,加上色彩,分数等深度剖析开发过程!
- 编写一个过滤器用于统一编码格式
- 关于android程序编写初级逻辑思考问题
- 编写业务逻辑代码-清晰可维护才是最重要的
- 编写统一、符合习惯的CSS的原则
- 《编写可读性代码的艺术》读书笔记 第二部分 简化循环和逻辑
- (转).Net高级进阶,在复杂的业务逻辑下,如何以最简练的代码,最直观的编写事务代码?
- 楼梯上有n阶台阶,上楼时可以一步上1阶,也可以一步上两阶,编写算法计算共有多少种不同的上楼梯的方法。