2017-08-19 11 views
1

firebaseからデータを取得するための一般的な方法を書いていますか?場合によっては、nullを戻すことが有効であり、そうでない場合は、汎用のparamがnullableかどうかを確認することが可能ですか?Kotlin - 汎用パラメータがオプションかどうかを確認しますか?

reference.obsrveObject(User.class) 

nullが

reference.obsrveObject(User?.class) 

NULL値で

fun DatabaseReference.observeSingleEvent(): Observable<DataSnapshot?> { 
    return Observable.create { subscriber -> 
     val valueEventListener = object: ValueEventListener { 
      override fun onDataChange(snapshot: DataSnapshot?) { 
       subscriber.onNext(snapshot) 
       subscriber.onCompleted() 
      } 

      override fun onCancelled(error: DatabaseError?) { 
       subscriber.onError(FirebaseDatabaseThrowable(error)) 
      } 
     } 

     addListenerForSingleValueEvent(valueEventListener) 
    } 
} 

fun <T>DatabaseReference.obsrveObject(clazz: Class<T>): Observable<T> { 
    return observeSingleEvent().map { snapshot -> 
     if (snapshot != null) { 
      snapshot.getValue(clazz) 
     } 
     else { 
      // if clazz is nullable return null 
      // if clazz is not nullabel throw 
      throw Exception("") 
     } 
    } 
} 

答えて

3

注意をonNext呼び出す必要があればスローする必要があります:私は個人的にはまだので、いくつかのFirebaseを使用していませんでした以下の例はコンパイルできないかもしれませんが、十分に近いものでなければなりません。

どちらもClass<T>でもKClass<T>でも、クラスを表すに過ぎないため、nullの可能性がありません。しかし、KTypeは、「オプションの型引数とnull許容度を持つクラス」を表すことができ、isMarkedNullableプロパティを持ちます。

reified type parametersを使用すると、汎用タイプのKClassが得られますが、(Kotlin 1.1の)KTypeは取得できません。ただし、genericタイプがnull is T(のpointing outのため、try/catchのラベリングnull as Tが必要でない)のヌル入力可能(nullable reified type : Kotlin)であるかどうかを確認できます。これにより


、限り、あなたはinlineとしてobsrveObjectをマークすることができますように、あなたは "一般的なパラメータがオプションであるかないかどうかを確認する" ことができます。

inline fun <reified T> DatabaseReference.obsrveObject(): Observable<T> { 
    return observeSingleEvent().map { snapshot -> 
     if (snapshot != null) { 
      snapshot.getValue(T::class.java) 
     } else if (null is T) { 
      null as T 
     } else { 
      throw Exception("") 
     } 
    } 
} 

使用法:

databaseReference.obsrveObject<User>() // Observable<User> 
databaseReference.obsrveObject<User?>() // Observable<User?> 

インライン関数を使用できないため(したがってタイプパラメータを変更できない) KTypeを取得する方法を見つける。

あなたはKCallable<R>returnTypeからKTypeを得ることができますが、あなたはまた、createTypeを使用してKClass<T>からKTypeを作成することができます。

User::class.createType(nullable = false) // User 
User::class.createType(nullable = true)  // User? 

ここにクラスがあるタイプのclassifierので、どのようにあなたがあなたのobsrveObjectを使用しているに応じて、引数型をClass<T>からKCallable<T>に変更する可能性があります。あなたは直接KTypeに変更し、必要に応じてインスタンスを作成しますが、私はKCallable<T>となるだろうので、あなたは、プロパティの戻り値の型から現在clazzをつかん推測している可能性があり:

fun <T : Any> DatabaseReference.obsrveObject(callable: KCallable<T>): Observable<T?> { 
    val kType = callable.returnType 
    val kClass = kType.classifier as KClass<T> 
    val clazz = kClass.java 
    return observeSingleEvent().map { snapshot -> 
     if (snapshot != null) { 
      snapshot.getValue(clazz) 
     } else if (kType.isMarkedNullable) { 
      null 
     } else { 
      throw Exception("") 
     } 
    } 
} 

あなたはその後、使用してそれを呼ぶだろう呼び出し可能な(プロパティ、関数などの)参照):

databaseReference.obsrveObject(session::user) 
+0

ありがとうございます。返された結果は、オプションのタイプオブザーバブルでなければなりませんか? – aryaxt

+0

'null'を返すには、Observable またはObservable ?を返す必要があります。後でしたい場合は、 'nullを返す 'ことができるはずです。 – mfulton26

+0

私は必要に応じてこれをオプションとして定義できると思っていましたが、これは迅速に可能ですが、Kotlinにはありませんか?たとえば、データ、データ、そのようにジェネリック型は必要に応じてユーザーとしてオプションまたは必須として定義することができます – aryaxt

関連する問題