【Android/BLE開発】明示的な数値を指定したEnumでエラーハンドリングを改善する
はじめに
Android開発、特にBLE通信のような低レベルな処理を扱う際、エラーコードの管理に悩んだことはありませんか?
本記事では、明示的な数値を指定したEnumを使ったエラーハンドリングの実装方法と、そのメリットについて解説します。
対象読者
- Androidアプリ開発の初心者〜中級者
- BLE通信を扱うアプリを開発している方
- エラーハンドリングの設計に悩んでいる方
背景:マジックナンバー問題
従来のコードでは、エラーコードを直接数値で扱うことが多くありました。
// 悪い例:マジックナンバーを使った実装
public void onError(int errorCode) {
if (errorCode == 133) { // この133が何を意味するのか分かりにくい
showErrorMessage("接続に失敗しました");
} else if (errorCode == 8) {
showErrorMessage("タイムアウトしました");
}
}
この実装の問題点:
- 数値だけでは意味が分からない
- コードの可読性が低い
- 保守性が悪い
マジックナンバー(※1): そのシステムの開発者しか知らない意味を持った数値のこと。コードの可読性と保守性を下げる原因となります。
解決策:明示的な数値を指定したEnum
明示的な数値を持つEnumを使うことで、この問題を解決できます。
Enumの実装例
// エラーコードを管理するEnum
public enum BleErrorCode {
// 各エラーに明示的な数値を割り当て
CONNECTION_FAILED(133, "BLE接続に失敗しました"),
TIMEOUT(8, "接続がタイムアウトしました"),
DEVICE_NOT_FOUND(2, "デバイスが見つかりません"),
PERMISSION_DENIED(1, "権限が許可されていません"),
UNKNOWN_ERROR(0, "不明なエラーが発生しました");
// エラーコード(数値)を保持
private final int code;
// ユーザー向けメッセージを保持
private final String message;
// コンストラクタでコードとメッセージを設定
BleErrorCode(int code, String message) {
this.code = code;
this.message = message;
}
// エラーコード(数値)を取得
public int getCode() {
return code;
}
// エラーメッセージを取得
public String getMessage() {
return message;
}
// 数値からEnumを取得するメソッド
public static BleErrorCode fromCode(int code) {
// すべてのEnum値をループして探す
for (BleErrorCode error : values()) {
if (error.code == code) {
return error;
}
}
// 該当するコードがない場合は不明なエラーを返す
return UNKNOWN_ERROR;
}
}
使用例
// BLE通信のManagerクラスでの使用例
public class BleManager {
// エラー発生時のコールバック
public interface BleErrorCallback {
void onError(BleErrorCode errorCode);
}
private BleErrorCallback callback;
// BLE接続処理
private void connectToDevice() {
// 接続処理...
// エラーが発生した場合
int nativeErrorCode = 133; // ネイティブレベルから取得したエラーコード
// 数値をEnumに変換してコールバックで返す
BleErrorCode errorCode = BleErrorCode.fromCode(nativeErrorCode);
callback.onError(errorCode);
}
}
// ViewやActivityでの使用例
public class MainActivity extends AppCompatActivity {
private void setupBleManager() {
BleManager bleManager = new BleManager();
// エラーコールバックの設定
bleManager.setErrorCallback(new BleManager.BleErrorCallback() {
@Override
public void onError(BleErrorCode errorCode) {
// エラーメッセージを表示
showErrorDialog(errorCode.getMessage());
// ログやアナリティクスには数値コードを送信
logError("BLE Error: " + errorCode.getCode());
// エラーの種類によって処理を分岐
switch (errorCode) {
case CONNECTION_FAILED:
// 再接続を試みる
retryConnection();
break;
case PERMISSION_DENIED:
// 権限リクエスト画面へ遷移
requestPermissions();
break;
default:
// その他のエラー処理
break;
}
}
});
}
}
この実装のメリット
1. コードの可読性向上
// 数値よりも意味が明確
if (errorCode == BleErrorCode.CONNECTION_FAILED) {
// 処理
}
2. ユーザーフレンドリーなエラー表示
- ユーザーには分かりやすいメッセージを表示
- サポートやログには数値コードを記録
- 両方の情報を1つのオブジェクトで管理
3. 保守性の向上
- エラーコードの追加・変更が容易
- IDE(※2)の補完機能が使える
- typo(※3)によるバグを防止
IDE(※2): 統合開発環境(Integrated Development Environment)の略。Android Studioなど、プログラミングを支援するツールのこと。
typo(※3): タイプミス(綴り間違い)のこと。Enumを使うことで、IDEが候補を表示してくれるため、間違った値を入力するミスを防げます。
4. エラー分析の効率化
// 数値コードをログに記録することで、後から分析しやすい
Log.e("BLE", "Error occurred: code=" + errorCode.getCode()
+ ", message=" + errorCode.getMessage());
使いどころ
この実装パターンが特に有効なケース:
-
ハードウェアやOSのネイティブコードとの連携
- BLE、NFC、カメラなど低レベルAPIのエラーハンドリング
-
外部システムとの通信
- APIのレスポンスコード管理
- ステータスコード管理
-
ユーザーとサポートの両方に情報提供が必要な場合
- ユーザー:分かりやすいメッセージ
- サポート:具体的なエラーコード
まとめ
明示的な数値を指定したEnumを使うことで:
- マジックナンバーを排除し、コードの可読性を向上
- ユーザーフレンドリーなエラー表示とログ記録を両立
- 保守性の高いエラーハンドリングを実現
BLE通信のような低レベルな処理を扱う際は、ぜひこのパターンを活用してみてください。
参考
更新履歴
2025-05-12 下書き
2026-01-13 初版公開