内容简介:终于到了BaseActivity的封装了,在本章中将对通用性的一些方法和操作进行抽取,放到Base中。先起个名字,我们的Base就叫CandyBaseActivity吧,Candy是糖果的意思,我希望这一套东西能让人像吃糖果一样的甜!在本篇中关于Base,我们需要进行两种封装:
- overridePendingTransition(Activity的切换动画)
- 创建 工具 类:ActivityAnimUtils
- CandyBaseActivity创建两个方法:
- CandyLoadingBaseActivity
引言
终于到了BaseActivity的封装了,在本章中将对通用性的一些方法和操作进行抽取,放到Base中。
正文
先起个名字,我们的Base就叫CandyBaseActivity吧,Candy是糖果的意思,我希望这一套东西能让人像吃糖果一样的甜!
分析
在本篇中关于Base,我们需要进行两种封装:
- CandyBaseActivity,最基本,最底层的Base,附带通用操作的封装。
- CandyLoadingBaseActivity继承至CandyBaseActivity,不是所有的页面都是需要弹窗的,像弹窗需要重写很多的方法,就不适合放到最底层。
- MVPBaseActivity,进行MVP分层的Base,里面包含生命周期的订阅和取消订阅。
CandyBaseActivity
首先确定我们现阶段能封装什么:
- mActivity
- 将T.showToast封装到底层
- startActivity
- overridePendingTransition(Activity的切换动画)
- initToolbar
mActivity
每次要引用上下文都用类名的方式来指定,这就比较繁琐了。
protected Activity mActivity; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); mActivity = this; }
showToast
直接通过工具类T来调用showToast方法在原来的基础上市比较方便,但是一直需要传递一个 context
就比较让人烦躁了,所以将showToast放到Base中。代码如下:
/** * 显示文本信息 * * @param text 文本信息 */ public void showToast(String text) { T.showToast(mActivity, text); } /** * 显示文本信息 * * @param resId 文本资源id信息 */ public void showToast(int resId) { T.showToast(mActivity, resId); }
showToast方法定义为public,是为了能在其他地方,如:Presenter中进行 强转
后直接调用。
overridePendingTransition(Activity的切换动画)
关于Activity的切换动画有各种各样的,根据不同的喜好有不同的做法,我这里使用的是: 右滑进入、左滑退出
,其他动画自行探索。
动画xml
setup_next_in.xml
<?xml version="1.0" encoding="utf-8"?> <translate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="300" android:fromXDelta="100%p" android:fromYDelta="0" android:toXDelta="0" android:toYDelta="0" > <!-- 下一页 进入 位置为100 到达0 --> </translate>
setup_next_out.xml
<?xml version="1.0" encoding="utf-8"?> <translate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="300" android:fromXDelta="0" android:fromYDelta="0" android:toXDelta="-100%p" android:toYDelta="0" />
setup_pre_in.xml
<?xml version="1.0" encoding="utf-8"?> <translate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="300" android:fromXDelta="-100%p" android:fromYDelta="0" android:toYDelta="0" android:toXDelta="0"/>
setup_pre_out.xml
<?xml version="1.0" encoding="utf-8"?> <translate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="300" android:fromXDelta="0" android:fromYDelta="0" android:toXDelta="100%p" android:toYDelta="0" />
创建工具类:ActivityAnimUtils
/** * Activity的跳转动画 * * @author aohanyao create in 2018年10月04日02:36:34 */ public class ActivityAnimUtils { /** * 跳转到 * * @param activity */ public static void to(Activity activity) { activity.overridePendingTransition(R.anim.setup_next_in, R.anim.setup_next_out); } /** * 退出动画 */ public static void out(Activity activity) { activity.overridePendingTransition(R.anim.setup_pre_in, R.anim.setup_pre_out); } }
CandyBaseActivity创建两个方法:
/** * 右边划出 */ protected void slideLeftOut() { ActivityAnimUtils.out(mActivity); } /** * 进入 */ protected void slideRightIn() { ActivityAnimUtils.to(mActivity); }
在startActivity之后调用 slideRightIn()
, finish()
的时候调用 slideLeftOut()
startActivity
原本常用的方法是: startActivity(new Intent(mActivity, Target.class));
,这其中 new Intent()这一部分都是冗余的,我们可以封装一下,其中关于值的传递采用的是一个 Pair<String, Object>
的可变参数,然后根据不同的类型,将数据填充到intent中。具体代码如下:
/** * 打开 Activity * * @param activity */ protected void launchActivity(Class<? extends Activity> activity) { startActivity(new Intent(mActivity, activity)); // 加上动画 slideRightIn(); } /** * 打开 Activity * * @param activity */ protected void launchActivityForResult(Class<? extends Activity> activity, int requestCode) { startActivityForResult(new Intent(mActivity, activity), requestCode); // 加上动画 slideRightIn(); } /** * 打开新的 Activity * * @param activity 目标Activity * @param pairs 键值对 */ protected void launchActivity(Class<? extends Activity> activity, Pair<String, Object>... pairs) { Intent intent = new Intent(mActivity, activity); // 填充数据 IntentUtils.fillIntent(intent, pairs); startActivity(intent); // 加上动画 slideRightIn(); } /** * 打开新的 Activity * * @param activity 目标Activity * @param pairs 键值对 */ protected void launchActivityForResult(Class<? extends Activity> activity, int requestCode, Pair<String, Object>... pairs) { Intent intent = new Intent(mActivity, activity); // 填充数据 IntentUtils.fillIntent(intent, pairs); startActivityForResult(intent, requestCode); // 加上动画 slideRightIn(); }
关于 fillIntent
,这个方法主要是判断参数中值的类类型,然后进行intent的填充:
/** * Intent工具类 */ public class IntentUtils { /** * 填充intent数据,暂时只写了常用的一些数据格式,不常用的没写 * * @param intent * @param pairs */ public static void fillIntent(Intent intent, Pair<String, Object>[] pairs) { if (pairs != null) { for (Pair<String, Object> pair : pairs) { Object value = pair.second; //判断不同的类型,进行强转和存放 if (value instanceof Boolean) { intent.putExtra(pair.first, (Boolean) value); } if (value instanceof Byte) { intent.putExtra(pair.first, (Byte) value); } if (value instanceof Short) { intent.putExtra(pair.first, (Short) value); } if (value instanceof Long) { intent.putExtra(pair.first, (Long) value); } if (value instanceof Float) { intent.putExtra(pair.first, (Float) value); } if (value instanceof Double) { intent.putExtra(pair.first, (Double) value); } if (value instanceof Integer) { intent.putExtra(pair.first, (Integer) value); } if (value instanceof String) { intent.putExtra(pair.first, (String) value); } if (value instanceof Parcelable) { intent.putExtra(pair.first, (Parcelable) value); } if (value instanceof Serializable) { intent.putExtra(pair.first, (Serializable) value); } } } } }
综上,还把前面的动画用上了。
如何调用:
//普通 launchActivity(DialogExampleActivity.class); //普通携带参数 launchActivity(ToastExampleActivityActivity.class, new Pair<String, Object>("key1", "value1"), new Pair<String, Object>("key1", "value1")); //返回值 launchActivityForResult(LoginActivity.class,200); // 返回值携带参数 launchActivityForResult(LoginActivity.class, 200, new Pair<String, Object>("key1", "value1"), new Pair<String, Object>("key1", "value1"));
initToolbar
关于Toolbar这里使用的是 android.support.v7.widget.Toolbar
,简单又方便,先看看我们在创建的时候系统生成的Toolbar:
<android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/AppTheme.AppBarOverlay"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:popupTheme="@style/AppTheme.PopupOverlay" /> </android.support.design.widget.AppBarLayout>
为了以后的扩展性和能够统一的在Base中操作,要做一下操作:
- 为AppBarLayout和Toolbar定义id资源,通过统一id来管理
- 为AppBarLayout和Toolbar定义style,将id加入到style中,在xml中直接引用style
定义id
<resources> <item name="base_toolbar" type="id" /> <item name="base_appbar" type="id" /> </resources>
定义style
<resources> <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" /> <style name="BaseAppBarLayoutStyle"> <item name="android:layout_width">match_parent</item> <item name="android:layout_height">44dp</item> <item name="android:theme">@style/AppTheme.AppBarOverlay</item> <!--这里设置 标题栏的颜色--> <item name="android:id">@id/base_appbar</item> </style> <!--标题栏的样式--> <style name="BaseToolbarStyle" parent="Widget.AppCompat.Toolbar"> <!--高度--> <item name="android:layout_height">?attr/actionBarSize</item> <!--id--> <item name="android:id">@id/base_toolbar</item> <!--宽度--> <item name="android:layout_width">match_parent</item> <!--背景颜色--> <item name="android:background">?attr/colorPrimary</item> </style> </resources>
使用样式
将原本activity_layout的内容更改一下:
<android.support.design.widget.AppBarLayout style="@style/BaseAppBarLayoutStyle"> <android.support.v7.widget.Toolbar style="@style/BaseToolbarStyle" app:popupTheme="@style/AppTheme.PopupOverlay" /> </android.support.design.widget.AppBarLayout>
initToolbar
在初始化Toolbar的时候需要有一些属性是需要可配置的,需要为这些配置项创建不同的方法,让子类来进行复写:
Toolbar颜色
Toolbar返回icon
Toolbar返回事件
前面定义了一个id资源 base_toolbar
,我们可以直接在Base中通过 findViewById
来获取Toolbar。
initToolbar具体代码如下:
/** * 是否初始化了toolbar */ private boolean isInitToolbar = false; @Override protected void onStart() { super.onStart(); if (!isInitToolbar) { initToolbar(); } } /** * 初始化toolbar */ private void initToolbar() { Toolbar mToolbar = findViewById(R.id.base_toolbar); if (null != mToolbar) { //设置返回按钮 setSupportActionBar(mToolbar); mToolbar.setBackgroundColor(getToolbarBackground()); mToolbar.setNavigationIcon(getNavigationIcon()); mToolbar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { onNavigationOnClickListener(); } }); isInitToolbar = true; } } /** * 获取toolbar的背景 * @return */ private int getToolbarBackground() { return getResources().getColor(R.color.colorPrimary); } /** * 返回按钮点击 */ protected void onNavigationOnClickListener() { finish(); slideLeftOut(); } /** * 返回按钮 * * @return */ protected int getNavigationIcon() { return R.drawable.ic_arrow_back_white_24dp; }
子类不用管Toolbar的初始化 ,需要在xml中使用定义的style就可以完成初始化。
CandyLoadingBaseActivity
在本次CandyLoadingBaseActivity中需要封装的是 DialogHelper,让子类直接通过 show...()
的方式来显示弹窗,而不用加上 mDialogHelper
的方式。而封装的方式差不多是将DialogHelper的方法重写一遍,只不过方法体内的调用对象换成DialogHelper,具体直接看下面代码:
public class CandyLoadingBaseActivity extends CandyBaseActivity implements OnDialogCancelListener { protected DialogHelper mDialogHelper; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (mDialogHelper == null) { mDialogHelper = new DialogHelper(mActivity, this); } } /** * 显示 loading 弹窗,默认不能点击空白处进行取消 * * @param loadingTip 信息提示 */ public void showLoadingDialog(String loadingTip) { showLoadingDialog(loadingTip, true); } /** * 显示 loading 弹窗 * * @param loadingTip 信息提示 * @param cancelable 能不能点击空白的地方 */ public void showLoadingDialog(String loadingTip, Boolean cancelable) { mDialogHelper.showLoadingDialog(loadingTip, cancelable); } /** * 信息提示弹窗 * * @param message 提示信息的内容 */ public void showMessageDialog(String message) { mDialogHelper.showMessageDialog(message); } /** * 信息提示弹窗 * * @param message 提示信息的内容 * @param confirmListener 确认按钮点击的回调 */ public void showMessageDialog(String message, OnDialogConfirmListener confirmListener) { mDialogHelper.showMessageDialog(message, confirmListener); } /** * 成功提示弹窗 * * @param message 提示信息的内容 */ public void showSuccessDialog(String message) { mDialogHelper.showSuccessDialog(message); } /** * 成功提示弹窗 * * @param message 提示信息的内容 * @param confirmListener 确认按钮点击的回调 */ public void showSuccessDialog(String message, OnDialogConfirmListener confirmListener) { mDialogHelper.showSuccessDialog(message, confirmListener); } /** * 警告提示弹窗 * * @param message 提示信息的内容 */ public void showWarningDialog(String message) { mDialogHelper.showWarningDialog(message); } /** * 警告提示弹窗 * * @param message 提示信息的内容 * @param confirmListener 确认按钮点击的回调 */ public void showWarningDialog(String message, OnDialogConfirmListener confirmListener) { mDialogHelper.showWarningDialog(message, confirmListener); } /** * 错误提示弹窗 * * @param message 提示信息的内容 */ public void showErrorDialog(String message) { mDialogHelper.showErrorDialog(message); } /** * 错误提示弹窗 * * @param message 提示信息的内容 * @param confirmListener 确认按钮点击的回调 */ public void showErrorDialog(String message, OnDialogConfirmListener confirmListener) { mDialogHelper.showErrorDialog(message, confirmListener); } /** * 显示确认弹窗 * * @param message 提示信息 * @param confirmText 确认按钮文字 * @param cancelText 取消按钮文字 * @param confirmListener 确认按钮点击回调 * @param cancelListener 取消按钮点击回调 */ public void showConfirmDialog(String message, String confirmText, String cancelText, final OnDialogConfirmListener confirmListener, final OnDialogCancelListener cancelListener) { mDialogHelper.showConfirmDialog(message, confirmText, cancelText, confirmListener, cancelListener); } /** * 显示确认弹窗 * * @param message 提示信息 * @param confirmText 确认按钮文字 * @param cancelText 取消按钮文字 * @param confirmListener 确认按钮点击回调 */ public void showConfirmDialog(String message, String confirmText, String cancelText, OnDialogConfirmListener confirmListener) { showConfirmDialog(message, confirmText, cancelText, confirmListener, null); } /** * 显示确认弹窗 * * @param message 提示信息 * @param confirmListener 确认按钮点击回调 */ public void showConfirmDialog(String message, OnDialogConfirmListener confirmListener) { showConfirmDialog(message, "确定", "取消", confirmListener, null); } /** * 关闭弹窗 */ public void dismissDialog() { mDialogHelper.dismissDialog(); } @Override public void onDialogCancelListener(AlertDialog dialog) { //空实现,让子类做自己想做的事情 } }
示例
将DialogExampleActivity继承至CandyLoadingBaseActivity,然后注释掉DialogHelper相关的代码。
MVPBaseActivity
关于MVPBaseActivity,这里要做的封装有:
- 使用泛型 P 来表示Presenter。
- 将Dialog与Presenter进行绑定:取消Dialog的同时取消订阅、请求完成关闭Dialog。
- 将Presenter与Activity进行绑定:onDestroy的时候取消订阅,防止内存泄漏。
泛型P
abstract public class MVPBaseActivity<P extends BasePresenter> extends CandyLoadingBaseActivity { private P mPresenter; /** * 底层获取P * * @return P */ protected synchronized P getP() { if (mPresenter == null) { mPresenter = createPresenter(); } return mPresenter; } /** * 创建Presenter * * @return 返回Presenter的实例 */ protected abstract P createPresenter(); }
将需要MVP的Activity继承至MVPBaseActivity,并且传入一个BasePresenter子类的P,然后实现 createPresenter()
返回具体的实现类,最后直接通过 getP()
来调用Presenter,为了演示效果,我已经将 LoginActivity
做了更改,详情请查看源码,核心代码如下:
public class LoginActivity extends MVPBaseActivity<LoginPresenter> { ... private void initEvent() { ... getP().login(account, password); ... } @Override protected LoginPresenter createPresenter() { return new LoginPresenter(this); } }
绑定Dialog
前面在封装MVP的时候我们定义了一个 BaseView
,里面包含了 onComplete
方法,所以我们可以直接让MVPBaseActivity实现BaseView,核心代码如下:
@Override public void onComplete() { // 请求完成、关闭dialog dismissDialog(); } @Override public void onDialogCancelListener(AlertDialog dialog) { super.onDialogCancelListener(dialog); // dialog取消,取消订阅 getP().unDisposable(); }
绑定Activity
其实就是在onDestroy的时候取消订阅一下,代码如下:
@Override protected void onDestroy() { super.onDestroy(); // 销毁 取消订阅 getP().unDisposable(); }
整体代码如下:
/** * Mvp BaseActivity * * @param <P> */ abstract public class MVPBaseActivity<P extends BasePresenter> extends CandyLoadingBaseActivity implements BaseView { private P mPresenter; /** * 底层获取P * * @return P */ protected synchronized P getP() { if (mPresenter == null) { mPresenter = createPresenter(); } return mPresenter; } /** * 创建Presenter * * @return 返回Presenter的实例 */ protected abstract P createPresenter(); @Override public void onComplete() { // 请求完成、关闭dialog dismissDialog(); } @Override public void onDialogCancelListener(AlertDialog dialog) { super.onDialogCancelListener(dialog); // dialog取消,取消订阅 getP().unDisposable(); } @Override protected void onDestroy() { super.onDestroy(); // 销毁 取消订阅 getP().unDisposable(); } @Override public void onFailure(String message) { // showWarningDialog(message); // 暂不实现,后面有一篇文章:统一错误管理 } }
结束
总结
终于完成了三个BaseActivity的封装了,可能有人有疑惑:为什么没有BaseFragment呢?其实BaseFragment和BaseActivity相差不大,只是一些方法调用的时机不一样,还有就是没用Toolbar的初始化,这里由于篇幅的问题就没用一一列出,不过我在源码中已经完成了BaseFragment的封装,可以直接查看源码。
最后
关于Base的封装还没有完呢?预计还有还几章的篇幅,敬请期待!
软广
一个痴心妄想想成为一个全屏(栈)工程师的程序猿。
来来,关注一下吧!
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 封装JDBC—非框架开发必备的封装类
- SpringBlade 2.3.2 发布,增加 OSS 封装及单元测试封装
- SpringBlade 2.3.2 发布,增加 OSS 封装及单元测试封装
- docker 封装 alinode
- 封装Apk签名工具
- axios封装笔记
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
精通Spring 4.x
陈雄华、林开雄、文建国 / 电子工业出版社 / 2017-1-1 / CNY 128.00
Spring 4.0是Spring在积蓄4年后,隆重推出的一个重大升级版本,进一步加强了Spring作为Java领域第一开源平台的翘楚地位。Spring 4.0引入了众多Java开发者翘首以盼的基于Groovy Bean的配置、HTML 5/WebSocket支持等新功能,全面支持Java 8.0,最低要求是Java 6.0。这些新功能实用性强、易用性高,可大幅降低Java应用,特别是Java W......一起来看看 《精通Spring 4.x》 这本书的介绍吧!