BaseActivity:统一编写共有逻辑

来源:互联网 发布:淘宝客服常用语大全 编辑:程序博客网 时间:2024/04/29 12:49

转载请注明出处: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都写一遍

下面就对BaseActivityNetworkStateView以及一些其他共有的逻辑内容进行介绍

  • 定义加载布局,进行共同界面(NetworkStateView)的加载

其实在BaseActivity中,我们可以先给BaseActivity先定义一个布局文件如activity_base,在activity_base布局文件中先定义好共同的布局控件如NetworkStateViewToolbar等,并且在最后定义一个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")@Overridepublic 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进行添加移除了

@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(getLayoutId());    ...    ActivityUtils.addActivity(this);}@Overrideprotected 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中,例如显示DialogToastSnackbar

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

@Overrideprotected void onResume() {    MobclickAgent.onResume(this);}@Overrideprotected void onPause() {    MobclickAgent.onPause(this);}
  • ButterKnife,EventBus等

使用过ButterKnife和EventBus的同学都知道,ButterKnife需要进行View的绑定和解绑,而EventBus需要对Activity对象进行注册和反注册,这样我们也不会在每个Activity都去重复进行这一操作,而是在BaseActivity进行bindunbind的操作,用到EventBus时,也可以在BaseActivity进行注册和反注册

private Unbinder unbinder;@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {    ...    unbinder = ButterKnife.bind(this);    EventBus.getDefault().register(this);    ActivityUtils.addActivity(this);    initDialog();    ...}public void onEventMainThread(BaseEvent event) {    ...do...}@Overrideprotected 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方法,判断授权结果

@Overridepublic 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项目,该项目将会对于在开发中经常需要使用到的例如BaseActivityBaseFragment网络请求等进行一些基本封装,方便以后使用,项目将会持续更新,欢迎大家进行star和关注

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 商品房没有门厅业主该怎么办 公帐付款备注错了怎么办 我是农村户口在外省交社保怎么办 北京租房遇到黑中介怎么办 上海租房子不让带孩子怎么办 租的房子没窗户怎么办 北京安河桥安河家园租房被骗怎么办 领完失业金后怎么办 北京公租房太小怎么办 申请公租房太小怎么办 房东电费收贵了怎么办 申请公租房工资超了怎么办 重庆公租房工资超了怎么办 公租房申请父母房子贷款怎么办 公产房父母去世办公证怎么办 动迁过程中承租人去世了怎么办 公租房的房间带阳台怎么办 公租房合同到期没有社保怎么办 租房合同没有到期违约了怎么办 租房户到期不搬怎么办 公租房摇号摇到了又怎么办 公租房被清退会怎么办 公租房摇不到号怎么办 公租房到期不搬怎么办 租房到期租客不搬怎么办 房产证面积与实际不符怎么办 社保晚交了1天怎么办 个人社保忘交了怎么办 个人社保晚交了怎么办 医保晚交了几天怎么办 辞职后转为灵活就业养老怎么办 公司名称变更提取不了公积金怎么办 五险合一软件已经减员怎么办 法人社保不在投标单位怎么办 换工作单位后社保怎么办 在北京孩子没有一老一小怎么办 深户小孩怎么办社保卡 社保卡没办下来去医院住院怎么办 老年社保卡丢了怎么办 外墙掉瓷砖伤车伤人怎么办 医保卡姓名弄错了怎么办