【お手軽】Backボタンを二回タップすると終了する例の機能を実装してみる

2013.01.01

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは2013年。こむろです。

今年ものんべんだらりんと技術ネタをあげていこうと思います。よろしくお願い致します。

Androidでは、たまにBackボタンを二回タップしないと終了しないアプリケーションがあります。Google推奨の標準のUIではないですが、結構メジャーなアプリケーションで実装されているような気がします。Backボタンを一度タップしただけでは終了したくない場合、終了確認ダイアログを出す方法もありますが、今回は、Backボタンを二回タップすると終了する機能をさくっと作ってみたいと思います。

この実装方法よりもスマートでエレガントな実装方法があれば、是非教えてください

Backボタンを検知する

何のボタンがタップされたかは、物理キー、ソフトウェアキーボードを含めて、Activity#dispatchKeyEvent で検知可能です

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
	return super.dispatchKeyEvent(event);
}

KeyEvent event のkeyCodeを評価すればOKです。KeyEvent に定数が定義してありますので、それを利用します。

Backボタンを検知。KeyEvent#KEYCODE_BACK を使います

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
	
	// Backボタン検知する
	if(event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
		Log.d(TAG, "Press back button");
		return false;
	}
	// Backボタンに関わらないボタンが押された場合は、通常処理.
	return super.dispatchKeyEvent(event);
}

ちなみに上記のコード実装をすると、絶賛Backボタンの動作がすべて無視されるので、アプリが終了できなくなるのでご注意を。

Backボタンを二度タップされたことを検知する

特に思いつかなかったので、タップ回数の状態をboolean変数で持たせてみます。また規定時間内に二度タップされたことを検知する必要があるので、何かしらTimerが必要になります。ちょうどAndroidのパッケージに CountDownTimer というabstract classがあるので、これを利用してみます。

// onFinish(), onTick()
keyEventTimer = new CountDownTimer(1000, 100) {
	
	@Override
	public void onTick(long millisUntilFinished) {
		Log.d(TAG, "call onTick method");
	}
	
	@Override
	public void onFinish() {
		Log.d(TAG, "call onFinish method");
	}
};

abstract classのため、そのままインスタンス化はできないので、実装を書きます。引数の前方の数値は、Finishまでの時間をmsで指定します。後方の数値は、Finishまでの刻み時間の指定です。この場合は、1秒後にonFinish()が実行され、その間に10回のonTick()が実行され(るはずです)ます。

完全体

全体のコードはこんなかんじでしょうか

import android.os.Bundle;
import android.os.CountDownTimer;
import android.app.Activity;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.widget.Toast;

public class MainActivity extends Activity {
	
	// Log用のTAG
	private static final String TAG = MainActivity.class.getSimpleName();
	
	// BackボタンPress時の有効タイマー
	private CountDownTimer keyEventTimer;
	
	// 一度目のBackボタンが押されたかどうかを判定するフラグ
	private boolean pressed = false;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		// onFinish(), onTick()
		keyEventTimer = new CountDownTimer(1000, 100) {
			
			@Override
			public void onTick(long millisUntilFinished) {
				Log.d(TAG, "call onTick method");
			}
			
			@Override
			public void onFinish() {
				pressed = false;
			}
		};
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.activity_main, menu);
		return true;
	}

	@Override
	public boolean dispatchKeyEvent(KeyEvent event) {
		
		// Backボタン検知
		if(event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
			if(!pressed) {
				// Timerを開始
				keyEventTimer.cancel(); // いらない?
				keyEventTimer.start();
			
				// 終了する場合, もう一度タップするようにメッセージを出力する
				Toast.makeText(this, "終了する場合は、もう一度バックボタンを押してください", Toast.LENGTH_SHORT).show();
				pressed = true;
				return false;
			}
			
			// pressed=trueの時、通常のBackボタンで終了処理.
			return super.dispatchKeyEvent(event);
		}
		// Backボタンに関わらないボタンが押された場合は、通常処理.
		return super.dispatchKeyEvent(event);
	}
}

実行結果

device-2013-01-01-002802

こんな感じです。1秒以内に再度Backボタンをタップするとアプリケーションを終了できます。1秒以上経過した場合は、またメッセージが出てきて終了されません。

Androidで標準で持っていない機能なので、標準のUIからは外れるんだろうなーとは思いますが、要件として必要になることがあるかもしれないので、試しに実装してみました。

Happy Android Life!