2024.12.19
システムの穴を運用でカバーしようとしてミス多発… バグが大量発生、決算が合わない状態から業務効率化を実現するまで
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.12.20
日本の約10倍がん患者が殺到し、病院はキャパオーバー ジャパンハートが描く医療の未来と、カンボジアに新病院を作る理由
2024.12.19
12万通りの「資格の組み合わせ」の中で厳選された60の項目 532の資格を持つ林雄次氏の新刊『資格のかけ算』の見所
2024.12.16
32歳で成績最下位から1年でトップ営業になれた理由 売るテクニックよりも大事な「あり方」
2023.03.21
民間宇宙開発で高まる「飛行機とロケットの衝突」の危機...どうやって回避する?
PR | 2024.12.20
モンスター化したExcelが、ある日突然崩壊 昭和のガス工事会社を生まれ変わらせた、起死回生のノーコード活用術
2024.12.12
会議で発言しやすくなる「心理的安全性」を高めるには ファシリテーションがうまい人の3つの条件
2024.12.18
「社長以外みんな儲かる給与設計」にした理由 経営者たちが語る、優秀な人材集め・会社を発展させるためのヒント
2024.12.17
面接で「後輩を指導できなさそう」と思われる人の伝え方 歳を重ねるほど重視される経験の「ノウハウ化」
2024.12.13
ファシリテーターは「しゃべらないほうがいい」理由 入山章栄氏が語る、心理的安全性の高い場を作るポイント
2024.12.10
メールのラリー回数でわかる「評価されない人」の特徴 職場での評価を下げる行動5選
Climbers Startup JAPAN EXPO 2024 - 秋 -
2024.11.20 - 2024.11.21
『主体的なキャリア形成』を考える~資格のかけ算について〜
2024.12.07 - 2024.12.07
Startup CTO of the year 2024
2024.11.19 - 2024.11.19
社員の力を引き出す経営戦略〜ひとり一人が自ら成長する組織づくり〜
2024.11.20 - 2024.11.20
「確率思考」で未来を見通す 事業を成功に導く意思決定 ~エビデンス・ベースド・マーケティング思考の調査分析で事業に有効な予測手法とは~
2024.11.05 - 2024.11.05