2024.10.10
将来は卵1パックの価格が2倍に? 多くの日本人が知らない世界の新潮流、「動物福祉」とは
Deep Dive into Slice(全1記事)
リンクをコピー
記事をブックマーク
もり氏(以下、もり):こんばんは。Slicesの内部実装を見ながら自分でこういうの作るにはどうやって作るだろう的な、ちょっと益体のない話をしようと思っています。
自己紹介させてください。森と言います。ヤフーから来ました。
ヤフーには黒帯というこういう場でお話ししたりする役割があるんですが、私はAndroid分野で黒帯をしております。そのほかヤフオクもやっております。
いきなり宣伝になってしまいますが、最近本を出しました。
ところで今我々はこちらヒカリエにいるんですけれども、なんとここに啓文堂書店があります。啓文堂書店、よろしくお願いします。
(会場笑)
では始めていきたいと思います。Slicesについてです。
まずSlicesの仕組みなんですけれども。Slicesを返すSliceProvider、我々はこれを作ります。
このSliceProviderはContentProviderを継承していて、ContentProviderなのでSlicesを表示する側はURIをもとにデータ、ここではSlicesを要求するという感じで動いています。
Slices自体がこんな感じで構造化されたフォーマットのデータになっています。
ほかのSlicesとか表示フォーマットだとかアイコンなんかが含まれています。
SliceProviderを実装するにはAndroid Studio 3.2を入れて右クリックして、NewからOther、SliceProviderを押せば終わりなんすけれども。
それだとあんまりなので少し説明を入れると、SliceProviderを継承したクラスを作ってonBindSliceメソッドの中でSlicesを作って返すという感じで作ります。
これは結局ContentProviderなのでマニフェストファイルにAuthorityとともに追加するという感じで使います。
こうして我々サードパーティーはSliceProviderを作るわけなんですが、作ったとしてどこで使ってもらえるのか? 最初はGoogle検索アプリで使用されます。
Google検索アプリでユーザーがクエリを入力するときのサジェストの中に、自分のアプリのSlicesを表示してもらえる可能性があります。
そのための方法が2通りあって、まずユーザーがアプリ名を入力したときに表示する方法。この方法は簡単で、マニフェストファイルのメインアクティビティにメタデータを追加します。
このメタデータにSlicesに対応するURIを設定して、アクティビティの中でGoogle Play ServicesとGoogle検索のパーミッションを入れれば終わりです。
でもGoogle検索アプリでアプリ名で検索するユーザーって……そんなユースケースあるかな? って感じなので,一般的な単語での検索に反応したいなっていうところです。
これのやり方なんですけれども、FirebaseAppIndexingにIndex登録するときにメタデータとしてSlicesのURIを追加する。こうするとAppIndexingが使用されるタイミングでSlicesが使われる可能性があるという感じになります。
そのあとマニフェストファイルのSliceProviderのエレメントにIndexしたURLを受け取るintent-filterを追加します。SlicesのURIではなくてIndexしたURLを設定します。
最後にSlicesプロバイダーのonMapIntentToUriというところで、AppIndexingが渡してくるディープリンクのURLをSlicesのURIに変換して返すという感じです。
以上がGoogle検索アプリで表示してもらう場合の方法です。
ところでサードパーティーは表示できないのか? というところです。Google検索アプリで表示してもらえるだけでもけっこう嬉しいんですが、サードパーティーのアプリ間で連携できればもうちょっと便利そうな感じがします。
特にヤフーにはたくさんのサービスがあって、いろんなアプリを世に出しています。これらで連携できるようになると、なんか便利そうだなって思うわけですね。ヤフオクのケースだと、例えば決済アプリでネイティブ化するということもできそうです。
こういう連携をどうすれば実現できるかなんですけども。ステップ1、待つ。
(会場笑)
というのもGoogle I/Oから帰ってきたときにGoogleの人と話してきたんですが、Slicesの表示をサードパーティーに解放するかどうかはまだ決まっていない。
今、Slice Viewerというものが公開されていて、SliceViewというSlicesを表示する用のViewもJetpackの中に入ってるんですけども。このAPIも今後どうなるかわからないということを言っていました。
じゃあ、Slicesの表示が解放されなかったらどうやってサードパーティ間連携をしていったらいいのでしょうか? 作りましょう、それっぽいのを。
というわけでSlicesが具体的にどう動いてるのかを追いかけてみたいと思います。今回はSliceViewerのソースコードをもとにSliceを要求するところからSlicesを作って返すところまで追いかけていきたいと思います。
まずSlicesを要求するところから。
SliceViewerではSliceViewのbindメソッドを呼ぶことでSlicesのリクエストが開始されます。
これは拡張関数でして、中ではSliceLiveDataというクラスを生成して値を監視しています。
SliceLiveDataではSliceManagerのインスタンスを取得して、bindSliceメソッドを呼びます。
このSliceManagerのgetInstanceメソッドはAndroid P以降かどうかで返すインスタンスが変わってきます。
Android P以降の場合SliceManagerのラッパーを返すんですが、これは新たに爆誕したSliceManagerというシステムサービスをラップしたものになります。
P未満の場合はSliceManagerCompatというクラスのインスタンスを返します。自分でシステムマネージャー作っても虚しいだけなので、今回はこっちのSliceManagerCompatを追いかけていきます。
このbindSlicesが呼ばれてたいたわけなんですが、このクラスはSliceProviderCompatのメソッドを呼ぶだけのクラスです。今、Slicesを要求している側なんですけども、実はSlicesを返す側もSliceProviderCompatを使います。
実は間にはSliceProviderCompatが入ってお互いのSliceProviderCompat同士で通信します。SliceProviderCompatではURIをチェックしたりしてbindSlicesを呼びます。
ここが終着点なんですが、ContentResolverからContentProviderClientを取得してcallメソッドを呼んで、その戻り値のバンドルからSlicesを生成して返します。
ContentProviderを使ったことがある人っていますか?
(会場挙手)
いっぱいいますよね。ContentProviderClientを使ったことがある人っていますか?
いないですね。ContentProviderClientはAPIレベル5からある古株のクラスです。ContentResolverを経由しないで直接ContentProviderとやり取りするためのものです。
ContentProviderデータを要求するときに毎回ContentResolverを使っていると、毎回URIから対応するプロバイダはどれかなって探す処理が走ります。この探す処理がなくなるのでかなり高速化します。
そのcallメソッドなんですが、リレーショナルな感じでリクエストしないときに使うようなメソッドです。引数としてメソッド名を渡します。
実際には任意のメソッドを呼ぶわけじゃなくて、対応するプロバイダーのcallメソッドが呼ばれます。呼び出されたプロバイダ側で引数として渡されるメソッド名や引数を判定して、なにかを実行して結果をBundleで返します。
ここまでがSlicesを要求するフェーズです。結局のところSliceProviderCompatのcallメソッドを呼んでいました。これに対してSlicesを返す側のアプリは何をしているのかを追いかけてみたいと思います。
callメソッドはこうなっています。handleBindSliceというメソッド内でSlicesを作って、Bundleに変換して、さらにBundleに積んで返しています。
Slicesを作っているhandleBindSliceを見てみると、こんな感じです。
なんやかんやでonBindSliceStrictを呼びます。そのonBindSliceStrictがSlicesを生成するときの終着点になります。
2秒でANRが発生するように設定して、ディスクI/Oなど重たい処理をしたらクラッシュするようにしたうえで、SliceProviderのonBindSliceを呼びます。
SliceProviderのonBindSliceは最初に説明したとおり、自分でオーバーライドして実装するものです。
なので大切なのはSlicesが要求されたときに自分で返す場合には、同期的なディスクI/Oだとかネットワークをしないで、2秒以内に返さないといけません。
すぐに返せないのであれば一旦「読み込み中」とでも返しておいて非同期的にデータを取得してnotifyChangeを呼ぶようにしましょう。
こんな感じでSlicesを返しました。そのSlicesはどのように表示されているかですが、もともとライブデータ内で要求されていたので、まずはpostValueでライブデータを更新します。
それを受け取って、SliceView内のプロパティを更新します。
プロパティアクセスっぽく見えるんですが、実際にはSliceViewのsetSliceが呼ばれていて。メソッド内のreinflateというメソッドを呼びます。
この中でSlicesの値、プロパティを読み取りながらViewを生成していくんですが、そこは単純なのでこれ以降は省略します。
長々とSlicesの内部実装を見てきたわけですが、こうしたSlicesめいたものを自分で作るんだったらどうするのか、ということでまとめます。
まずBundleと相互変換できるクラスを作ります。次にContentProviderClientを使ってBundleをやり取りします。最後にBundleから元のクラスに戻して、その値を参照しながらViewを生成するロジックを書く。ここだけ見ると簡単そうに見えまが、ひたすらめんどくさい感じになります。
全体のまとめとしては、Slicesは古典的なAPIをうまく使って作られています。まずはGoogle検索アプリで使われます。サードパーティー間の連携に使用できるかはまだ不透明なようです。
でも似たようなことは作れるようになりましたね。ということで、ご静聴ありがとうございました。
(会場拍手)
関連タグ:
2024.11.13
週3日働いて年収2,000万稼ぐ元印刷屋のおじさん 好きなことだけして楽に稼ぐ3つのパターン
2024.11.11
自分の「本質的な才能」が見つかる一番簡単な質問 他者から「すごい」と思われても意外と気づかないのが才能
2024.11.13
“退職者が出た時の会社の対応”を従業員は見ている 離職防止策の前に見つめ直したい、部下との向き合い方
2024.11.12
自分の人生にプラスに働く「イライラ」は才能 自分の強みや才能につながる“良いイライラ”を見分けるポイント
2023.03.21
民間宇宙開発で高まる「飛行機とロケットの衝突」の危機...どうやって回避する?
2024.11.11
気づいたら借金、倒産して身ぐるみを剥がされる経営者 起業に「立派な動機」を求められる恐ろしさ
2024.11.11
「退職代行」を使われた管理職の本音と葛藤 メディアで話題、利用者が右肩上がり…企業が置かれている現状とは
2024.11.18
20名の会社でGoogleの採用を真似するのはもったいない 人手不足の時代における「脱能力主義」のヒント
2024.11.12
先週まで元気だったのに、突然辞める「びっくり退職」 退職代行サービスの影響も?上司と部下の“すれ違い”が起きる原因
2024.11.14
よってたかってハイリスクのビジネスモデルに仕立て上げるステークホルダー 「社会的理由」が求められる時代の起業戦略
2024.11.13
週3日働いて年収2,000万稼ぐ元印刷屋のおじさん 好きなことだけして楽に稼ぐ3つのパターン
2024.11.11
自分の「本質的な才能」が見つかる一番簡単な質問 他者から「すごい」と思われても意外と気づかないのが才能
2024.11.13
“退職者が出た時の会社の対応”を従業員は見ている 離職防止策の前に見つめ直したい、部下との向き合い方
2024.11.12
自分の人生にプラスに働く「イライラ」は才能 自分の強みや才能につながる“良いイライラ”を見分けるポイント
2023.03.21
民間宇宙開発で高まる「飛行機とロケットの衝突」の危機...どうやって回避する?
2024.11.11
気づいたら借金、倒産して身ぐるみを剥がされる経営者 起業に「立派な動機」を求められる恐ろしさ
2024.11.11
「退職代行」を使われた管理職の本音と葛藤 メディアで話題、利用者が右肩上がり…企業が置かれている現状とは
2024.11.18
20名の会社でGoogleの採用を真似するのはもったいない 人手不足の時代における「脱能力主義」のヒント
2024.11.12
先週まで元気だったのに、突然辞める「びっくり退職」 退職代行サービスの影響も?上司と部下の“すれ違い”が起きる原因
2024.11.14
よってたかってハイリスクのビジネスモデルに仕立て上げるステークホルダー 「社会的理由」が求められる時代の起業戦略