どっこと備忘録群

アウトプットしないとインプットできない私が Androidアプリ開発をメインとした備忘録を載せています。

Activityを扱う

Activityを追加する

最小単位で必要な作業は以下2つ。

  1. AppComatActivity を継承したクラスを新規作成する。
  2. AndroidManifest.xmlに定義を追加する。

Activityクラスの新規作成

AppComatActivity を継承したクラスを追加する。

例えば、CustomActivity を実装する。 実装はどこでも問題ないが、Activityであれば専用のファイル(CustomActivity.kt)を作成するのが自然。

class CustomActivity : AppCompatActivity() {
}

AndroidManifest.xmlに定義の追加

前項で実装したCustomActivityの定義をAndroidManifest.xmlに追加する。

定義は<application>タグ内に追加する。

<application
  ... 
  ...>
  <activity android:name="com.mkt120.sampleapplication.CustomActivity" />

</application>

新規プロジェクトを作成すると、MainActivityがすでに定義されているので、それを参考にすると良い。

Activityを開始する

startActivityを使う。

例えばボタンをタップした時に、1つめの画面(MainActivity)から2つめの画面(CustomActivity)を開始する場合は以下。

  findViewById<View>(R.id.button_start_activity).setOnClickListener {
      val intent = Intent(context, CustomActivity::class.java)
      startActivity(intent)
  }

Activityを開始し、その結果を受け取る

ActivityResultLauncher.launchを使う。

2つめのActivityの処理結果を1つめのActivityで受け取りたい場合、startActivityで開始すると結果を受け取ることができない。

ActivityResultLauncher.launchを使ってActivityを開始し、2つめのActivityの処理結果を受け取る処理を実装しておく。

例えば2つめの画面として、CustomActivityを以下のように実装する。

class CustomActivity : AppCompatActivity() {

    companion object {
        const val EXTRA_RESULT_DATA = "extra_result_data"
    }

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

        val button1 = findViewById<Button>(R.id.button_1)
        button1.setOnClickListener {
            // 処理結果をintentに設定してActivityを終了する
            val data = Intent().apply {
                putExtra(EXTRA_RESULT_DATA, button1.text.toString())
            }
            setResult(RESULT_OK, data)
            finish()
        }
        val button2 = findViewById<Button>(R.id.button_2)
        button2.setOnClickListener {
            // 処理結果をintentに設定してActivityを終了する
            val data = Intent().apply {
                putExtra(EXTRA_RESULT_DATA, button2.text.toString())
            }
            setResult(RESULT_OK, data)
            finish()
        }
    }

}

res/activity_startactivity_custon.xmlとして以下を追加する。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:gravity="center"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button_1"
        android:layout_width="wrap_content"
        android:text="ボタン1"
        android:layout_height="wrap_content"/>

    <Button
        android:id="@+id/button_2"
        android:layout_width="wrap_content"
        android:text="ボタン2"
        android:layout_height="wrap_content"/>

</LinearLayout>

1つ目の画面でCustomActivityを開始するため、ActivityResultLauncherを生成する。 ActivityResultLauncherregisterForActivityResultを利用する。

  private val activityResultLauncher = registerForActivityResult(StartActivityForResult()) { result ->
    if (result.resultCode != RESULT_OK) {
      // キャンセルされた
      return@registerForActivityResult
    }
    val data = result.data?.getStringExtra(CustomActivity.EXTRA_RESULT_DATA)
    val textView = findViewById<TextView>(R.id.text_view_result)
    textView.text = "$data:がタップされました"
  }

生成したActivityResultLauncherCustomActivityを開始する。

  findViewById<View>(R.id.button_register_activity_for_result).setOnClickListener {
    val intent = Intent(context, CustomActivity::class.java)
    activityResultLauncher.launch(intent)
  }

補足:startActivityForResultについて

startActivityForResultActivityResultLauncherが追加される前に利用されていた機能で、現在はdeprecated(非推奨)となっている。

参考

Activityを透明にする

AndroidManifest.xmlでそのActivityテーマを適用する。

styles.xmlで透明なActivity用のテーマを定義する。

