kotlinは簡単なAndroidルーティングを実現する(2)--』rxbusはintentの代わりに値を伝達する
25598 ワード
OK、前の文章では基礎機能を実現しました.startactivity、kotlinは簡単なAndroidルーティング(1)を実現しましたが、パラメータの伝達はまだできません.この文章ではパラメータの伝達を完成しました.
もちろん,伝達パラメータが最初に考慮されるのはIntentに違いない.
activityを起動するときにパラメータを持っていくのは比較的簡単ですが、コードを見てみましょう.Routerにはaddpamaメソッドが必要です.もちろん、タイプ判断は完全にできます.手動でタイプを追加する必要はありません.
そしてstartActivityの時にintentEventのbundleを渡せばいいです
複雑ではありません.使うときもいいです.コードを書くことができます.
はっきりしているかどうか.しかし、データを取得するときは優雅ではありません.
このようにして取得しました.もちろんAndroidではわかりますが、iosやEEであればこのコードを見ると少しぼんやりしていて、意味が分かりません.このような突然のコードは、奇妙に見えます.routerでパラメータを取得することを望んでいます.router.getPama()->{}という形式でコードをより明確にします.
intentの使用を放棄させたのはもう一つ、startactivityforresultの場合、受信パラメータにonactivityResult()を書く必要があります.
そしてfragmentでパラメータを渡す場合はもう一つの方法でArgumentsを使ってパラメータを渡す必要がありますが、私たちのプロジェクトでパラメータを渡すことは簡単に統一できますか?
そこで何か方法を考えたが、感覚的にはよくなかったので、イベントディレクターにeventbusを使いたいと思っていたが、eventbusが少し古くなったような気がして、しばらくひっくり返し続けた後、これはReactiveXを使ってできることに気づいた.
どうすればいいのか、まず簡単なrxbusを実現し、tonyのコード「RxJava 2.x実戦」のRxを参考にEventbusを実現し、簡略化した結果、
簡単に説明すると、これはRxAndroidパッケージに基づいたRelayライブラリを使用しています.このライブラリは観察者としても送信者としても、最も重要な点です.異常が発生した後もメッセージを受信できます(これはプログラムの頑丈性にとって非常に重要です.そうしないと、1、2回異常が発生した後、イベントバスが使えなくなり、app全体が終わります).そして、registerStickyメソッドがあり、toObservableStickyを登録します.次世代コードを見て、postStickyを見ていると、イベントを同期してmStickyEventMapに保存します.そして登録するとき、mapからデータを取り出してobservableに送信するという問題が解決します.observableはpostの後に登録して、前に送信したパラメータを受信することができます.では、カプセル化した後、ページとページの間でパラメータの伝達、伝達などを行うことができます.
そして、エコーパラメータを取得する必要があるactivityでgerResultメソッドを実装すればOKです.
2つのfragment間の伝達パラメータでもpoststickyではなくpostを完全に使用できる場合、poststicky単はActivityでの伝達値を満たすシーン(observableはpost後に登録される)
もちろんパッケージが悪いので、このようなイベントバスはfragment間の伝達パラメータを満たすことができ、ルーティングのfragmentのサポートはまだ行われていません.次はfragmentがルーティングを使用して切り替えることを実現する必要があります.
もちろん,伝達パラメータが最初に考慮されるのはIntentに違いない.
activityを起動するときにパラメータを持っていくのは比較的簡単ですが、コードを見てみましょう.Routerにはaddpamaメソッドが必要です.もちろん、タイプ判断は完全にできます.手動でタイプを追加する必要はありません.
fun addPama(key:String,value:Any):Router{
// value start
if (value == null) {
// RLog.w("Ignored: The extra value is null.")
return this
}
var bundle = intentEvent.bundle
if (bundle == null) {
bundle = Bundle()
}
if (value is Bundle) {
bundle.putBundle(key, value)
} else if (value is Byte) {
bundle.putByte(key, value)
} else if (value is Short) {
bundle.putShort(key, value)
} else if (value is Int) {
bundle.putInt(key, value)
} else if (value is Long) {
bundle.putLong(key, value)
} else if (value is Char) {
bundle.putChar(key, value)
} else if (value is Boolean) {
bundle.putBoolean(key, value)
} else if (value is Float) {
bundle.putFloat(key, value)
} else if (value is Double) {
bundle.putDouble(key, value)
} else if (value is String) {
bundle.putString(key, value)
} else if (value is CharSequence) {
bundle.putCharSequence(key, value)
} else if (value is ByteArray) {
bundle.putByteArray(key, value)
} else if (value is ShortArray) {
bundle.putShortArray(key, value)
} else if (value is IntArray) {
bundle.putIntArray(key, value)
} else if (value is LongArray) {
bundle.putLongArray(key, value)
} else if (value is CharArray) {
bundle.putCharArray(key, value)
} else if (value is BooleanArray) {
bundle.putBooleanArray(key, value)
} else if (value is FloatArray) {
bundle.putFloatArray(key, value)
} else if (value is DoubleArray) {
bundle.putDoubleArray(key, value)
}else if (value is CharArray) {
bundle.putCharArray(key, value)
}
else if (value is IBinder) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
bundle.putBinder(key, value)
} else {
// RLog.e("putBinder() requires api 18.")
}
} else if (value is ArrayList) {
if (!value.isEmpty()) {
val obj = value[0]
if (obj is Int) {
bundle.putIntegerArrayList(key, value as ArrayList)
} else if (obj is String) {
bundle.putStringArrayList(key, value as ArrayList)
} else if (obj is CharSequence) {
bundle.putCharSequenceArrayList(key, value as ArrayList)
} else if (obj is Parcelable) {
bundle.putParcelableArrayList(key, value as ArrayList<out Parcelable>)
}
}
} else if (value is SparseArray) {
bundle.putSparseParcelableArray(key, value as SparseArray<out Parcelable>)
} else if (value is Parcelable) {
bundle.putParcelable(key, value)
}
else if (value is Serializable) {
bundle.putSerializable(key, value)
} else {
// RLog.w("Unknown object type: " + value.javaClass.name)
}
// ,
// else if (value is Array) {
// bundle.putParcelableArray(key, value)
// }
// else if (value is Array) {
// bundle.putStringArray(key, value)}
intentEvent.bundle = bundle
return this
}
そしてstartActivityの時にintentEventのbundleを渡せばいいです
複雑ではありません.使うときもいいです.コードを書くことができます.
router.initialize("activityfragment")
.addPama("test","teststr")
.addPama("testbool",true)
.addPama("testInt",100)
.start(baseContext)
はっきりしているかどうか.しかし、データを取得するときは優雅ではありません.
var str = intent.getStringExtra("test")
var b = intent.getBooleanExtra("testbool",false)
var i =intent.getIntExtra("testInt",0)
このようにして取得しました.もちろんAndroidではわかりますが、iosやEEであればこのコードを見ると少しぼんやりしていて、意味が分かりません.このような突然のコードは、奇妙に見えます.routerでパラメータを取得することを望んでいます.router.getPama()->{}という形式でコードをより明確にします.
intentの使用を放棄させたのはもう一つ、startactivityforresultの場合、受信パラメータにonactivityResult()を書く必要があります.
そしてfragmentでパラメータを渡す場合はもう一つの方法でArgumentsを使ってパラメータを渡す必要がありますが、私たちのプロジェクトでパラメータを渡すことは簡単に統一できますか?
そこで何か方法を考えたが、感覚的にはよくなかったので、イベントディレクターにeventbusを使いたいと思っていたが、eventbusが少し古くなったような気がして、しばらくひっくり返し続けた後、これはReactiveXを使ってできることに気づいた.
どうすればいいのか、まず簡単なrxbusを実現し、tonyのコード「RxJava 2.x実戦」のRxを参考にEventbusを実現し、簡略化した結果、
class RxBus//
private constructor() {
private var bus: Relay? = null
private val mStickyEventMap: MutableMap, Any>
init {
bus = PublishRelay.create().toSerialized()
mStickyEventMap = ConcurrentHashMap()
}
fun post(event: Any) = bus!!.accept(event)
private fun <T> toObservable(eventType: Class<T>): Observable<T> = bus!!.ofType(eventType)
fun <T> register(eventType: Class<T>, onNext: Consumer<T>): Disposable =toObservable(eventType).observeOn(AndroidSchedulers.mainThread()).subscribe(onNext)
fun postSticky(event: Any) {
synchronized(mStickyEventMap) {
mStickyEventMap.put(event.javaClass, event)
}
bus!!.accept(event)
}
/**
* eventType (eventType)
*/
private fun <T> toObservableSticky(eventType: Class<T>): Observable<T> {
synchronized(mStickyEventMap) {
val observable = bus!!.ofType(eventType)
val event = mStickyEventMap[eventType]
return if (event != null) {
observable.mergeWith(Observable.create(object : ObservableOnSubscribe<T> {
override fun subscribe(e: ObservableEmitter<T>) {
e.onNext(eventType.cast(event))
}
}))
} else {
observable
}
}
}
fun <T> registerSticky(eventType: Class<T>, onNext: Consumer<T>):Disposable
= toObservableSticky(eventType).observeOn(AndroidSchedulers.mainThread()).subscribe(onNext)
/**
* eventType Sticky
*/
fun <T> removeStickyEvent(eventType: Class<T>): T {
synchronized(mStickyEventMap) {
return eventType.cast(mStickyEventMap.remove(eventType))
}
}
/**
* Sticky
*/
fun removeAllStickyEvents() {
synchronized(mStickyEventMap) {
mStickyEventMap.clear()
}
}
fun unregister(disposable: Disposable?) {
if (disposable != null && !disposable.isDisposed()) {
disposable.dispose()
}
}
private object Holder {
val BUS = RxBus()
}
companion object {
fun get(): RxBus {
return Holder.BUS
}
}
}
簡単に説明すると、これはRxAndroidパッケージに基づいたRelayライブラリを使用しています.このライブラリは観察者としても送信者としても、最も重要な点です.異常が発生した後もメッセージを受信できます(これはプログラムの頑丈性にとって非常に重要です.そうしないと、1、2回異常が発生した後、イベントバスが使えなくなり、app全体が終わります).そして、registerStickyメソッドがあり、toObservableStickyを登録します.次世代コードを見て、postStickyを見ていると、イベントを同期してmStickyEventMapに保存します.そして登録するとき、mapからデータを取り出してobservableに送信するという問題が解決します.observableはpostの後に登録して、前に送信したパラメータを受信することができます.では、カプセル化した後、ページとページの間でパラメータの伝達、伝達などを行うことができます.
@Route("testactivity")
class TestActivity: Activity() {
var dispose :Disposable?=null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test)
// , , , ,
dispose = RxBus.get().registerSticky(IntentEvent::class.java,onNext = Consumer {
Log.e("result",it.bundle.getString("test"))
Log.e("result",it.bundle.getBoolean("testbool").toString())
Log.e("result",it.bundle.getInt("testInt").toString())
Log.e("result",it.bundle.getDouble("testfloat").toString())
})
}
override fun onBackPressed() {
RxBus.get().unregister(dispose)// unregister
RxBus.get().post(RouteResponse("respose")) //
super.onBackPressed()
}
}
abstract class RouterResultActivity : Activity() {
var backdispose : Disposable?=null //
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
backdispose = RxBus.get().register(RouteResponse::class.java,onNext = Consumer {
getResult(it)
})
}
//
abstract fun getResult(response:RouteResponse)
override fun onBackPressed() {
// Disposable
RxBus.get().unregister(backdispose)
super.onBackPressed()
}
fun back(){
RxBus.get().unregister(backdispose)
finish()
}
}
パラメータ取得を完了するために、このようなベースクラスを継承するそして、エコーパラメータを取得する必要があるactivityでgerResultメソッドを実装すればOKです.
override fun getResult(response: RouteResponse) {
Log.e("result",response.target)
}
2つのfragment間の伝達パラメータでもpoststickyではなくpostを完全に使用できる場合、poststicky単はActivityでの伝達値を満たすシーン(observableはpost後に登録される)
もちろんパッケージが悪いので、このようなイベントバスはfragment間の伝達パラメータを満たすことができ、ルーティングのfragmentのサポートはまだ行われていません.次はfragmentがルーティングを使用して切り替えることを実現する必要があります.