前言
写项目的时候经常会写到跳转Activiey,写到跳转Activit就一定会写到putExtra,就像下面那样
intent.putExtra("a", item.a)
intent.putExtra("b", item.b)
intent.putExtra("c", item.c)
挺多哈,每次都要重复前面相同的内容,所以就想着能不能写个扩展来简写。
开始
我们最终实现是这样的:
Intent(context, TestActivity::class.java)
.putExtraVararg(
"a" to item.a,
"b" to item.b,
"c" to item.c
)
仿mapOf
经常用到mapOf()
或者mutableMapOf()
就会知道,里面是用了Pair
类来生成Map的,所以受此启发,打算用Pair
来作为参数实现,那么写的时候就应该是这样写,参数为可变参数类型:
// 作为Intent的扩展
fun Intent.putExtraVararg(
vararg extras: Pair<String, Any?>
): Intent {
// 先省略
}
putExtra
的第一个参数类型肯定是String
类型,第二个参数的类型包括Bundle, Boolean, BooleanArray, Byte, ByteArray, Char, CharArray, String
等等,所以就用Any
类型,因为是可空的,所以加上?
。
那么调用的时候,就是这样子的
Intent(context, TestActivity::class.java)
.putExtraVararg(
"a" to item.a,
"b" to item.b,
"c" to item.c
)
是不是就是一开始说的那样,对比平常写的是不是简单了很多。
参数类型匹配
写好了参数,那么就要进行对参数类型的匹配进行对应的putExtra
。
vararg
参数可以用forEach
来循环对每个参数类型进行匹配:
fun Intent.putExtraVararg(
vararg extras: Pair<String, Any?>
): Intent {
if (extras.isEmpty()) return this
extras.forEach { (key, value) ->
value ?: let {
it.putExtra(key, it.toString())
return@forEach
}
when (value) {
is Bundle -> this.putExtra(key, value)
is Boolean -> this.putExtra(key, value)
is BooleanArray -> this.putExtra(key, value)
is Byte -> this.putExtra(key, value)
is ByteArray -> this.putExtra(key, value)
is Char -> this.putExtra(key, value)
is CharArray -> this.putExtra(key, value)
is String -> this.putExtra(key, value)
is CharSequence -> this.putExtra(key, value)
is Double -> this.putExtra(key, value)
is DoubleArray -> this.putExtra(key, value)
is Float -> this.putExtra(key, value)
is FloatArray -> this.putExtra(key, value)
is Int -> this.putExtra(key, value)
is IntArray -> this.putExtra(key, value)
is Long -> this.putExtra(key, value)
is LongArray -> this.putExtra(key, value)
is Short -> this.putExtra(key, value)
is ShortArray -> this.putExtra(key, value)
is Parcelable -> this.putExtra(key, value)
is Serializable -> this.putExtra(key, value)
else -> {
throw IllegalArgumentException("Not support $value type ${value.javaClass}..")
}
}
}
return this
}
发现没有,还少了ArrayList<String>
、ArrayList<CharSequence>
、ArrayList<? extends Parcelable>
这三个List的参数类型匹配,因为不能直接is
来匹配对应的Array类型,在群里问过之后,才得出最终的方法,Array里面有一个匹配对应类型的扩展函数isArrayOf()
:
/**
* Checks if array can contain element of type [T].
*/
@Suppress("REIFIED_TYPE_PARAMETER_NO_INLINE")
public fun <reified T : Any> Array<*>.isArrayOf(): Boolean =
T::class.java.isAssignableFrom(this::class.java.componentType)
so,这样就简单了,我们先匹配Array
,然后在匹配对应的ArrayList<String>
、ArrayList<CharSequence>
、ArrayList<? extends Parcelable>
,最后在对应put方法那里用as
:
is Array<*> -> {
@Suppress("UNCHECKED_CAST")
when {
value.isArrayOf<String>() -> {
this.putStringArrayListExtra(key, value as ArrayList<String?>)
}
value.isArrayOf<CharSequence>() -> {
this.putCharSequenceArrayListExtra(key, value as ArrayList<CharSequence?>)
}
value.isArrayOf<Parcelable>() -> {
this.putParcelableArrayListExtra(key, value as ArrayList<out Parcelable?>)
}
}
}
这样就实现了不同Array
类型的putExtra
。
最终
最后完整的代码为
fun Intent.putExtraVararg(
vararg extras: Pair<String, Any?>
): Intent {
if (extras.isEmpty()) return this
extras.forEach {
val key = it.first
val value = it.second ?: let {
it.putExtra(key, it.toString())
}
}
extras.forEach { (key, value) ->
value ?: let {
it.putExtra(key, it.toString())
return@forEach
}
when (value) {
is Bundle -> this.putExtra(key, value)
is Boolean -> this.putExtra(key, value)
is BooleanArray -> this.putExtra(key, value)
is Byte -> this.putExtra(key, value)
is ByteArray -> this.putExtra(key, value)
is Char -> this.putExtra(key, value)
is CharArray -> this.putExtra(key, value)
is String -> this.putExtra(key, value)
is CharSequence -> this.putExtra(key, value)
is Double -> this.putExtra(key, value)
is DoubleArray -> this.putExtra(key, value)
is Float -> this.putExtra(key, value)
is FloatArray -> this.putExtra(key, value)
is Int -> this.putExtra(key, value)
is IntArray -> this.putExtra(key, value)
is Long -> this.putExtra(key, value)
is LongArray -> this.putExtra(key, value)
is Short -> this.putExtra(key, value)
is ShortArray -> this.putExtra(key, value)
is Array<*> -> {
@Suppress("UNCHECKED_CAST")
when {
value.isArrayOf<String>() -> {
this.putStringArrayListExtra(key, value as ArrayList<String?>)
}
value.isArrayOf<CharSequence>() -> {
this.putCharSequenceArrayListExtra(key, value as ArrayList<CharSequence?>)
}
value.isArrayOf<Parcelable>() -> {
this.putParcelableArrayListExtra(key, value as ArrayList<out Parcelable?>)
}
}
}
is Parcelable -> this.putExtra(key, value)
is Serializable -> this.putExtra(key, value)
else -> {
throw IllegalArgumentException("Not support $value type ${value.javaClass}..")
}
}
}
return this
}
转成Java是这样的:
public final class IntentExtKt {
@NotNull
public static final Intent putExtraVararg(@NotNull Intent $receiver, @NotNull Pair... extras) {
Intrinsics.checkParameterIsNotNull($receiver, "receiver$0");
Intrinsics.checkParameterIsNotNull(extras, "extras");
if (extras.length == 0) {
return $receiver;
} else {
Pair[] var3 = extras;
int var4 = extras.length;
int var5;
Pair element$iv;
boolean var8;
String key;
for(var5 = 0; var5 < var4; ++var5) {
element$iv = var3[var5];
var8 = false;
key = (String)element$iv.getFirst();
if (element$iv.getSecond() == null) {
int var12 = false;
$receiver.putExtra(key, $receiver.toString());
}
}
var3 = extras;
var4 = extras.length;
for(var5 = 0; var5 < var4; ++var5) {
element$iv = var3[var5];
var8 = false;
key = (String)element$iv.component1();
Object value = element$iv.component2();
if (value != null) {
if (value instanceof Bundle) {
$receiver.putExtra(key, (Bundle)value);
} else if (value instanceof Boolean) {
$receiver.putExtra(key, (Boolean)value);
} else if (value instanceof boolean[]) {
$receiver.putExtra(key, (boolean[])value);
} else if (value instanceof Byte) {
$receiver.putExtra(key, ((Number)value).byteValue());
} else if (value instanceof byte[]) {
$receiver.putExtra(key, (byte[])value);
} else if (value instanceof Character) {
$receiver.putExtra(key, (Character)value);
} else if (value instanceof char[]) {
$receiver.putExtra(key, (char[])value);
} else if (value instanceof String) {
$receiver.putExtra(key, (String)value);
} else if (value instanceof CharSequence) {
$receiver.putExtra(key, (CharSequence)value);
} else if (value instanceof Double) {
$receiver.putExtra(key, ((Number)value).doubleValue());
} else if (value instanceof double[]) {
$receiver.putExtra(key, (double[])value);
} else if (value instanceof Float) {
$receiver.putExtra(key, ((Number)value).floatValue());
} else if (value instanceof float[]) {
$receiver.putExtra(key, (float[])value);
} else if (value instanceof Integer) {
$receiver.putExtra(key, ((Number)value).intValue());
} else if (value instanceof int[]) {
$receiver.putExtra(key, (int[])value);
} else if (value instanceof Long) {
$receiver.putExtra(key, ((Number)value).longValue());
} else if (value instanceof long[]) {
$receiver.putExtra(key, (long[])value);
} else if (value instanceof Short) {
$receiver.putExtra(key, ((Number)value).shortValue());
} else if (value instanceof short[]) {
$receiver.putExtra(key, (short[])value);
} else if (value instanceof Object[]) {
if ((Object[])value instanceof String[]) {
$receiver.putStringArrayListExtra(key, (ArrayList)value);
} else if ((Object[])value instanceof CharSequence[]) {
$receiver.putCharSequenceArrayListExtra(key, (ArrayList)value);
} else if ((Object[])value instanceof Parcelable[]) {
$receiver.putParcelableArrayListExtra(key, (ArrayList)value);
}
} else if (value instanceof Parcelable) {
$receiver.putExtra(key, (Parcelable)value);
} else {
if (!(value instanceof Serializable)) {
throw (Throwable)(new IllegalArgumentException("Not support " + value + " type " + value.getClass() + ".."));
}
$receiver.putExtra(key, (Serializable)value);
}
} else {
int var13 = false;
$receiver.putExtra(key, $receiver.toString());
}
}
return $receiver;
}
}
}
顺手写别的扩展
既然用到Intent的扩展,那么就顺手写下Activity的startActivity的扩展
/**
* 同Context的startActivity
*/
fun Context.toActivity(packageContext: Context?, cls: Class<*>, vararg extras: Pair<String, Any?>) {
startActivity(Intent(packageContext, cls).putExtraVararg(*extras))
}
/**
* 同Context的startActivity
*/
fun Context.toActivity(intent: Intent) {
startActivity(intent)
}
调用的时候就是这样子的
context.toActivity(
context,
SearchActivity::class.java,
SearchActivity.SEARCH_TYPE to item.type,
SearchActivity.SEARCH_UID to item.uid,
SearchActivity.SEARCH_NAME to item.name,
SearchActivity.SEARCH_KEY to item.key,
SearchActivity.SEARCH_GROUP to item.group
)
总结
通过这次的扩展,也学到了关于Array
的一些扩展函数,可以说是很美好了。