Google I/O 2018 にみる Android KTX その1

Android KTX は、次期 androidx のパッケージとも深い関わりをもっているようです。

androidx: Hello World!
You may notice that Android KTX uses package names that begin with androidx. This is a new package name prefix that we will be using in future versions of Android Support Library. We hope the division between android.* and androidx.* makes it more obvious which APIs are bundled with the platform, and which are static libraries for app developers that work across different versions of Android.

Android Developers Blog: Introducing Android KTX: Even Sweeter Kotlin Development for Android

また、パッケージ名に関してのマッピングも公式からアナウンスされ始めています。

AndroidX refactoring  |  Android Developers

そんな Android KTX に関係するいくつかの動画がアップされています。

Android Jetpack: sweetening Kotlin development with Android KTX (Google I/O 2018) - YouTube

Google I/O 2018: Stage 2 - YouTube

前回は、よく分からんオネーチャンが喋ってましたが、 今回は、Jake Wharton さんが遂に表に登場しました。

彼のトークやスライドは開発に有効に利用できることばかりです。

Kotlin の Extension Function の勉強にもなりますので、登場したコードを書き出しておきます。

並び順は、

「よくあるコード」(before)
「Android KTX のコード(拡張関数)」(KTX)
「KTXを利用したコード」(after)

です。

 

ViewGroupの再帰処理


// before
val userLayout: ViewGroup = findViewById(R.id.users)
for (index in 0 until userLayout.childCount) {
  val view = userLayout.getChildAt(index)
  // Do something with index and view...
}


// KTX
fun ViewGroup.forEachIndexed(action: (Int, View) -> Unit) {
  for (index in 0 until childCount) {
    action(index, getChildAt(index))
  }
}


// after
val userLayout: ViewGroup = findViewById(R.id.users)
userLayout.forEachIndexed { index, view ->
  // Do something with index and view...
}

 

getSystemService()


// before

// In an Activity, on API 23+...
val notifications = getSystemService(NotificationManager::class.java)

// or all API levels...
val notifications = ContextCompat.getSystemService(this,
  NotificationManager::class.java)


// KTX
inline fun <reified T> Context.systemService() =
  ContextCompat.getSystemService(this, T::class.java)


// after
val notifications = systemService<NotificationManager>()

 

Viewのパディング


// before
avatarView.setPadding(
  10, avatarView.paddingTop, 10, avatarView.paddingBottom)


// KTX
inline fun View.updatePadding(
  left: Int = paddingLeft,
  top: Int = paddingTop,
  right: Int = paddingRight,
  bottom: Int = paddingBottom
) {
  setPaddinng(left, top, right, bottom)
}


// after
avatarView.updatePadding(left = 10, right = 10)

 

デストラクチャ


// before
val rect = avaterView.clipBounds
val left = rect.left
val top = rect.top
val right = rect.right
val bottom = rect.bottom
// Use left, top, right, bottom...


// KTX
inline operator fun Rect.component1() = left
inline operator fun Rect.component2() = top
inline operator fun Rect.component3() = right
inline operator fun Rect.component3() = bottom


// after
val (left, top, right, bottom) = avatarView.clipBounds
// Use left, top, right, bottom...

val (left, top, right) = avatarView.clipBounds
// Use left, top, right...

val (left, _, right) = avatarView.clipBounds
// Use left, right...

 

すべての値のチェック


// before
val onlyDigits = true
for (c in phoneNumber) {
  if (!c.isDigit()) {
    onlyDigits = false
    break
  }
}


// before
val onlyDigits = phoneNumber.all { it.isDigit() }


// before
val onlyDigits = TextUtils.isDigitsOnly(phoneNumber)


// KTX
inline fun CharSequence.isDigitsOnly() = TextUtils.isDigitsOnly(this)


// after
val onlyDigits = phoneNumber.isDigitsOnly()

とりあえずは、前半のコードを書き出しておいて、次回へ

(つづく...)


【Android P】カメラに写ってる動いてるこれ何なの?

エミュレータでカメラ起動すると映るコレ。

微妙に動いてるんですけど...

何かのキャラなのか、

家にも見えたりするだけども、動いてるし。

 

一体、何なのっ?!


【Android Oreo】「Picture in Picture」は進化中?!

サンプル見てましたが。

android-PictureInPicture/README.md at master · googlesamples/android-PictureInPicture

...。

ただ、縮小されたActivityを常駐的に端末画面の上に載せたいだけなのですが...。

 

最小限の実装

BlankActivityで実装するだけ。

これぐらいまで。

AndroidManifest.xml


<activity android:name=".MainActivity"
    android:resizeableActivity="true"
    android:supportsPictureInPicture="true"
    android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation">

MainActivity.kt


class MainActivity : AppCompatActivity() {

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    if (VERSION.SDK_INT >= VERSION_CODES.O) {
      text.setOnClickListener {
        val params = PictureInPictureParams.Builder().apply {
          setAspectRatio(Rational(4, 3))
        }.build()
        enterPictureInPictureMode(params)
      }
    }
  }

  override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean,
      newConfig: Configuration) {
    super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig)
    if (isInPictureInPictureMode) {
      text.text = "small"
      setFullScreen(true)
    } else {
      text.text = "normal"
      setFullScreen(false)
    }
  }

  private fun setFullScreen(on: Boolean) {
    window.decorView.systemUiVisibility = if (on) {
      SYSTEM_UI_FLAG_LAYOUT_STABLE or
      SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
      SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
      SYSTEM_UI_FLAG_HIDE_NAVIGATION or
      SYSTEM_UI_FLAG_FULLSCREEN or
      SYSTEM_UI_FLAG_IMMERSIVE_STICKY
    } else {
      SYSTEM_UI_FLAG_LAYOUT_STABLE
    }
  }

}

PinPモードに入ったときのレイアウト変更は、フルスクリーンモードでツールバーを隠すのみ。

Preview 公開当時のサンプルが多いので、今現在の最小限実装でやってみたメモ的な。

関連APIは変化している様子。