KITCHEN DRINKER

主にAndroid開発メモとか

Kotlinのスコープ関数を使い分けたい

Kotlin — A deeper look – Hacker Noon より

f:id:nyanyonin:20170820011605p:plain:w300

この図分かり易いと思ってディスプレイに貼ってる。

この図↓も貼ることにした。(2017/10/05追記)

データクラスの話/スコープ関数の話 #rkt - Speaker Deck より

f:id:nyanyonin:20171005103610j:plain:w300

とてもわかりやすい!

この図↓も追加(2018/7/25追記)

Kotlin Demystified: What are 'scope functions' and why are they special? より

f:id:nyanyonin:20180725130318p:plain:w400

以下は自分用の調べたり人から聞いたりしたことのだらだらめも

let

public inline fun <T, R> T.let(block: (T) -> R): R = block(this)
  • 最後の値が戻り値になる
  • 自身がクロージャの引数になる
  • nullableのunwrapによく使う
  • 引数として関数をとる
  • 変換(convert)に向いてる
  • イメージ
    • ◯ func(it)
    • ✖️it.func()

run

public inline fun <T, R> T.run(block: T.() -> R): R = block()
  • クロージャ内の最後の実行結果がrun()の戻り値になる
  • letとwithが合わさったような定義
  • 任意の型Tの拡張関数で、そのTをレシーバとするメソッドのような関数を引数に取る必要がある
  • レシーバーのプロパティとかガンガン使ってなにかする場合に向いてる
  • イメージ
    • ◯ this.func()
    • ✖️func(this)

apply

public inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }
  • 返り値は自分自身。なので何か処理を施して自分に返したい時に使う。
  • Fragmentのインスタンスを作って、argumentsをセットする時など、 オブジェクトのインスタンスを生成して、 すぐにいくつかのプロパティを初期化する必要がある場合に向いてる
class RoomActivity : AppCompatActivity() {
  companion object {
    private const val EXTRA_ROOM_ID = "extra_room_id"

    fun createIntent(context: Activity, roomId: Int)
          = Intent(context, RoomActivity::class.java).apply {
      putExtra(EXTRA_ROOM_ID, roomId)
    }
  }

with

public inline fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
  • not 拡張関数
  • 第一引数に任意の型Tを取る。
  • 第二引数に関数を取るが、Tをレシーバとする関数である必要がある
  • applyと似てる
    • with:最後の実行式を返す
    • apply:自身を返す
  • イメージ:英語の意味で考えると分かり易いかも(〜を使って何かをする)

also

public inline fun <T> T.also(block: (T) -> Unit): T { block(this); return this }

たろうさんの記事がわかり易かったのでほぼ引用させていただきます。

applyとほぼ同じ。異なる点は「引数が元のレシーバ("hoge")の拡張関数ではなく、元のレシーバを引数に取る関数である」ところ。 その利点は2つ

①名前を付けられるのでコードの可読性が上がる

ラムダ式の内と外でthisの意味が変わらない

// applyを使用
val button = Button(this).apply {
  text = "Click me"
  setOnClickListener { 
    startActivity(Intent(this@MainActivity, NextActivity::class.java))
    // 単なる「this」ではNG   ^
  }
}
// alsoを使用
val button = Button(this).also { button -> 
  button.text = "Click me"
  button.setOnClickListener { 
    startActivity(Intent(this, NextActivity::class.java))
  }
}

同じく「元のレシーバを引数に取る関数」を引数に取るletとの違いは、letは戻り値を自分で決めるのに対し、alsoは元のレシーバが返されるという点

// letを使用
val button = Button(this).let { button -> 
  button.text = "Click me"
  button.setOnClickListener { 
    startActivity(Intent(this, NextActivity::class.java))
  }
  button // letの場合はこれが必要になる
}

めもここまで。

というわけで、やっぱりよくわからん!!!!!\(^o^)/

色んな人に使い分け方聞いてる*1んですが、 人によって微妙に使いどころ(捉え方?)違うような印象だったり・・・

英語の意味を考えて使うようにすると前よりしっくりきた。。ような気がする

まだまだ理解足りてないのでご指摘・補足等ございましたら遠慮なくお願いいたします🙇🙇


参考サイト

Kotlin — A deeper look – Hacker Noon

http://qiita.com/ngsw_taro/items/d29e30809fc8a38691e

Kotlin 1.1で追加された標準ライブラリの関数をざっくり見る - visible true


*1:①返り値を使わない+何か初期化とかするときはwithで、自分自身が欲しい場合はapply、返り値を使いたいときはrun or letみたいな感じ

RxJava入門してきた

こちらに参加してきましたという感想文です。

自分のRxレベルはAPI周りの非同期処理を見よう見まねで触れ出した初心者レベル。

入門者向けの内容だったので正直ありがたかったです🙏

RxJavaは1から2への移行がなかなか苦労する(null が非許容になった等)ということは耳にしていたので、 今からやるなら何も意識せずRxJava2を使った方がいいそう。

speakerdeck.com

お話の中で印象的だったのは、黒川さんがイメージするRxJavaは、よく言われる川の流れというより、 排水管の流れをキュッとコントロールするイメージだそう。

確かに自分もそっちの方がしっくりくるかも

あとオペレータは黒川さんも把握できてないほど種類が多いとか、、

当日の課題はこち

github.com

RxJavaってどう課題にするんだろう🤔と思ってたけど、Android要素が取り入れられてて、 しかも業務で活かせそうな内容で大変有り難いです🙏

入門者はやってみると良いと思います!

あと図々しく質問したらこんなお返事いただけました🙇🙇

まだRxJavaは出来ることが多すぎて混乱中ですが、うまくキュキュッとコントロールできるようになりたいものです。

ダイエットを頑張った話

speakerdeck.com をしてきた。

結局今のサイズは…?

施策が増えたりでちょっと太ってしまったのですが現状は 6.1M です。 ので一番太ってたころと比べると1/4ほどになりました

反省点

