heihei blog

Blog icon by Unsplash https://unsplash.com/@virussinside

Notes - An Opinionated Guide to Dependency Injection on Android (Android Dev Summit '19)

f:id:shaunkawano:20191026000524p:plain

※Notes記事では、英語のセッション動画やポッドキャストの内容を(雑に)英語でメモに書き残すことを行っています。本記事は、あくまで動画を見ながら、参考程度に読んでいただくことを想定しています。Notes記事には雑メモ程度のものだったり、書き起こしのようなものもあります。これから実際の動画を見る際には、本記事の内容が少しでもお役に立てば幸いです。(内容において不備、誤字脱字等ありましたら気軽にご連絡いただけると嬉しいです!m(__)m)

本記事は、An Opinionated Guide to Dependency Injection on Android (Android Dev Summit '19)の記事です。

Dependency Injection

Car needs engine to work = Engine is a dependency of car = Car depends on engine

  • With dependency injection, those dependencies are provided to a class instead of the class creating them itself.
  • You should always apply dependency injection principle to your app
    • sets fundamentals of testable and scalable app
    • Reusability of code
    • Good balance of loosely-coupled dependencies
    • Ease of refactoring

Dagger

Recommendation

  • Does not use reflection
  • Recommended tool
  • Dagger is used on Gmail, Google Photos, Youtube

Steep learning curve..

  • Started providing a common guidance, which is a set of documentation from the basics to the complex topics
  • Codelab for Dagger

dagger-android?

  • Google is stopping its development
  • Adding no more feature
  • Trying to reduce the amount of code you have to write

Better Dagger code with Kotlin

Dagger + Kotlin = ♡

  • No more JvmStatic
  • Qualifier Annotations
  • Kotlin wildcards

Future versions

  • Some more improvements are coming
    • e.g. for companion object

Simple DI Approach in Android

  • still under construction
  • how it will look like
    • Focus on binding declarations

Bindings

The time you spend working on DI should really go to what you keep working on to scale your app.

Injection

  • Not just using @Inject, you should do some more extra work, for example to set up app component
  • Add @EntryPoint for Android component class
    • Tells that you want this Android component to be a entry point into the graph
  • Support and provide easy hookups for lifecycle related components like ViewModel

Components

  • Predefined Components
    • SingletonComponent
    • ActivityComponent
    • ServiceComponent
    • FragmentComponent

Jetpack DI Initiative

  • Integrated with Dagger
  • Jetpack Extensions
    • Fragments
    • ViewModel
    • WorkManager

Takeaways

  • Use DI
  • Use Dagger
  • Check out the guidance
  • We're improving DI in Android, so stay tuned!

所感・まとめ・個人的に印象に残ったことなど

  • 共通ガイドを作った
    • 基礎的なところから複雑なトピックまで扱ってるからみてほしい
  • Kotlinとの相性をもっと良くしていきたい
    • 今後のリリースでCompanion Objectに関連したリリースなども行う予定?
  • dagger-androidの開発今はやめてる
    • もっとよくできると思っているから
  • セットアップコスト、学習コストを下げていきたい
    • ActivityなどのAndroidのEntryPointとなるFrameworkに対して@EntryPointを付与することで、そのクラスを起因にグラフを作る、つまり今までのonCreate内でのComponentクラスのセットアップまわりの処理などを自動でやってくれるような仕組みとか
    • 他のLifecycleに関するAACのクラスなどをより簡単にDIできるようにする仕組みとか
    • 独自に定義しなくてもある程度一般的なComponentを用意しておくとか

DIはいいぞ、Daggerもいいぞ、どんどん良くしていくからぜひ使ってくれよな!感が伝わりました

以上です!

Notes - Fragments: Past, Present, and Future (Android Dev Summit '19)

f:id:shaunkawano:20191025202341p:plain

※Notes記事では、英語のセッション動画やポッドキャストの内容を(雑に)英語でメモに書き残すことを行っています。本記事は、あくまで動画を見ながら、参考程度に読んでいただくことを想定しています。Notes記事には雑メモ程度のものだったり、書き起こしのようなものもあります。これから実際の動画を見る際には、本記事の内容が少しでもお役に立てば幸いです。(内容において不備、誤字脱字等ありましたら気軽にご連絡いただけると嬉しいです!m(__)m)

本記事は、Fragments: Past, Present, and Future (Android Dev Summit '19)の記事です。

Fragment Past

Android API 11

Fragments were really designed from the beginning to the kind of Micro Activities.

  • First step to move things from fat Activities to smaller fragments
    • this also meant that Fragments inherited a lot of APIs that Activity had
      • ActionBar Menus
    • this also meant that there became a lot custom hooks
      • Things activity got received needed to be received on Fragments as well
        • onActivityResult
        • Permissions
        • Multi Window
        • Picture in Picture

Present

  • Restructuring the goal of Fragments
    • focused API surfaces
      • core, simple, predictable no-surprise apis
      • without breaking changes
        • deprecating old apis with new better APIs
  • Providing testable APIs
    • Fragment testing artifact
      • Fragment Scenario
        • moveToState(), recreate()
        • launchFragmentInContainer
      • Working together with AndroidX team
  • Instantiating Fragments
    • Recreation after config change
    • FragmentTransaction add / replace
    • FragmentScenario
    • FragmentFactory
      • Support constructor injection
      • No requirement for no arg constructor
  • One container for Fragments
    • FragmentContainerView
      • Use it instead of FrameLayout
      • Replace the tag
      • does use FragmentManager under the hood
        • Fix issue of replacing fragment later
      • Fix the Z-ordering animation issue
  • System back
    • OnBackPressedDispatcher
      • Arch Components
  • ViewModels
    • by viewModels()
    • by navGraphViewModels(R.id.main)
    • by activityViewModels()
  • Lifecycle
    • ?

Future

  • Subject to change

  • multiple back stack

    • single stack: existing legacy on Android
    • allow saving and restoring a whole stack of fragments without losing state
    • Bottom nav made easy
  • returning results
    • how do I talk between fragments?
    • fragment API right now is not great
    • create a better API for startActivityForResult() and for passing a result to another Fragment
      • building and hopefully sharing in a few months
  • lifecycle
    • fragment has two lifecycles
      • fragment itself
      • fragment's view has totally different lifecycle
        • view may get destroyed, but fragment still exists
    • what if, these two lifecycles are the same?
      • bringing these things together, we can solve a lot of complexity. => maybe this kind of opt-in APIs will be available in FragmentActivity level.

所感・まとめ・個人的に印象に残ったことなど

  • FragmentFactory、FragmentScenarioを使うことでFragmentの生成やテストがしやすくなったよ
    • Factoryを使うことでconstructor injectionも可能になったよ
  • FragmentをViewに内包する場合にはFragmentContainerViewを使う(FrameLayoutは使わない)
    • 内部ではFragmentManagerが利用されている
  • Googleとしては、将来的にももっともっと良くしていきたいFragment APIが沢山ある
    • 複数のバックスタックを可能にする(BottomNavの切替時とかの管理を簡単にしたい)
    • Fragment-Fragment間の値の受け渡しとかをより簡単にできたら(FragmnetActivityあたりへのAPI変更が数ヶ月以内にあるかも?)
    • Fragment自体のLifecycleとViewLifecycleを1つにできるとしたら...???

FramgentのAPIはより使いやすく、直感的なものになっていきそうですね。

以上です!

2019年9月を振り返る

9月を振り返ります。今年は残り24%くらいらしい。

入籍した

秋分の日に入籍をしました。同棲をはじめて半年以上だったこともあり、特に入籍後になにか変わった!ということはないですが、これからも二人で穏やかに、楽しく暮らしたいと思っています。

指輪は鎌倉彫金工房というところで、自分たちで叩いたりして形作りしました。

f:id:shaunkawano:20191005163541p:plain

↑これがこうなりました↓

f:id:shaunkawano:20191005164739p:plain

Bit Valley 2019に参加した

f:id:shaunkawano:20191005163549p:plain

bit-valley.jp

「ITトップが考えるモノづくり対談」の回が一番聞いてて楽しかった。

以下はメモしてたところから特に印象的だったことの抜粋

  • 一度合理的かと思われることに対して、再考するようにしている
    • 「無邪気に言うと」、「極論すると」という言い方で別の視点から考えるようにしていく
    • ユーザーニーズがすべて。テクノロジードリブンとか、レベニュードリブンではまったくない
    • ユーザーが純粋に「おっ、すげっ」って体験して思ってくれるかどうか

技術書典に参加した

f:id:shaunkawano:20191005163555p:plain

今まで2回、サークルとして、本を出す側として参加したことがあったのですが、今回は見て回ったり買う専で参加しました。 列がすごくて断念しそうになったけど耐えてなんとか戦利品ゲットした。 奥さんも初めて参加だったけど、興味深いものがいっぱいあってお祭りみたいで楽しかったようで、一緒にいけてよかった。

さらりとですが、以上です。

Notes - Firebase offline: What works, what doesn't, and what you need to know (Firebase Summit 2019)

f:id:shaunkawano:20191005165929p:plain

※Notes記事では、英語のセッション動画やポッドキャストの内容を(雑に)英語でメモに書き残すことを行っています。本記事は、あくまで動画を見ながら、参考程度に読んでいただくことを想定しています。Notes記事には雑メモ程度のものだったり、書き起こしのようなものもあります。これから実際の動画を見る際には、本記事の内容が少しでもお役に立てば幸いです。(内容において不備、誤字脱字等ありましたら気軽にご連絡いただけると嬉しいです!m(__)m)

本記事は、Firebase offline: What works, what doesn't, and what you need to know (Firebase Summit 2019)の記事です。

Should we care about offline anyway?

  • Yes! Users may..

    • be in crowded place
    • go underground
  • Firebase is not an offline-first platform, but offline-tolerant

What works

  • It (mostly) works
    • Caching things locally
    • Exponential back-off and retry

Firebase Auth

  • you only have the access to the user object
  • you can't login

Gotchas

  • Login
  • Auth Persistence
    • Tells how long you stay logged in
    • Trade-off between offline-experience and security

Cloud Firestore

How large is that cache, anyway?

  • For mobile - 100MB
  • For web - 40MB
  • on-device cache is not indexed right now
    • unpack and scan every document you are searching
    • if your cache is too big or too many writes this can be quite slowly
  • Maybe not pre-loading your cache too much is better than overloading cache data
  • Adjust your cache size by configuring Firestore

Cloud Storage

  • you can save large object to the cloud
  • specifying a reference like a path to upload and download the content

All The Measurement Libraries

  • On Android, all this uploading is done by Google Play Services
    • That is why if your app were crashed on Android, you can see that crashed data and upload it for you
    • if offline, exponential back-off retry
  • Performance Monitoring
    • 10MB of data, shared across all apps (Android)
    • 10MB of data, per app (iOS)
    • Oldest data usually gets eliminated
  • Analytics
    • About 100,000 events
    • Most recent data gets eliminated
  • Crashlytics
    • 9 crashes(up to 150k each)

Conclusion

  • If you're offline, things mostly just work
  • Designed for occasional offline moments, but not offline-first
    • if you need complete offline experience, maybe not the right tool
  • Measurement tools don't trust data that too old
    • Mostly 72 hours old?

所感・まとめ・個人的に印象に残ったことなど

  • Androidでは、Firebase AnalyticsやFirebase CrashlyticsはGoogle Play Services経由でログを送信している
    • そのため、アプリのタスクがキルされている状態でも動作する
  • Firebaseはオフラインファーストのサービスではないが、通常利用によるオフライン状態(地下鉄や混雑時)などには想定されており、2つの方法を用いてオフライン対応をしている
    • Local cache
    • Exponential backoff and retry
  • オフライン時にもオンラインと同等のサービス提供が必須なアプリには適切なツールではないかもしれない

以上です!

2019年8月を振り返る

今年、残り30%切りました〜。8月をさっくり、写真をいくつかピックアップして振り返ります。

f:id:shaunkawano:20190914160015p:plain

箱根旅行にいき、小田原の花火大会にいきました。 Pixelで撮影した写真です。綺麗でした。

f:id:shaunkawano:20190914160022p:plain

台風が近づいており、出発できるかわからなかったときの一枚。10:05の熊本行きの飛行機、無事に乗れました。運を使い果たした感がありました。

f:id:shaunkawano:20190914160030p:plain

買ってしまいました。もふもふです。便利です。Maxも一つ買って使っていますが、これ単体だけでも買う価値あるかもです。Yogiboは長時間座り続けると腰悪くしそう感を感じたので、用法用量を守って正しく使っていきましょう。

f:id:shaunkawano:20190914160038p:plain

リトルボーイというカレー屋さんにランチに行ってきました。量が尋常じゃないです。ちなみに写真のカレールーの下には、カツがゴロゴロいます。夜ご飯はいらなかったです。一度行ってみたかった場所。行けてよかった。

f:id:shaunkawano:20190914160044p:plain

天気の子、聖地巡礼行ってきました!懐かしい。

他にも色々あった気がしなくもないですが、たまにはこれでもかってくらいゆるいのも良いでしょうということで、以上です!

8月もお疲れさまでした!

2019年7月を振り返る

8月入ってから少し立ちましたが、7月を振り返ります。

Battle Conference U30に参加した

Battle Conference U30とは、というと下記です(公式サイトより抜粋)

「Battle Conference Under30」(BCU30)は、Under30エンジニアによるUnder30エンジニアのための参加型技術カンファレンスです。 単に若手エンジニアが技術的知見を発表するだけではありません。 登壇者と直接議論できるブース、誰でも参加できるプログラミングコンテスト、デモ展示やポスター展示など、参加者同士のコミュニケーションを促進する様々なコンテンツを用意しています。 それらを通して、参加者全員が、所属を超えて切磋琢磨し互いに刺激を受け合い、エンジニアとしてより一層成長するきっかけをつかむことを期待しています。

bcu30.jp

数年前から、毎年開催されているイベントです。

自分は初年度のイベントで運営のお手伝いを少していて、今年は運営メンバーとかではなく、弊社ブースでわちゃわちゃしていただけでした。発表もいくつか見に行きました。

小学生の登壇者の方とかもいたりして、刺激的でした。(そして皆様発表がうまい。)

正確ではないですがきっと来年もある?と思います。今気になった方で、来年時点でも参加対象の方はぜひ足を運んでみてはいかがでしょうか。

運営メンバーの皆様おつかれさまでした!!

Matching Dev Meetup#4に参加した

matching-dev-group.connpass.com

株式会社イグニスさんが会場提供で、「エンジニアリング」がテーマで、エンジニアだけではなく様々な職種の方の発表を聞くことができました。 開発プロセスの話やコーディング以外のエンジニアリングの話などもあり、エンジニアが中心の勉強会とはまた一風違った勉強会でした。

その他

福岡観光した

f:id:shaunkawano:20190721125732p:plain

大濠公園 浮見堂

美味しいものを食べたり、観光地(福岡タワー、太宰府天満宮など)や公園、神社などを歩き回ったりしていました。

f:id:shaunkawano:20190721125735p:plain

太宰府天満宮

食べては歩いてを繰り返して、満足な旅行でした。

f:id:shaunkawano:20190721125737p:plain

住吉公園

映画「天気の子」を観た

www.tenkinoko.com

観た方、ぜひ語りましょう!

7月もお疲れさまでした!

Android TransitionにListenerを追加する

業務で少し調べたことのメモ程度に。

AndroidでViewをアニメーションさせたいときの実装方法の一つとして、Transitionがあります。

Transition

Transitionの概要については、公式ドキュメント、もしくはyarakiさんによる下記のスライドが参考になります。

yaraki.github.io

Transitionは、アニメーションの前後のViewの状態を保存、比較をして、それに応じたAnimatorを生成し実行してくれる便利なAPIです。

例えば下記のようなコードを実行すると、binding.target Viewの表示・非表示がフェードしながら切り替わります。

TransitionManager.beginDelayedTransition(binding.root) // rootとなるViewGroupを指定
binding.target.isVisible = !binding.target.isVisible // アニメーションしたいViewの描画状態を更新

beginDelayedTransition関数は魔法のような関数となっており、これを実行後にViewの表示切り替えを行うことで、よしなにアニメーションをしてくれます。

上記の例では、内部でデフォルトとして設定されているTransitionクラスを利用して動きのアニメーションを実現します。もちろんデフォルト以外の動きを実現するために、自分で独自のTransitionクラスを定義し渡すこともできます。

val myTransition = MyTransition()
TransitionManager.beginDelayedTransition(binding.root, myTransition) // 第2引数にTransitionを渡す

Listenerを追加する

よくあるパターンとして、アニメーションの終了後に何らかの処理を実行したい場合があります。

Transitionが終了したタイミングでよしなに処理を行いたい場合には、TransitionクラスのaddListener関数を使って、Listenerを追加します。

以下はTransitionクラスのaddListener関数の内部実装です。

/**
 * Adds a listener to the set of listeners that are sent events through the
 * life of an animation, such as start, repeat, and end.
 *
 * @param listener the listener to be added to the current set of listeners
 *                 for this animation.
 * @return This transition object.
 */
 @NonNull
 public Transition addListener(@NonNull TransitionListener listener) {
   if (mListeners == null) {
     mListeners = new ArrayList<>();
   }
   mListeners.add(listener);
   return this;
 }

カスタムTransitionを定義している場合はTransition初期化時にaddListener関数を呼び出すことで問題なくListenerを追加できます。

val myTransition = MyTransition().addListener(object : Transition.TransitionListener() {
  ... // 関数をoverride
})
TransitionManager.beginDelayedTransition(binding.root, myTransition)

では、カスタムTransitionを定義していない場合(=beginDelayedTransition関数の引数にTransitionクラスを渡さない場合)はどうすればいいのでしょうか?

そのような場合には、Transitionクラスが内部で保持している、デフォルトのTransitionクラスを初期化し、このクラスにListenerを追加できます。

デフォルトのTransitionクラスというのは、AutoTransitionというクラスです。内部実装を読むと、TransitionManagerクラスに、private staticフィールドとして定義されていることがわかります。

public class TransitionManager {
  ...
  private static Transition sDefaultTransition = new AutoTransition();

なのでこのAutoTransitionクラスを初期化して利用をすれば、問題ないです。

val transition = AutoTransition().addListener(...)
TransitionManager.beginDelayedTransition(binding.root, transition)

Tips

addListener関数には素直にTransitionListenerクラス自体を渡すこともできますが、代わりにこのListenerクラスを実装したTransitionListenerAdapterというクラスを渡すこともできます。AdapterクラスはAndroidAPIにあるinterfaceクラスをただoverrideしただけ(独自の処理はない)のclassです。TransitionListener以外のListenerなどに対しても定義されていることがあります。

Adapterクラスがintefaceに定義されている関数をすべて空で実装しているため、このAdapterクラスを代わりに利用することで、Listenerに定義されている関数の中で、開発者がoverrideしたい関数のみをAdapterクラスを介してoverrideして利用することができます。

最終的には以下のようなコードとなりました。

val transition = AutoTransition()
    .addListener(object : TransitionListenerAdapter() {
      override fun onTransitionEnd(transition: Transition) {
        // do something
      }
    })
TransitionManager.beginDelayedTransition(binding.root, transition)
binding.target.isVisible = !binding.target.isVisible

まとめ

  • AndroidでViewのアニメーションを行う際にはTransition APIも選択肢の一つ
  • Transition APIを使ったアニメーションで、所定のタイミングで処理を実行したい場合にはTransitionクラスのaddListener関数を利用する
  • デフォルトで用意されているTransitionクラスはAutoTransition
  • TransitionListener interfaceにはTransitionListenerAdapterクラスが用意されている