記一次寫Intent的擴充套件
寫專案的時候經常會寫到跳轉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$valuetype${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$valuetype${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 )