Android アプリの Drawable リソースのエイリアスの作成について
当たり前の内容だけど日本語ドキュメントが間違っててバグを埋め込んでしまった (リリースはしてない) ので共有。
Drawable リソースのエイリアス作成
res/values/drawables.xml ファイルみたいなファイルを作って、そこに <drawable name="alias_name">@drawable/target_drawable</drawable>
みたいなタグを書けばエイリアスを作れる。
To create an alias to an existing drawable, use the
element. For example: <?xml version="1.0" encoding="utf-8"?> <resources> <drawable name="icon">@drawable/icon_ca</drawable> </resources>If you save this file as drawables.xml (in an alternative resource directory, such as res/values-en-rCA/), it is compiled into a resource that you can reference as R.drawable.icon, but is actually an alias for the R.drawable.icon_ca resource (which is saved in res/drawable/).
App resources overview | Android Developers
日本語ドキュメントが間違ってる件
日本語ドキュメントだと、
既存のドローアブルのエイリアスを作成するには、
<bitmap>
要素を使用します。次に例を示します。
って書かれてる。 が、実際にこれをやって (Bitmap Drawable 以外の?) Drawable リソースのエイリアスを作成しようとすると実行時にエラーが発生する。 (API level 16、23、25 のエミュレータで確認。)
ドキュメントの誤りについては https://issuetracker.google.com/issues/78862550 に報告した。
`bitmap` 要素を使ったときのエラー例
<?xml version="1.0" encoding="utf-8"?> <bitmap xmlns:android="http://schemas.android.com/apk/res/android" android:src="@drawable/simple_drawable" />
上のような XML ファイルを用意して、Drawable として読み込もうとすると以下のようなエラー。
java.lang.RuntimeException: Unable to start activity ComponentInfo{info.vividcode.sample.simple/info.vividcode.sample.simple.MainActivity}: android.view.InflateException: Binary XML file line #31: Binary XML file line #31: Error inflating class ImageView at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476) (中略) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) Caused by: android.view.InflateException: Binary XML file line #31: Binary XML file line #31: Error inflating class ImageView at android.view.LayoutInflater.inflate(LayoutInflater.java:539) at android.view.LayoutInflater.inflate(LayoutInflater.java:423) (中略) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) Caused by: android.view.InflateException: Binary XML file line #31: Error inflating class ImageView at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:782) at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:704) (中略) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) Caused by: android.content.res.Resources$NotFoundException: File res/drawable/simple_drawable_3.xml from drawable resource ID #0x7f02005f at android.content.res.Resources.loadDrawableForCookie(Resources.java:2640) at android.content.res.Resources.loadDrawable(Resources.java:2540) at android.content.res.TypedArray.getDrawable(TypedArray.java:870) at android.widget.ImageView.<init>(ImageView.java:152) (中略) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) Caused by: org.xmlpull.v1.XmlPullParserException: Binary XML file line #2: <bitmap> requires a valid 'src' attribute (以下略)
Android における View にまつわる状態とライフサイクルについての考慮のメモ
Activity が再生成される際の、View の onSaveInstanceState
メソッドと onRestoreInstanceState
メソッドについて個人用にまとめておく。
Activity の再生成
- Activity が再生成 (re-creation) される際には、以前の状態が
Activity#onCreate
とActivity#onRestoreInstanceState
に渡される。 Activity#onRestoreInstanceState
が呼ばれるのは、Activity#onStart
が呼ばれた後。- 『This method is called after
onStart()
when the activity is being re-initialized from a previously saved state, given here in savedInstanceState.』 (Activity#onRestoreInstanceState
より)
- 『This method is called after
Activity#onRestoreInstanceState
が呼ばれるのは、Activity 再生成後の最初のActivity#onStart
が呼ばれた後の 1 回だけ。 (Android 8.0 の端末で実際の挙動を確認。)
View 周り
- View にも
View#onRestoreInstanceState
メソッドやView#onSaveInstanceState
メソッドがあるが、これらはどこから呼ばれるのか? - →
Activity#onRestoreInstanceState
メソッドやActivity#onSaveInstanceState
メソッドのデフォルト実装による。- 『The default implementation of this method performs a restore of any view state that had previously been frozen by
onSaveInstanceState(Bundle)
.』
- 『The default implementation of this method performs a restore of any view state that had previously been frozen by
Window
あたりがルートビューのView#saveHierarchyState
やView#restoreHierarchyState
などを呼んで、そっからView#dispatchSaveInstanceState
やView#dispatchRestoreInstanceState
やらが呼ばれて、最後にView#onSaveInstanceState
やView#onRestoreInsntaceState
やらにたどり着く。android:saveEnabled
の考慮はView#dispatchSaveInstanceState
で行われる。- 子 View の
View#dispatchSaveInstanceState
を呼ぶのはViewGroup#dispatchSaveInstanceState
が行っている。 - ここら辺は実際のコードをみて確認した。 API Level 27。
View にまつわる状態とライフサイクルについての考慮 (?)
- View Model やら Presenter みたいな、いわゆる Presentation Model 的なものを作っていると、Activity の再生成時の View の状態 (
View#onRestoreInstanceState
で復元されるやつ) と、Presentation Model 側の状態の同期をどうとるかで悩むことになりがち。 - 道はいくつもある
- カスタム View を作って、その内部に状態を持たせる。 状態の保存はカスタム View の
View#onSaveInstanceState
に任せる。 - View の状態管理は完全にアプリケーション側の責務ということにして、Android フレームワークの力には頼らない。 View には
android:saveEnabled="false"
を設定する。 - Activity 再生成時の状態復元は View だけでやって、Presentation Model 側では View 側の状態復元をフックにして状態を変える。
- 具体的に言うと、例えば
EditText
の入力内容に対応して Presentation Model 側で状態を保持する設計を考える。 Activity 再生成時の初期状態ではEditText
も Presentation Model も入力内容がない場合の状態になってて、onRestoreInstanceState
でEditText
の状態が復元される際にTextWatcher
でイベントを捕捉して Presentation Model 側の状態も変える、みたいな。
- 具体的に言うと、例えば
- カスタム View を作って、その内部に状態を持たせる。 状態の保存はカスタム View の
- Android フレームワークの挙動をちゃんと理解しておけばなんとでもなるのだけど、ちゃんとりかいしておかないと変なところでハマる。
- 個人的には Activity と View を疎に保ちたいのだけど、Android フレームワーク的には結構べったりくっついてるので辛い。
ThreeTenABP と ThreeTenBP の関係について (Android における JSR-310 バックポート)
「ThreeTenABP って Android フレームワークに依存するけど、ドメインレイヤとかで Android 依存を排除したい場合どうするのがいいんですかね」 という相談を受けて、ThreeTenABP 周りを調べたのでメモ。
ThreeTenABP って何?
- JSR 310 Date and Time API の Android 向け Backport。 Jake 氏作。
- GitHub リポジトリ : GitHub - JakeWharton/ThreeTenABP: An adaptation of the JSR-310 backport for Android.
- 『An adaptation of the JSR-310 backport for Android.』 とのこと。
JSR 310 Date and Time API 周りの話
- ThreeTen - Home page and Documentation
- Java SE 8 で Java API に導入された時刻周りの API。
- Java SE 7 以前の環境向けのバックポートも存在する : ThreeTen Backport
ThreeTenABP が存在する意味は?
ThreeTenABP の具体的な実装
というわけで
ThreeTenABP を使いたいけど Android フレームワークに依存させたくないというモジュールでは、ThreeTen Backport に依存させて、テストを書く際にタイムゾーン情報の扱いだけなんとかする、みたいなことをすれば良さそう。
タイムゾーン情報周りを厳密にテストしなくていいなら、compileOnly "org.threeten:threetenbp:${threetenbp_version}"
と testCompile "org.threeten:threetenbp:${threetenbp_version}"
を依存に追加しちゃうのが手軽でいい気がする。 (バージョン周りはよしなに。 これでうまくいくだろうと思って書いてるけど特に何も確認はしてない。)
関連ページ
- ThreeTen-Backport – Changes : ThreeTen Backport の 1.3 でタイムゾーン情報を持たない JAR ファイルもリリースされるようになった。 Android 用。
- GitHub - dlew/joda-time-android: Joda-Time library with Android specialization : Joda-Time でも同じような問題があって、Android 用のものが作られてる。
- Joda Time's Memory Issue in Android : タイムゾーン情報を JAR から読み込む方式だと Android でメモリ使用量が大きくなる話。 (Joda-Time の話だけど ThreeTen Backport も同じらしい。)
- Android の Java で時刻を扱う (Date、Calendar、DateFormat クラス) - ひだまりソケットは壊れない : 本筋ではないけど冒頭で ThreeTen ABP の紹介をした。
Android のアカウントマネージャ (AccountManager) の概説
最近 Android のアカウントマネージャを仕事で触ったので、調べた内容としてアカウントマネージャの概要をまとめておきます。
Web 上を調べると AccountManager
を使う処理の実装方法はいろいろ見つかるのですが、アカウントマネージャの概要を説明しているページはあんまりなくて全体像を掴みにくいと思っています。 そういう情報を探している人の役に立てば幸いです。
公式ドキュメント
アカウントマネージャに関する公式ドキュメントは以下のものぐらいしかなさそうです。 AccountManager
クラスのドキュメントを全て (各メソッドの説明も含めて) 読むと大体理解できると思います。 (下記ドキュメントを見て理解したら本ページの内容を読む必要はありません。)
- AccountManager | Android Developers
- AbstractAccountAuthenticator | Android Developers
- Remembering Users | Android Developers
AccountManager
を使って認証情報を取得する方法 (利用側) : Remembering Your User と Authenticating to OAuth2 ServicesAccountManager
経由でのアカウント追加や認証情報取得のリクエストを処理する方法 (提供側) : Creating a Custom Account Type
アカウントマネージャの概要
アカウントマネージャは、Android のシステムがユーザーのオンラインアカウントを中央管理するための機能です。 Android 端末の 「設定」 にずらずらとアカウントが並ぶと思いますが、これもアカウントマネージャの仕組みで実現されています。
各種オンラインサービスはそれぞれ異なったアカウントの扱い方や認証方式を使うため、アカウントマネージャはアカウント種別ごとに authenticator モジュールを使い分けるようになっています。
使いどころ
複数アプリで認証情報を共有するときに便利です。 (認証情報の提供側、および利用側両方とも。)
また、単一アプリでのみ認証情報を使う場合でも便利に使えると思います。 なぜなら、アカウントマネージャを使うことで認証周りの処理を分離しやすくなり、また、統一された方法で認証トークンを扱えるようになるためです。
用語
- Account Type : Authenticator を特定するための文字列。
- Auth token (認証トークン) : オンラインサービスのユーザー認証に使われるトークン。
- Auth token type : Authenticator 固有の、Auth token 種別。 1 つのアカウントが auth token を複数持つことができる。
- Feature : Authenticator 固有の、アカウントプロパティを特定するトークン。
- Client (クライアント) / Application : アカウントマネージャを使って認証情報を取得するアプリを指す。
- Authenticator : トークンの払い出しなどを行うやつ。 実体は
AbstractAccountAuthenticator
を継承したクラス。- システム上で有効な authenticator (
AbstractAccountAuthenticator
) を持っているアプリを指して Authenticator と言ったりもしてる? (明示的にアプリを表す場合は 「Authenticator アプリ」 と呼ぶのが良さそう。) - クライアントであり、かつ Authenticator であるというようなアプリも存在しうる。
- システム上で有効な authenticator (
Authenticator とクライアントの関係
アカウントマネージャを扱う処理を大別すると、authenticator とクライアントに分かれます。
- Authenticator (や、それに関連する処理) : オンラインサービスのアカウント取得や認証処理を行います。 典型的には、ユーザーに対してログイン画面を表示してユーザー名とパスワードを入力させ、それらのアカウント情報を使ってオンラインサービスから認証情報を取得して、アカウントマネージャに渡します。 普通はそのオンラインサービスの提供者がアプリの中に実装します。
- Authenticator のメソッドはアカウントマネージャから呼ばれます。
- クライアント : アカウントマネージャを通じて、オンラインサービスの認証情報 (アクセストークンなど) を取得し、それを使ってオンラインサービスにリクエストを投げる、というような処理です。
クライアントが AccountManager
のクライアント向けのメソッドを呼ぶと、(一部のメソッドは) 対応する Authenticator のメソッドを呼びます。 そして、典型的には Authenticator のメソッドは AccountManager
の Authenticator 用のメソッドを呼びます。 クライアントも Authenticator も AccountManager
のメソッドを呼ぶという点で混乱しやすいのですが、AccountManager
のメソッドをクライアント用メソッド群と Authenticator 用メソッド群に分けると、理解しやすいと思います。
自社サービスクライアントと他社サービスクライアントについて公式ドキュメント上での区別はありませんが、こういう分け方で考えると理解しやすいと思うので、本ページではこのように表記します。 ちなみに厳密な区別としては、「扱うアカウント種別の authenticator アプリと同じシグネチャを持つアプリ」 が自社サービスクライアント、「異なるシグネチャを持つアプリ」 が他社サービスクライアントです。
AccountManager
のメソッド一覧
アカウントマネージャについて理解するには AccountManager
クラスに生えている全てのメソッドを把握すればいいのですが、ドキュメントそのままだと理解しづらいので、整理して一覧できるようにしておきます。 これらのメソッド一覧に目を通すと、アカウントマネージャについての理解が深まるはずです。
API level 25 のドキュメントを参照しています。
クライアント向け
他社サービスのクライアントが使えるメソッド
Authenticator 一覧を取得したり、アカウント一覧を取得したり (パーミッションがあれば他社サービスのアカウントも全て)、指定のアカウントの認証トークンを取得したり、指定の認証トークンが無効になっていることをアカウントマネージャに伝えたり、ユーザーが指定のアカウントのパスワードを知っていることを確認するよう依頼したり、といったことができます。
getAuthenticatorTypes()
- システムに登録されている Authenticator 一覧を返す。
- パーミッション不要。
addOnAccountsUpdatedListener
- アカウントマネージャが管理するアカウントの変化 (追加や削除など) を検知するリスナ (
OnAccountsUpdateListener
) を追加する。 getAccounts
メソッドで取得可能なアカウントの変化のみ検知できる。 (典型的には、任意のアカウントの変化を検知するにはGET_ACCOUNTS
パーミッションが必要。)
- アカウントマネージャが管理するアカウントの変化 (追加や削除など) を検知するリスナ (
removeOnAccountsUpdatedListener(OnAccountsUpdateListener)
- リスナの削除。
addAccount
- アカウント取得系
confirmCredentials
updateCredentials(Account, String, Bundle, Activity, AccountManagerCallback<Bundle>, Handler)
getPreviousName
- 指定のアカウントの前の名前を返す。
LOGIN_ACCOUNTS_CHANGED_ACTION
ブロードキャストを受け取ったときに、アカウント名が変更されているかどうか検知できるようにするためのメソッドらしい。
- Auth token 取得系 : AccountManager がキャッシュしていたらそれを返し、なければ対応する Authenticator が認証トークンを取得する。
getAuthToken(Account, String, Bundle, boolean, AccountManagerCallback<Bundle>, Handler)
- バックグラウンドの処理向け。
- 指定のアカウントの指定のトークン種別の認証トークンを取得する。 アカウントマネージャがキャッシュしている場合はそれが返される。 キャッシュされていない場合は authenticator がリクエストを処理する。
- Authenticator は、パスワードが使えるのであればそれでサーバーに問い合わせを行う。 それが無理ならユーザーにログイン画面を表示して、ユーザー入力によって認証トークンを取得する。
notifyAuthFailure
に真を渡したならば、そのインテントを開始するステータスバーの通知も表示される。- その場合 (ログインする必要がある場合? それともステータスバーの通知が表示される場合?) には、ユーザーが対応するまで何時間も、何日も、あるいは永遠に待つことになる可能性がある。
notifyAuthFailure
に偽を渡した場合は、アプリケーションがIntent
を開始する責任がある。- API level 22 以下では
USE_CREDENTIALS
パーミッションが必要。
getAuthToken(Account, String, boolean, AccountManagerCallback<Bundle>, Handler)
- API level 14 で Deprecated になってるので
Bundle
パラメータ有り版を呼ぶこと。
- API level 14 で Deprecated になってるので
getAuthToken(Account, String, Bundle, Activity, AccountManagerCallback<Bundle>, Handler)
blockingGetAuthToken
getAuthTokenByFeatures(String, String, String[], Activity, Bundle, Bundle, AccountManagerCallback<Bundle>, Handler)
invalidateAuthToken
hasFeatures
自社アプリ (同じシグネチャを持つアプリ) のみ
removeAccount(Account, Activity, AccountManagerCallback<Bundle>, Handler)
removeAccount(Account, AccountManagerCallback<Boolean>, Handler)
- 上に同じ。 Deprecated。
renameAccount(Account, String, AccountManagerCallback<Account>, Handler)
clearPassword
- アカウントマネージャが保持しているパスワードを削除する。 「ログアウト」 ボタンの処理などで使われることを想定しているらしい。
setPassword
メソッドでも同じことができるけどこっちの方が必要な権限は少ないっぽい。- アカウントの Authenticator と同じシグネチャが必要。
editProperties
Authenticator (または、それに関連する処理) 向け
addAccountExplicitly(Account, String, Bundle)
- アカウントをアカウントマネージャに追加する。
- Authenticator に関連するサインアップ処理向け。
addAccount
メソッドなどのシステムがアカウント追加を検知できるメソッド経由で呼ばれたわけじゃない場合は、自前でnotifyAccountAuthenticated
メソッドを呼ぶべき。
removeAccountExplicitly(Account)
notifyAccountAuthenticated(Account)
- アカウントが認証されたことをシステムに伝える。
- このイベント情報が他のアプリで使われたりするっぽい? (未調査。)
- 呼び出し側はアカウントの Authenticator と同じシグネチャを持つ必要がある。
getPassword
setPassword(Account, String)
getUserData
setUserData(Account, String, String)
peekAuthToken(Account, String)
setAuthToken(Account, String, String)
その他
get(Context)
: インスタンス取得。getAccountsByTypeForPackage
: システム用。newChooseAccountIntent(Account, List<Account>, String[], String, String, String[], Bundle)
- アカウント選択画面を表示するための
Intent
を生成する。
- アカウント選択画面を表示するための
newChooseAccountIntent(Account, ArrayList<Account>, String[], boolean, String, String, String[], Bundle)
- 上の Deprecated 版。
関連ページ
- 『Android アプリのセキュア設計・セキュアコーディングガイド』2016年9月1日版 (JSSEC) : セキュリティ周りのことはこれが一番良いはず。 説明もわかりやすい。
- AccountManagerを利用する : 利用側についてわかりやすくまとまっている。
- AccountManagerでアカウントを管理する : 提供側の実装方法がわかりやすくまとまっている。
- Android におけるアカウント管理 : 提供側の実装方法がわかりやすくまとまってる。
- authenticator.xml の accountType の文字列を strings.xml に入れてはいけない : 厳しい。
- Differences of AccountManager from API 22 to 24 : Kyobashi.dex #4 における shogo さんの発表資料。 最近の Android のバージョンごとの差異の説明。 複数アプリに同じ account type の authenticator を持たせるとどうなるのか、といった話も出てきて非常に参考になる。
読んだ : Kotlin スタートブック ― 新しい Android プログラミング / 長澤 太郎 著
Kotlin エバンジェリスト (JetBrains 黙認) であり、日本 Kotlin ユーザグループ代表であるたろーさん (長澤 太郎) によって書かれた書籍 『Kotlin スタートブック ― 新しい Android プログラミング』 (赤べこ本) を読みました!!
Kotlinスタートブック -新しいAndroidプログラミング
- 作者: 長澤太郎
- 出版社/メーカー: リックテレコム
- 発売日: 2016/07/13
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (1件) を見る
本書を読む前から、公式のリファレンスやチュートリアルなどの気になる箇所を見てはいて Kotlin についてはなんとなく理解はしていたのですが、ところどころ知識が欠けている部分もあったので、本書によってそういった知識の欠落を埋めることができました。
どんな本か?
内容については著者のたろーさんが紹介されています。
導入としてまず 1 部があり、2 部で Kotlin の文法や機能の詳細が解説されます。 3 部にて、Android アプリ開発で Kotlin をどのように活用できるかが説明されます。 対象読者は 「Java および Android 開発経験者」 と書かれていますが、2 部までなら Android アプリ開発については知らなくても問題なく読み進められます。 「Android アプリ開発で Kotlin を使うために読む本」 というわけではなく、「Kotlin を使い始めるときに読む本」 かつ 「Android 開発に Kotlin を活用するためにどうすればいいかが書かれている本」 という感じです。
全体としては易し目の説明でスクリーンショットも多用されているのでプログラム開発の初心者でも読みやすい本だと思います。 一方で、説明する内容についてきちんと節が分かれていて飛ばし気味に読むこともやりやすいので、ソフトウェア開発についてある程度経験がある人が Kotlin の導入のために読むというのにも適しています。
感想
Kotlin を Java の代わりとして使い始めるのは結構簡単で、いくつかある Java との違い (各種文法の違いや 「==
演算子は同一性検査ではない」 みたいな違い) をおさえさえすれば導入できます。 逆に導入するのが簡単なせいで、「ちゃんと Kotlin 特有の機能や文法を学ぶ」 機会を設けず、必要に応じて公式リファレンスを参照している、という人も多いのではないでしょうか。 私もまさにそんな感じだったので、今回本書を読んで Kotlin 特有の機能、文法を学べたのは非常に良かったです。
内容的には深く突っ込んでいくという感じではないので、本書を読みつつ気になったところは公式リファレンスを参照する、みたいに読み進めていくといい気がします。 公式リファレンスとは違った視点での説明されている項目もあったりするので、両方参照することで理解が深まったりもすると思います。 公式リファレンスには書かれていない 『!!
演算子の代わりに requireNotNull
メソッドを使うと良い』 というような記述があるのも本書の良いところですね。
まさに 「これから Kotlin を使っていこうと思っている人のための Kotlin 入門本」 として、以下のような人にオススメできる書籍でした。
- Kotlin を使ってみてるけどまだ Kotlin 全体についてちゃんとは学んでいない。
- まだ Kotlin を使ってみてないけどこれから使ってみようかと思っている。
第 3 部の内容 (Kotlin で Android アプリ開発) について、ほとんど知っているものだったので自分にとってはあまり意味はなかったのですが、Kotlin を使った Android アプリ開発がどんな感じか全然知らない人にとってはそれらも役立つと思います。
読書メモ
自分にとって気になった箇所と、それに関連する公式リファレンスへのリンク。
require
メソッド で満たすべき条件を記述できる。 (P31)- string template と raw string 50
List
型の値がイミューダブルとはかぎらない。List
型のサブクラスにImmutableList
があるので、ImmutableList
オブジェクトがList
型として渡される可能性がある。 (P54)List
以外のコレクションクラスも同様。
Range
のin
演算子で、値が範囲に含まれているかどうか調べられる。 (P55)- イテレータに何らかのインターフェイスを実装する必要はない。 規定のメソッドさえオペレータとして定義されていれば良い。 (P63)
- 可変長引数は
vararg
修飾子で宣言。 配列を渡すときには spread 演算子 (*
; アスタリスク) で展開。 (P73) - 末尾再起呼び出し最適化に
tailrec
修飾子。 (P76) - ローカル関数、関数定義の中に関数を定義できる。 (P77)
- インライン関数の引数としてインライン関数外で呼ばれうるラムダを受け取る場合は
noinline
修飾子を付ける。 (P94)- 修飾子を何もつけないと、インライン関数の実行コンテキストでの実行しかできない。 インライン関数の引数のラムダもインライン展開されるため。
- スタックトレースの内容に影響を受けるような関数も
noinline
にすることを検討すると良いとのこと。 - 参考 : Inline Functions - Kotlin Programming Language
- インライン関数の引数として別の実行コンテキストでインライン化されて実行されるラムダを受け取る場合は
crossinline
修飾子を付ける。 (P94)- これにより、非ローカルリターンが使えないことを呼び出し側に伝える。
- 参考 : Inline Functions - Kotlin Programming Language
- インライン展開されるラムダ式では非ローカルリターンが使える。 (P95)
- ラムダ式から脱出する場合はラベルへのリターン。 (P96)
- Kotlin にはラムダ式以外に無名関数もある。 ラムダと違い
return
で無名関数から脱出する。 (P97) - ラムダ式と無名関数をあわせて関数リテラルという。 (P97)
- 公開範囲は public と internal (同一モジュール内) と private と protected (Java とは違って同一パッケージからは見えない)。 (P138)
- 使用場所変位指定による型投影。 使用側で
in
またはout
修飾子を指定する。 (P163) - クラス宣言における型パラメータが共変の場合は
out
修飾子を、反変の場合はin
修飾子で宣言。 宣言場所変位指定。 (P165) - 型引数について何もわからない場合でもそのジェネリック型を使いたい場合にはスター投影。 (P167)
- インライン関数の型パラメータを具象型パラメータ (reified type parameter) にすることで実行時にその型を扱えるようになる。 (P168)
!!
演算子の代わりにrequireNotNull
メソッドを使うことで意図をメッセージで表現できる。 (P180)- 安全キャスト
as?
を使うと、キャストできないときはnull
になる。 (P183) - 参照の等価性と構造の等価性。 (P190)
- 言葉遣いが 「同一性」 と 「等価性 (同値性)」 じゃないんだなー、という部分がちょっと驚き。
- 参考 : Equality - Kotlin Programming Language
infix
キーワードのついた 1 引数のメソッドを中置表記で呼び出せる。 (P192)- 範囲を作る
..
も中置表記。 - 参考 : Functions - Kotlin Programming Language
- 範囲を作る
- 分解宣言 (destructuring declaration) には
operator
つきのcomponentN
メソッドが必要。 (P194)- データクラスは componentN も自動生成してくれる。 (P197)
- 参考 : Destructuring Declarations - Kotlin Programming Language
- 内部クラスには
inner
修飾子を付ける。 (P199) try
は式。 (P211)- レシーバ付き関数リテラルの型
A.(B)->C
は(A, B)->C
のサブタイプ。 (P214)