Firebase Cloud Messaging(FCM)のHTTP legacy protocolでsendするメモ
fcm_regacy_http.kt
import okhttp3.* private const val URL = "https://fcm.googleapis.com/fcm/send" private val MEDIA_TYPE_JSON = MediaType.parse("application/json; charset=utf-8") private val CLIENT = OkHttpClient() fun send(serverKey: String, jsonString: String): Response = newCall(serverKey, jsonString).execute() fun send(serverKey: String, jsonString: String, callback: Callback) { newCall(serverKey, jsonString).enqueue(callback) } private fun newCall(serverKey: String, jsonString: String): Call = CLIENT.newCall(Request.Builder() .url(URL) .header("Authorization", "key=$serverKey") .post(RequestBody.create(MEDIA_TYPE_JSON, jsonString)) .build() )
Autosizing TextViews
TextView のフォントサイズの自動調整機能は Android 8.0 (API level 26) から導入され、Support Library 26.0 以降でも採用されています。
XML
<TextView android:layout_width="0dp" android:layout_height="wrap_content" android:gravity="center" android:maxLines="2" android:text="じゅげむじゅげむごこうのすりきれかいじゃりすいぎょのすいぎょうまつうんらいまつふうらいまつくうねるところにすむところ・・・" app:autoSizeMinTextSize="1px" app:autoSizeTextType="uniform" />
注意
Auto sizing が効いてない場合の表示:
Auto sizing が効いている場合の表示:
Data BindingでDelegates.observableを使う際に非nullの初期値を強制されたくない件
Data Binding Library で notifyPropertyChanged を利用する際、普通にやると下記のように非 null の初期値が強制されてしまう。
class MyModel : BaseObservable() { @get:Bindable var myText: String by Delegates.observable("") { _, _, _ -> notifyPropertyChanged(BR.myText) } }
しかし、lazy のように get 時には非 null だが初期値は null にしたいというケースがある。
でも、下記のようにできるとラクチンっすね。
class MyModel : BaseObservable() { @get:Bindable var myText: String by dataBindingObservable(BR.myText) }
ということで、以下のようなコードで対応する。
// 上記から dataBindingObservable(BR.myText) って呼ばれるやつ。 fun <T> BaseObservable.dataBindingObservable(brId: Int): ReadWriteProperty<Any?, T> = lazyObservable { _, _, _ -> notifyPropertyChanged(brId) } /** * @see kotlin.properties.Delegates.observable */ inline fun <T> lazyObservable(crossinline onChange: (property: KProperty<*>, oldValue: T?, newValue: T) -> Unit): ReadWriteProperty<Any?, T> = object : LazyObservableProperty<T>() { override fun afterChange(property: KProperty<*>, oldValue: T?, newValue: T) = onChange(property, oldValue, newValue) } /** * @see kotlin.properties.ObservableProperty */ abstract class LazyObservableProperty<T> : ReadWriteProperty<Any?, T> { private var value: T? = null protected open fun beforeChange(property: KProperty<*>, oldValue: T?, newValue: T): Boolean = true protected open fun afterChange(property: KProperty<*>, oldValue: T?, newValue: T) {} override fun getValue(thisRef: Any?, property: KProperty<*>): T { return value ?: throw IllegalStateException("Property ${property.name} should be initialized before get.") } override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) { val oldValue = this.value if (!beforeChange(property, oldValue, value)) { return } this.value = value afterChange(property, oldValue, value) } }
おまけ。
// notifyChange() を使いたい場合 fun <T> BaseObservable.dataBindingObservable(): ReadWriteProperty<Any?, T> = lazyObservable { _, _, _ -> notifyChange() } // 初期値と brId を指定したい場合 fun <T> BaseObservable.dataBindingObservable(initialValue: T, brId: Int): ReadWriteProperty<Any?, T> = Delegates.observable(initialValue) { _, _, _ -> notifyPropertyChanged(brId) } // 初期値を指定して notifyChange() を使いたい場合 fun <T> BaseObservable.dataBindingObservable(initialValue: T): ReadWriteProperty<Any?, T> = Delegates.observable(initialValue) { _, _, _ -> notifyChange() }
kotlinで値がprimitive wrapperのためにlateinitできない場合
'lateinit' modifier is not allowed on properties of primitive types とか怒られるので by Delegates.notNull() で凌ぎましょう。
例:
import kotlin.properties.Delegates var i: Int by Delegates.notNull() fun main(args: Array<String>) { i = 10 println("i = $i") }
結果:
i = 10
Data Binding Library と Google Analytics for Firebase の依存関係の件
Data Binding Library と Google Analytics for Firebase が古いライブラリを参照してるのでメモ。
手元にある support library の version として "27.0.2" を採用しているプロジェクトで、普通にビルドすると lint で下記のように怒られる。
Incompatible Gradle Versions
../../build.gradle: All com.android.support libraries must use the exact same version specification (mixing versions can lead to runtime crashes). Found versions 27.0.2, 25.2.0. Examples include com.android.support:animated-vector-drawable:27.0.2 and com.android.support:support-media-compat:25.2.0
gradlew :modules:app:dependencies とかやると下記のような依存関係がわかる。
com.android.databinding:library:1.3.1 - com.android.support:support-v4:21.0.3 com.google.firebase:firebase-analytics:11.8.0 - com.google.android.gms:play-services-basement:11.8.0 - com.android.support:support-v4:25.2.0
ぐぬぬ、、、
本質的な解決じゃないけど下記のように設定してlintエラーを回避するくらいしかできんよな、、、(´・ω・`)
implementation "com.android.support:support-v4:27.0.2"
RxJava2のnullの扱いとOptional
RxJava 2.0 で Observable による null の emission が非サポートになったので、その点に関してのメモ。
Javaでnullをemitしてみる
Observable<String> source = Observable.create(emitter -> { try { emitter.onNext("Alpha"); emitter.onNext("Beta"); // io.reactivex.exceptions.OnErrorNotImplementedException: The mapper function returned a null value. emitter.onNext("Gamma"); emitter.onNext("Delta"); emitter.onNext("Epsilon"); emitter.onComplete(); } catch (Throwable e) { emitter.onError(e); } }); source.map(s -> s.length() >= 5 ? s.length() : null).subscribe(s -> System.out.println("RECEIVED: " + s));
emitter.onNext("Beta"); のところで例外がスローされる。
JavaでOptionalを使ってみる
Observable<String> source = Observable.create(emitter -> { try { emitter.onNext("Alpha"); emitter.onNext("Beta"); emitter.onNext("Gamma"); emitter.onNext("Delta"); emitter.onNext("Epsilon"); emitter.onComplete(); } catch (Throwable e) { emitter.onError(e); } }); source.map(s -> Optional.ofNullable(s.length() >= 5 ? s.length() : null)).subscribe(optional -> System.out.println("RECEIVED: " + (optional.orElse(null))));
Optional でラップすることにより null を emit していないので例外はスローされず、以下のように出力される。
RECEIVED: 5 RECEIVED: null RECEIVED: 5 RECEIVED: 5 RECEIVED: 7
kotlinで普通にSequencesを使った場合
val source = listOf("Alpha", "Beta", "Gamma", "Delta", "Epsilon") source.map { s -> if (s.length >= 5) s.length else null }.forEach { s -> println("RECEIVED: " + s) }
普通に null が扱えるので、例外はスローされず以下のように出力される。
RECEIVED: 5 RECEIVED: null RECEIVED: 5 RECEIVED: 5 RECEIVED: 7