  • apkサイズはもっと減らせる筈(proguard設定はもう少し見直せそう)
  • Zeplinいいぞ話が時間足りなくて出来なかった(今更感あるけど、便利機能が追加されてるので実際見せて紹介したかった)
  • Layout階層のダイエット話もしたかった(諸々間に合わなかった)
  • 自分のダイエットには失敗した…泣

教えていただけた他のダイエット方法

  • ロケールを絞る → 日本オンリーの仕様ならこんなことができるみたいです。知らなカッタ…
    赤字部分を追加でライブラリにあるja以外のstringsを弾いてくれる模様

build.gradle

    defaultConfig {
        minSdkVersion 15
          …

        resConfigs "ja"
    }

試してみたら500kBほど減りました


こちらは未だ試せてないけど試してみたいです🙏

setCustomAnimationsが効かなくてハマってた

FragmentTransactionに設定する順番が原因。 .addの後に.setCustomAnimationsしてのが問題だった。

    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
    transaction
            .setCustomAnimations(android.R.anim.slide_in_left, android.R.anim.slide_out_right,
                    android.R.anim.slide_in_left, android.R.anim.slide_out_right)
            .add(R.id.content_container, new Fragment())
            .addToBackStack(null)
            .commit();

これで解決。ハマったー泣

RecyclerViewの中でPopupMenuするとscrollしちゃう問題

こうなっちゃって困ってた

f:id:nyanyonin:20170317224708p:plain:w300

ボタン押したらにゅるって動いちゃう
          ↓

f:id:nyanyonin:20170317231439p:plain:w300



android.support.v7.widgetじゃなくてandroid.widget.PopupMenuを使ったら解決した。

f:id:nyanyonin:20170317230300p:plain:w300

ちゃんとわかってないけどv7のバグってことでいいのかな?
android - PopupMenu click causing RecyclerView to scroll - Stack Overflow

VectorDrawableをさっくり触った話

droidgirls.connpass.com こちらに参加してきたので感想などなど

VectorDrawable触ったことなかったけど、 講師のこにふぁーさんの解説と用意してきてくださった課題のおかげで 短い時間でさっくり動かすことができた。自分の整理用に書く

こちら当日のありがたいスライド(というか全てはここに書いてある) speakerdeck.com

VectorDrawableについてざっくり

VectorDrawableを使うとapkサイズが削減できる

SVG(Scalable Vector Graphics)を使っているのでpngなどのビットマップデータと違い、拡大しても画像が荒くなったりせず綺麗 → 今まで端末サイズ毎に用意してきたpngファイルを一つにできる。

Lollipop(API Level 21)未満もsupportされた

※Support Library23.2〜
但しanimatedVectorDrawableのmorphing animationは未だsupportされていない
(ただLollipop未満でも同じように動かせる方法もあるらしいとのこと)

逆にVectorDrawable使うべきじゃない時

大きい画像の場合(googleさん規定では200 × 200 より大きい画像)
また色や形状が複雑な画像の場合は初回読み込みが遅くなる

VectorDrawable使い方

svgファイル取得

一般的なデザインツール(sketchやadobe製品)なら大体svg吐き出しツールがある
GoogleのMaterial Designはすでに用意されてるものがある → https://design.google.com/icons

svgからXMLを作成

Android Studioの New > Vector Asset でXML作成してdrawableに吐き出してくれる
サイズは(きっと)小さければ小さいほど良いらしい

XMLをImageViewに設定

できたものをImageViewのandroid:srcapp:srcCompatに変えて指定
srcから設定するときはsetImageResource()を使う
toolbarのメニューiconでも使用できる
※TextView内で画像指定するときは別途selectorファイルを作ってそれを指定する
- その他詳細やGradleの設定などはこちらを VectorDrawable対応まとめ - Qiita

AnimatedVectorDrawable使い方

XMLファイルを用意

vector drawable
② animator
③ AnimatedVectorDrawable:①を@drawableに指定、②をtarget@animatorに指定
※ ①と③のnameを同じものにしなくてはいけない★

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="48dp"
    android:height="48dp"
    android:viewportHeight="48.0"
    android:viewportWidth="48.0">
    <path
        android:name="pause"
        android:fillColor="#000000"
        android:pathData="@string/path_pause" />
</vector>
<animated-vector  
   android:drawable="@drawable/ic_pause_48dp">
    <target
        android:name="pause"
        android:animation="@animator/anim_pause_to_play" />
</animated-vector>
※ 新しい書き方ではXMLは③のみでOKになった

srcにて③をImageViewに設定しstart()

Drawable drawable = imageView.getContext().getDrawable(③);
imageView.setImageDrawable(drawable);
Animatable animatable = (Animatable) drawable;
animatable.start();

toolなど

詰まったところ

