記録

主にAndroidアプリ開発に関する知見やその周辺に関わることについて記事をかいています

【Android】Gradle Kotlin DSLからGroovy DSLに戻したはなし

先日つぎのような記事を会社のブログで執筆し公開した。

inside.pixiv.blog

僕が担当しているアプリでアプリケーションレベルのモジュール分割をしているはなしを書いた。そこで、前回の記事のリンクを貼ったところ「前回の記事でGradle Kotlin DSL使ってるのに、今回の内容だとGroovy DSLになってる」っていう反応がいくつかあった。

自分で記事を書いていて、絶対そう思われるだろうなと思ってた。なので最初は、記事の中に何でそうなったのかも記載しようかなって思ったんだけど、記事の内容とずれるから書くのをやめた。

そこで、理由とか含めてまた記事にするかなって思ったけど、実はあまり深い理由もなく、ただただ文章を数行並べるだけになりそうだったので、ブログで適当に書いておこうと思った。

なぜGradle Kotlin DSLをやめたか

実際なんでGradle Kotlin DSLをやめたかというと、おもに開発速度をあげたかったというのが大きい。最初はKotlinで書けるし補完もきくし良いじゃんと思ったんだけど、慣れてくると補完なんて必要なくなる。

また、当時はAndroidStudioでGradle Kotlin DSLが扱いづらかったり、変更後にビルドとGradle Syncが必要だったりもした。さらに、多くのドキュメント等がGradle Kotlin DSL用の記述などに対応してなかったこともあり、調べる時間もかかっていた。

そういった背景もあり、普通にGroovy DSLで書いたほうが開発のスピードがでると判断し、Gradle Kotlin DSLの利用をやめた。僕が担当してるアプリは、僕がひとりで開発している点や、他にも採用や多くの仕事もこなしているため、とにかく時間のかかることはやめるという判断をとっている。

ちゃんと調べてないからわからないけど、いまはもう扱いやすくなってるかもしれない。だけど、Groovy DSLで書いてて困ることがないので、Gradle Kotlin DSLに戻すことを今は考えていない。

おしりセレブWETを2か月間使ってみた感想

おしりセレブWETって何かというと、簡単に言うと おしりを拭くようのWETティッシュ です。ウォシュレットとトイレットペーパーだけじゃ何かと不安で(あとごしごししたくない、痛いし)という理由で購入して2か月間使いました。

正直めちゃめちゃ良いです。ルーアナが優しく綺麗になっていくのが体験として素晴らしい。感覚的にトイレットペーパーの使用量も減りました。ウォシュレットの水拭くぐらいにしか使わない。

Amazonで注文するだけだけだし、去年買った買い物の中でかなり良い買い物でした。

【Android】Layout PreviewのDefault Themeを設定する

AndroidManifest.xmlでapplicationにthemeを設定しているとレイアウトプレビューのThemeにそれが反映される。

f:id:m4kvn:20210127071615p:plain

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/Theme.NavigationComponentSample">

そのため、モジュール分割等でAndroidManifest.xmlが分割されている場合などは、そちらにもthemeの設定をしないとそのモジュール内のレイアウトプレビューにthemeが適用されません。

<application android:theme="@style/Theme.NavigationComponentSample">
    <activity android:name=".HogeActivity" />
</application>

スタイルを変更してもプレビューに反映されずビルドしないと確認できなくて困っていたらこれが原因だった。

こちらを参考にしました。

stackoverflow.com

Navigation componentの暗黙的ディープリンクにはpathが必要

Navigation componentで m4kvn://main のようなディープリンクの設定をしたけど全然機能してくれないから何故なのか調べた。

調べた結果、Merged Manifestで <data android:path="/" /> が設定されるので m4kvn://mainURIには反応しないということだった。

次の記事が参考になります。

star-zero.medium.com

ナビゲーションには原則がある

Android Developersにナビゲーションの原則が記載されている。

developer.android.com

まとめると以下のようになる(細かい内容は上記を読む)

  • 最初に表示される固定の画面が必要で必ずバックスタックの最下層にある
  • アップボタンとバックボタンは同じ機能を持つがアップボタンがアプリを終了することはない
  • ディープリンクは手動で移動したのと同じバックスタックになり以前のバックスタックは破棄する

DialogFragmentでViewBindingを利用する

DialogやFragmentの layoutInflater を使ってViewBindingをinflateして、Dialogの setContentView にわたす。クリック時にDialogをdismissしたい場合などは先にDialogを作っておいて dialog.dismiss() をすれば良い。

class HogeDialogFragment : DialogFragment() {

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        val binding = FragmentHogeBinding.inflate(layoutInflater)
        binding.textView.text = getString(R.string.hello_world)

        return super.onCreateDialog(savedInstanceState).apply {
            // val binding = FragmentHogeBinding.inflate(layoutInflater)
            // binding.textView.text = getString(R.string.hello_world)
            setContentView(binding.root)
        }
    }

普段はAlertDialogにsetViewするのであまり使わないけど、リファクタリングとかに役立つかも。

MenuItemの文字色を動的に変更する

MenuItemのtitleにSpannableStringBuilderで加工したテキストを渡してあげる。なので色以外も変更できる。

val titleText = menuItem.title
val builder = SpannableStringBuilder(titleText)
val colorSpan = ForegroundColorSpan(color)
builder.setSpan(colorSpan, 0, titleText.length, SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE)
menuItem.title = builder

MenuItemの取得方法

Toolbarに直接Menuをinflateしている場合はToolbarのMenuから取得できる。

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(binding.root)
    binding.toolbar.inflateMenu(R.menu.hoge)
    val menuItem: MenuItem = binding.toolbar.menu.findItem(R.id.piyo)
}

onCreateOptionsMenuでMenuをinflateしてる場合は、onPrepareOptionsMenuを invalidateOptionsMenu() で呼び出しMenuItemを取得し処理する。

override fun onCreateOptionsMenu(menu: Menu?): Boolean {
    menuInflater.inflate(R.menu.hoge, menu)
    return true
}

override fun onPrepareOptionsMenu(menu: Menu?): Boolean {
    val menuItem: MenuItem? = menu?.findItem(R.id.piyo)
    return true
}