<style name="TransparentActivityTheme" parent="AppTheme.NoActionBar">
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="android:colorBackgroundCacheHint">@null</item>
    <item name="android:windowIsTranslucent">true</item>
</style>

追加したテーマを適用することで、そのActivityを透明にできる。

<activity
    android:name="com.sample.application.TransparentActivity"
    android:theme="@style/TransparentActivityTheme"/>

注意点:orientationを指定するとクラッシュする

透明なActivityの利用時には重要な注意点がある。 AndroidManifest.xmlandroid:screenOrientationを指定したり、プログラムで画面の向き(orientation)を設定すると、アプリがクラッシュする。 これは透明なActivityが親のActivityの向きに依存する仕様があるため。

透明なActivityを使用する際は、画面の向きに関する設定を行わないこと。

参考

Activityをダイアログのように表示する

1. 最小限の設定

Activityをダイアログのように見せるには、AndroidManifest.xmlで対象のActivityに以下のテーマを設定するだけです。

android:theme="@style/Theme.MaterialComponents.DayNight.Dialog"

これはDialogFragmentで使われるスタイルで、画面が浮き上がった見た目となる設定。

これをActivityに設定することでをダイアログのような見せ方を手軽に実現できる。 ただし見た目がかわるだけなので、ダイアログの挙動(ボタンや入力フィールドなど)は、レイアウト側で別途実装する必要がある。

2. カスタマイズする場合

アプリ全体で統一感のあるダイアログにしたい場合は、基本のテーマを継承してカスタマイズするのがよい。

Theme.MaterialComponents.DayNight.Dialogは、ダイアログのような表示を実現するために複数の属性を内部的に設定しています。主な属性は以下の通りです。

<item name="android:windowFrame">@null</item>
<item name="android:windowIsFloating">true</item>
<item name="android:backgroundDimEnabled">true</item>
<item name="android:windowBackground">@drawable/abc_dialog_material_background</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowAnimationStyle">@style/Animation.AppCompat.Dialog</item>

これらの属性をアプリの共通テーマを継承した独自のスタイルに設定することで、アプリのデザインに合わせたダイアログを実装できる。

補足

AndroidとしてはDialogFragmentの使用が推奨されているため、簡単な表示のみに留め 複雑なロジックや状態管理が必要な場合はDialogFragmentを利用した方が良い。

Activityのスタックをクリアしたい

Intent#setFlag(int)Intent.FLAG_ACTIVITY_CLEAR_TOP をセットする。

fun showTop(View view) {
  let intent = Intent(getApplication(), MainActivity::class.java)
  intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
  startActivity(intent);
}

起動したActivityを全て終了したい

Activity#finishAffinity() を使う。

参考

共通ボタンとして外部に通知する。

外部の共通ボタンが押されたことを検知したい

実装手順

  1. AndroidManifest.xmlに宣言を追加
  2. 通知を受け取った時の処理を実装
  3. 共有ボタンによるデータ送信のintentを受け取る宣言を明記し

1. AndroidManifest.xmlに宣言を追加

例えば共有ボタンが押された時に MainActivity を起動したいとき、<intent-filter> に以下を追加する。

<activity android:name=".MainActivity" >
  <intent-filter> 
    <action android:name="android.intent.action.SEND" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:mimeType="text/plain" />
  </intent-filter>
</activity>

2. 通知を受け取った時の処理を実装

メンバ変数として持っているintentに共有情報として値が保持されているので Intent.EXTRA_TEXT をキーに参照する。

override fun onCreate(savedInstanceState: Bundle?) {
  if (intent?.action == Intent.ACTION_SEND) {
    val text = intent.getStringExtra(Intent.EXTRA_TEXT)
    // 良しなにする
  }
}

共有ボタンを実装したい

共有したいデータを詰めたintentIntent#createChooserに渡して、返されたintentをstartActivityする。

val temp: Intent = Intent().apply {
  action = Intent.ACTION_SEND
  putExtra(Intent.EXTRA_TEXT, "テストのテキストです")
  type = "text/plain"
}
startActivity(Intent.createChooser(temp, null))

最終更新: NaN.NaN.NaN