记一次写Intent的扩展


前言

写项目的时候经常会写到跳转Activiey,写到跳转Activit就一定会写到putExtra,就像下面那样

1
2
3
intent.putExtra("a", item.a)
intent.putExtra("b", item.b)
intent.putExtra("c", item.c)

挺多哈,每次都要重复前面相同的内容,所以就想着能不能写个扩展来简写。

开始

我们最终实现是这样的:

1
2
3
4
5
6
Intent(context, TestActivity::class.java)
.putExtraVararg(
"a" to item.a,
"b" to item.b,
"c" to item.c
)

仿mapOf

经常用到mapOf()或者mutableMapOf()就会知道,里面是用了Pair类来生成Map的,所以受此启发,打算用Pair来作为参数实现,那么写的时候就应该是这样写,参数为可变参数类型:

1
2
3
4
5
6
// 作为Intent的扩展
fun Intent.putExtraVararg(
vararg extras: Pair<String, Any?>
): Intent {
// 先省略
}

putExtra的第一个参数类型肯定是String类型,第二个参数的类型包括Bundle, Boolean, BooleanArray, Byte, ByteArray, Char, CharArray, String等等,所以就用Any类型,因为是可空的,所以加上?

那么调用的时候,就是这样子的

1
2
3
4
5
6
Intent(context, TestActivity::class.java)
.putExtraVararg(
"a" to item.a,
"b" to item.b,
"c" to item.c
)

是不是就是一开始说的那样,对比平常写的是不是简单了很多。

参数类型匹配

写好了参数,那么就要进行对参数类型的匹配进行对应的putExtra

vararg参数可以用forEach来循环对每个参数类型进行匹配:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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()

1
2
3
4
5
6
/**
* 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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

最终

最后完整的代码为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
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是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100

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的扩展

1
2
3
4
5
6
7
8
9
10
11
12
13

/**
* 同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)
}

调用的时候就是这样子的

1
2
3
4
5
6
7
8
9
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的一些扩展函数,可以说是很美好了。