2018年4月13日金曜日

[Android]暗黙的Intentを受け取ることができるActivityの存在確認

この文書作成時の環境は以下です。

  • Kotlin 1.2.31
  • Android SDK 27

Intent#resolveActivity()

暗黙的Intentを用いてstartActivityすると、受け取れるActivityがないとき、ActivityNotFoundExceptionが発生するので、存在チェックをしなければならない。
一般的なインテント | Android Developersにあるとおり、Intent#resolveActivity()を使用する。
存在チェックはstartActivityのタイミングでするのではなく、Activity#onCreate()などでチェックして、存在しないならば機能を封印してしまうのが良い。

MainActivity.kt
...

fun Intent.existsImplicitReceiver(pm: PackageManager) : Boolean{
    return this.resolveActivity(pm) != null
}

class MainActivity : AppCompatActivity() {

    val cameraRequestCode:Int = 1

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

        val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
         //  resolveActivityの結果がnullならば機能を封印する
        if(intent.resolveActivity(packageManager) == null){
            button_camera.isEnabled = false
        }

        button_camera.setOnClickListener {
            startActivityForResult(intent, cameraRequestCode)
        }
    }
}

2018年4月11日水曜日

Hello Kotlin for Android

この文書作成時の環境は以下です。

  • Windows 10 Home バージョン1709
  • Android Studio 3.1.1
  • Gradle 4.4
  • Gradle Android Plugin 3.1.1
  • Kotlin 1.2.31

Kotlin is 何

KotlinはJetBrains製の言語で、IDE開発でJavaの代用をするために作られたらしい。1 JVMで動く。
AndroidStudioがJetBrains製ということで、当初はAndroidStudioがサポートする言語という位置づけだったが、2017年5月にGoogleに正式採用された。2
KotlinはJavaと100%相互運用性がある3ので、JavaとKotlinをまぜまぜしながら開発できるらしい。
選択肢は多いにこしたことはないので、是非Kotlinも書けるようになっておきたい。

Hello World in Android

まずは新しいプロジェクトを作成する。Android Studio 3.0以降ならKotlinはプリインストールなのでInclude Kotlin supportのチェックボックスをonにする
image.png (39.6 kB)

ActivityはBasic Activityを追加しておく
image.png (47.8 kB)

エミュレータで実行するとHello Worldする。OK
image.png (25.1 kB)

自動生成されるKotlinファイルを読み解く

Kotlin supportをチェックしておくとMainActivity.javaの代わりにMainActivity.ktが自動生成される。Kotlinファイルを読んでみる

MainActivity.kt
package blue.hassaku.hellokotlin

import android.os.Bundle
import android.support.design.widget.Snackbar
import android.support.v7.app.AppCompatActivity
import android.view.Menu
import android.view.MenuItem

import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

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

        fab.setOnClickListener { view ->
            Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                    .setAction("Action", null).show()
        }
    }

    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        // Inflate the menu; this adds items to the action bar if it is present.
        menuInflater.inflate(R.menu.menu_main, menu)
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        return when (item.itemId) {
            R.id.action_settings -> true
            else -> super.onOptionsItemSelected(item)
        }
    }
}

セミコロンの無い文、後置の型指定、各所のアロー演算子など気になるところはあれど、Androidマンならだいたい読めるのでは?

kotlin-android-extensionsによるViewの解決

MainActivity.kt
        ...
        fab.setOnClickListener { view ->
            Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                    .setAction("Action", null).show()
        }
        ...

急に出てくるfab。これが定義されているのはこちら。

activity_main.xml
    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        app:srcCompat="@android:drawable/ic_dialog_email" />

import kotlinx.android.synthetic.main.activity_main.*とすることで、id付きViewがid名に自動で解決される。すばらしい。
JavaのようにfindViewById()してキャストして4といった操作が必要ない。

式として解釈できるifとwhen

kotlinではifwhenは式として解釈される。(whenはJavaでいうところのswitch

MainActivity.kt
        ...
        return when (item.itemId) {
            R.id.action_settings -> true
            else -> super.onOptionsItemSelected(item)
        }
        ...

上記のコードは、item.itemIdの値がR.id.action_settingsと同値ならtrueを返し、それ以外ならsuper.onOptionsItemSelected(item)を返すという処理。

感想

今後本格的に学んでいくため、現時点ではKotlinの良さというのは判らない。ただ、Javaとの100%相互運用性があるため、少しずつでもKotlinを覚えていくと幸せになりそう。