🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

Q&A

解決済

1回答

3045閲覧

AndroidアプリKeyEvent取得時の挙動がうまくいきません

tattys

総合スコア7

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

0グッド

0クリップ

投稿2021/02/02 11:48

前提・実現したいこと

AndroidStudioにて短い時間内に端末のバックボタンが二回押下されたらアプリを終了できるようにしました。ここまでは安定して実行できました。
さらに、メニューバーが開いていれば一度目のバックボタンが押されたときはメニューバーを閉じるようにし、閉じた状態でバックボタンが二回押下されたらアプリを終了できるようにしようと思いました。

 するとメニューバーを開いるときにバックボタンを押下するとメニューバーは正しく閉じたのですが、アプリを終了するための一度目の押下としても反応してしまいました。

何か他の原因があるでしょうか?

発生している問題・エラーメッセージ

にメニューバーが開いているときにバックボタン押下でメニューバーは正しく閉じますが、
終了するための一度目のバックボタンとしても反応し、トーストも表示されてしまいます。
ログはこんなことになっています。
それぞれ一回ずつしかバックボタンを押下していないのになぜかKeyEventが二回拾われているように見えます

-----------------メニューバーが閉じている時の一度目のバックボタン押下時------------------ D/menuOpened: false D/pressed: false false D/menuOpened: false D/pressed: true ----------------メニューボタンで開いたとき------------------- D/menuButton: メニュー表示 ---------------メニューバーが開いているときの一度目のバックボタン押下-------------------- D/menuOpened: true D/pressed: false D/menuButton: メニュー非表示 D/menuOpened: false D/pressed: false false ---------------時間内に二回のバックボタン押下-------------------- D/menuOpened: false D/pressed: false false D/menuOpened: false D/pressed: true D/menuOpened: false D/pressed: true D/menuOpened: false D/pressed: true -----------------ここでアプリは正常終了する-------------------

レイアウトソースコード

XML

1<?xml version="1.0" encoding="utf-8"?> 2<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:app="http://schemas.android.com/apk/res-auto" 4 xmlns:tools="http://schemas.android.com/tools" 5 android:layout_width="match_parent" 6 android:layout_height="match_parent" 7 tools:context=".MainActivity"> 8 9 <Button 10 android:id="@+id/menuButton" 11 android:layout_width="wrap_content" 12 android:layout_height="wrap_content" 13 android:text="MenuButton" 14 app:layout_constraintStart_toStartOf="parent" 15 app:layout_constraintTop_toTopOf="parent" /> 16 17 <androidx.constraintlayout.widget.ConstraintLayout 18 android:id="@+id/menuBar" 19 android:layout_width="match_parent" 20 android:layout_height="match_parent" 21 android:layout_marginTop="55dp" 22 android:layout_marginEnd="100dp" 23 android:layout_marginRight="100dp" 24 android:background="@color/black" 25 app:layout_constraintBottom_toBottomOf="parent" 26 app:layout_constraintEnd_toEndOf="parent" 27 app:layout_constraintStart_toStartOf="parent" 28 app:layout_constraintTop_toTopOf="parent"> 29 30 </androidx.constraintlayout.widget.ConstraintLayout> 31</androidx.constraintlayout.widget.ConstraintLayout>

アクティビティソースコード

Kotlin

1package com.example.myapplication 2 3import androidx.appcompat.app.AppCompatActivity 4import android.os.Bundle 5import android.os.CountDownTimer 6import android.util.Log 7import android.view.KeyEvent 8import android.view.View.GONE 9import android.view.View.VISIBLE 10import android.widget.Button 11import android.widget.Toast 12import androidx.constraintlayout.widget.ConstraintLayout 13 14class MainActivity: AppCompatActivity(){ 15 // 一度目のBackボタンが押されたかどうかを判定するフラグ 16 private var pressed = false 17 18 // メニューバー開閉フラグ 19 private var menuOpened = false 20 // 開閉するメニューバー 21 lateinit var menuBar: ConstraintLayout 22 //タイマー 23 private var keyEventTimer: CountDownTimer? = null 24 25 override fun onCreate(savedInstanceState: Bundle?) { 26 super.onCreate(savedInstanceState) 27 setContentView(R.layout.activity_main) 28 29 val menuButton = findViewById<Button>(R.id.menuButton) 30 menuBar = findViewById(R.id.menuBar) 31 menuBar.visibility = GONE 32 // 二度バックボタンが押されるときのタイマー 33 keyEventTimer = object : CountDownTimer(1000, 100) { 34 override fun onTick(millisUntilFinished: Long) { 35 } 36 override fun onFinish() { 37 pressed = false 38 } 39 } 40 menuButton.setOnClickListener{ 41 Log.d("menuButton", "メニューバー表示") 42 menuBar.visibility = VISIBLE 43 menuOpened = true 44 } 45 46 } 47 48 fun closeMenuBar(){ 49 menuBar.visibility = GONE 50 Log.d("menuButton", "メニューバー非表示") 51 menuOpened = false 52 } 53 override fun dispatchKeyEvent(event: KeyEvent): Boolean { 54 if (event.keyCode == KeyEvent.KEYCODE_BACK) { 55 Log.d("menuOpened", menuOpened.toString()) 56 Log.d("pressed", pressed.toString()) 57 if (menuOpened){ 58 closeMenuBar() 59///////////////////////ここを変えてみたりしたが同じ結果///////////////////// 60 return false 61/////////////////////////////////////////////////////////////////////////// 62 } else if (!pressed) { 63 Log.d("pressed",pressed.toString()) 64 keyEventTimer!!.cancel() 65 keyEventTimer!!.start() 66 67 Toast.makeText(this, "終了する場合は、もう一度バックボタンを押してください", Toast.LENGTH_SHORT).show() 68 pressed = true 69///////////////////////ここを変えてみたりしたが同じ結果///////////////////// 70 return false 71/////////////////////////////////////////////////////////////////////////// 72 } else 73 return super.dispatchKeyEvent(event) 74 } 75 return super.dispatchKeyEvent(event) 76 } 77}

試したこと

KeyEventの戻り値を変えたりしましたが結果は同じでした。

端末の問題(壊れているとか?)かと思って以下の端末で試しましたが結果は同じでした
Pixel 4 API 28 (Emulator)
Sony SO-03K (実機)
Sony SO-51A (実機)

補足情報(FW/ツールのバージョンなど)

AndroidStudio4.1.2
Kotlin 1.4.21

を使いました。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

dispatchKeyEvent の先頭に

Kotlin

1 Log.d("dispatchKeyEvent", event.toString())

を入れると分かりますが、キーイベントは action が ACTION_DOWN と ACTION_UP の 2 回来ます。

メニュー非表示状態では、
・ACTION_DOWN で pressed = true になる
・ACTION_UP では super.dispatchKeyEvent(event) を呼ぶが、ACTION_UP の場合は何もしない
ので、結果的に期待通りの動作になってます。

一方、メニュー表示状態では、
・ACTION_DOWN でメニューを非表示にする
・ACTION_UP で pressed = true になる
ため、次のバックボタン押下で終了してしまいます。

修正方法としては、event.action をチェックしても良いのですが、dispatchKeyEvent ではなく onBackPressed メソッドをオーバーライドするのが良いと思います。
参考: [Android] バックキー押下時の onBackPressed() - うら紙のメモ

投稿2021/02/02 19:03

hoshi-takanori

総合スコア7899

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tattys

2021/02/03 04:16

大変丁寧にご回答いただきありがとうございます。しかも速い!! 言われてみれば納得のいく原因でした。 早速修正したいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問