Kotlinのデフォルト値を使用した関数やコンストラクタをJavaから使用する際のtips
tl;dr
Kotlinコードで定義したデフォルト値を使用した関数,コンストラクタをJavaコードで使う事を想定する場合には@JvmOverloads
アノテーションをつける
@JvmOverloadsアノテーション
Kotlinの関数やコンストラクタの宣言で、以下のようにデフォルト値を使うと
class MyClass { fun myFunc(a: String = "", b: Int = 1, c: Boolean = true) {} }
JavaからはMyClass#myFunc(String, int, boolean)
のみ定義されているように見えます
変数b,cにはデフォルト値を使いつつMyClass#myFunc(String)
の呼び出しを行いたいという場面では@JvmOverloads
アノテーションを使うことができます
@JvmOverloads fun myFunc(a: String = "", b: Int = 1, c: Boolean = true) {}
Javaからは以下の4つが定義されているように見えます
- myFunc()
- myFunc(String)
- myFunc(String, int)
- myFunc(String, int, boolean)
@JvmOverloads
アノテーションをつける事で生成されるメソッドは、関数定義の後ろに宣言されているデフォルト値付き引数から順番に省略されます
今回の例ではc
>b
>a
の順番に引数が消えた関数が生成されます
使用例: AndroidのCustomView
AndroidでCustomViewに以下のようなコンストラクタを生成する際に使うことができます
- MyCustomView(Context)
- MyCustomView(Context, AttributeSet)
- MyCustomView(Context, AttributeSet, int)
class MyCustomView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : View(context, attrs, defStyleAttr)
後ろにあるデフォルト値付き引数から順番に消えるため、リフレクションを使う場合など、引数の順番が大事な場合には定義の順番に気をつける必要があります
公式ドキュメント
Kotlinレポジトリのidea pluginやJ2Kのテスト実行方法メモ
Kotlin1.1.50あたりからビルドスクリプトがgradle(Gradle Kotlin Script)になった。その影響かテストの実行方法が変わっていたので、メモしておく
※以下の情報は古くなる可能性が高いのでまずはKotlin(github)のReadmeを先に読んでください
Gradleタブから実行
IntellijのGradleタブからtestを実行するタスクを見つけて実行する
だいたいはTasks
のverification
にあると思う
Gradleのタスクを直接実行する
Gradleなのでターミナルから直接テストタスクを実行することができる
テストの実行
例: ideaのテストを実行
./gradlew :idea:cleanTest :idea:test
テスト結果はbuildディレクトリの中に作成される
一部のテストだけ実行する
一部のテストだけ実行したいという場合がよくあると思うが、その場合は--tests
オプションを使うと良い
例: ideaのorg.jetbrains.kotlin.addImport
パッケージ内のテストのみ実行
./gradlew :idea:cleanTest :idea:test --tests org.jetbrains.kotlin.addImport.*
Projectツリーから実行
Intellijの設定
Readmeにも少し書いてあるが、以下のページを開き
Preferences
-> Build, Execution, Deployment
->Build Tools
-> Gradle
-> Runner
Delegate IDE build/run actions to Gradle
をチェックする。書いてある通り、チェックをするとビルドや実行のアクションをGradleに移譲することができる
テストの実行
設定が終わったらIntellijでプロジェクトツリーでテストコードがあるディレクトリを開き、右クリックをしてRun Testする
一部のテストのみ実行する
RunTestを行うと新しくRun Configurationが作られていると思うので、Edit Configurationsから編集を行う
Gradleタスクの引数で制御する形になるのでArgumentsに条件を書く
CamTwistを使ってAndroidEmulatorのカメラソースをPC画面にする
バーコード読み取り機能を作る場合などにいちいち実機でバーコードをスキャンするのが面倒臭かったのでなんとかPCに表示した画像をエミュレータのカメラソースにできないか調べてみました
CamTwist
CamTwistはニコニコ生放送やTwitchなどで配信する時に、Webカメラの映像ではなく、PC画面を映像のソースとして配信するためのソフトです。エミュレータではWebカメラや内臓カメラをソースとして使えますが、同じようにCamTwistの映像も使うことができます
以下の方法はCamTwist以外にも同じ機能をもったソフトであれば有効だと思います
設定方法
CamTwist
CamTwistをダウンロードページからダウンロードしてインストールします
CamTwistの設定は、以下のようにします
- Desktop (範囲は任意)
- Rotation Translation(任意)
- Zoom(任意)
エミュレータで表示した時に画像が回転した状態で表示されていたらRotationを設定してみてください
AVD
- エミュレータの設定画面から
Show Advanced Settings
を押す - Cameraの設定をwebcam0にする
- 設定を保存
以上で設定は終了です
エミュレータ起動
エミュレータでカメラアプリを起動して確認してみます
以下のようにCamTwistで指定した範囲の映像が表示されていればOKです
おまけ webcam0について
Macではもともと内臓カメラがついている端末がほとんどだと思いますが、エミュレータの設定では内臓カメラやCamTwistなどの映像ソースが複数ある場合でもwebcam0しか選択することができません(AndroidStudioのエミュレータ設定ではカメラがあろうがなかろうがNone, Emulated, Webcam0の3つのみ選択できるようになっているようです)。
そのため、環境によっては内臓カメラの映像が自動的に選択されてしまうかもしれません。
emulatorコマンド Commonly used optionsを見た限りではemulatorコマンドからエミュレータを起動する際にどの映像ソースを使うかを選択できそうですが、カメラ一覧を取得してもwebcam0しか表示されず任意の映像ソースを選択する方法はわかりませんでした。
FCMを使ってAndroid端末へ通知を送るスクリプト
Firebase Cloud Messaging(FCM)を使ってAndroid端末へ通知を送るスクリプトを作りました(iOSは非対応です)
スクリプト内で送られているデータはcurlを使う場合を参照してください
作成したスクリプト
ソースコードは https://github.com/sckm/fcm-send にあがっています
インストール
あらかじめgoがインストールされている必要があります
$ go get github.com/sckm/fcm-send
使い方
以下のように、はじめにjsonのdataキーで送りたい内容をファイルに書いておきます
{ "message": "Hello World!", "title": "example title" }
その後、以下のコマンドを実行することで通知が送られます
$ token='registration token' $ server_key='your server key' $ fcm-send -t $token -s $server_key -p data.json
curlを使う場合
作成したスクリプトは以下のcurlコマンドと同等のリクエストを送っています
token='registration token' server_key='your server key' msg='{"message":"Hello World!", "title": "example title"}' curl \ --header "Authorization: key=${server_key}" \ --header Content-Type:"application/json" \ https://fcm.googleapis.com/fcm/send \ -d "{ \"to\" : \"${token}\", \"data\": $msg }"
FirebaseCrashReportingにmappingファイルをあげるスクリプトを作った
FirebaseCrashReportingにAndroidのマッピングファイルをあげる際に相対パスが使えなかったり、google-services.jsonがapp直下にない時にAppIdなどを指定するのが面倒くさかったのでgolangでスクリプトを作ってみました
ソースコードは https://github.com/sckm/fcr-upload-mapping
動作環境
- あらかじめgoがインストールされている必要があります
- Mac OS X El Capitan以外では動作を確認していないです
- 内部でfirebase-crashプラグインで生成されるコマンドを使っているのでプラグインを適用する必要があります(バージョン1.0.5以上)
Uploading ProGuard mapping files with Gradle
インストール
go get github.com/sckm/fcr-upload-mapping
使い方
cd [Androidプロジェクトのルートパス] fcr-upload-mapping \ -a [サービスアカウントキーファイルのパス] \ -c [アプリバージョンコード] \ -p [パッケージ名] \ -m [マッピングファイルのパス] \ -s [google-services.jsonのパス]
google-services.jsonがapp直下にある場合は省略可能です
その他
今はgradlewがあるディレクトリでしか動かないようになっていたり、引数の説明が足りないので修正したい
Golangに慣れていないのでコードが汚い・・・
RxJava2のSingle.zipのエラー処理ではまった話
問題
RxJavaでたまにonErrorReturnItem
などでエラー処理をしていてもたまにエラーがすり抜けてきてアプリが落ちてしまうことがあった
問題となっていそうな部分を簡単に表すと以下のようになっていた
Single.zip( Single Single ) .onErrorReturnItem
対処方法
RxJavaのissuesを調べてみると同じ問題があった
Rx2: Multiple errors in zip'ed observables throw exception
ここに書いてある対処方法は、
RxJavaPlugins.setErrorHandler()
でエラーハンドラーを設定する(issueのコメントではsetOnError
になっているが名前が変更になった?)- zipの中のSingleで
onErrorReturn
やonErrorResumeNext
などを呼び出す
いっけん良さそうに見えるので原因がわかりづらくてはまってしまった
実際にはどうしてそうなってしまうのかまだわかっていないのでRxJavaの実装を読んでいきたい
文字列リソースに複数の値を渡す
基本的な方法
複数の値を渡す際には%1$s
や%2$s
などを設定する。
1や2で何番目の引数を使うかを指定する
<string name="string_res1">1番目%1$s 2番目%2$s"</string>
getString(R.string.string_res1, "A", "B") 結果: 1番目A 2番目B
渡した値の一部を使わない場合
引数で複数の値を渡すが文字列リソースで使わない場合の挙動
<string name="string_res2">2番目のみ%2$s"</string>
getString(R.string.string_res2, "A", "B") 結果: 2番目のみB
特に問題なく文字列が取得できる
必要以上に値を渡した場合
1番目の引数のみ使う文字列リソースに2つの値を渡した場合
<string name="string_res3">1番目%1$s"</string>
getString(R.string.string_res3, "A", "B") 結果: 1番目A
実行時には問題なく文字列が取得できる
ただしlintでの警告がでる
values-ja/strings.xml
を作成して日本語の場合に2つの値を使うようにしても警告がでた