  • AnimatedVectorDrawableの③の書き方をすると Element animated-vector doesn't have required attribute android:drwableだのattribute is missing the android namespace prefixだのエラーが出る f:id:nyanyonin:20170129183354p:plain
    → 現状のAndroid studio(ver 2.2.3)の対応が追いついてないだけのようで、エラーは出るがこれで動く

  • 5未満の端末でTextViewのandroid:drawableLeftで落ちる
    → StateListDrawableを作成してその中でVectorDrawableを指定してあげる必要がある(※参考)
    → 使用するActivityで以下の呼び出しが必要

static {
 AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

感想

  • Lollipop未満もサポートされたってことでアイコン系はVectorDrawableに置き換えてどれだけサイズ減るか試してみたい
  • vectorファイルの命名がgoogleサンプルのic_〜〜_[size]dp.xmlが一般的?みたいだけどなんか気持ち悪い、皆さんどうしてるんだろう
  • AndroidIconAnimatorでファイル作ってみようとしたけど簡単なことしかできなかったムズイ(;・∀・) 出来たら書きますっ
  • pathの仕組みの解説をこにふぁーさんが「ね、簡単でしょ」的にしてたけど難しかった😭
  • こちらの用意してくださったサンプルコードが入門向けにとてもわかりやすかったです
    こにふぁーさんありがとうございました!!!


何か間違ってたらご指摘お願いしますm(__)m