Android 之路 (7) - 对BaseActivity的简单封装

引言

终于到了BaseActivity的封装了,在本章中将对通用性的一些方法和操作进行抽取,放到Base中。

正文

先起个名字,我们的Base就叫CandyBaseActivity吧,Candy是糖果的意思,我希望这一套东西能让人像吃糖果一样的甜!

分析

在本篇中关于Base,我们需要进行两种封装:

  1. CandyBaseActivity,最基本,最底层的Base,附带通用操作的封装。
  2. CandyLoadingBaseActivity继承至CandyBaseActivity,不是所有的页面都是需要弹窗的,像弹窗需要重写很多的方法,就不适合放到最底层。
  3. 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


<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" >

translate>

setup_next_out.xml


<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


<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


<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 的可变参数,然后根据不同的类型,将数据填充到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" />