LoginSignup
1
1

More than 5 years have passed since last update.

FirebaseのRealtime Databaseでクリアタイムランキングを作成する(Androidアプリ)

Posted at

前回の続きです。
https://qiita.com/KIRIN3qiita/items/4573d26187b8c9e53fc6

今回はRealtime Databaseの実践編としてゲームクリアタイムのランキングを作成します。
qiita.png

私が昔作成したお釣り支払いゲームのクリアタイムランキング画像です。

自作のしょぼいゲームアプリでも、クリアタイムランキングがあると少しは形になります。(インストール数100ぐらいですが・・・)
至高の支払い(https://play.google.com/store/apps/details?id=jp.kirin3.changegame&hl=ja)
これを応用すればスコアランキングなども作れます。

ルール作成

$ Variablesを利用して、ユーザーごとのデータを保存するルールを作成します。

$ Variablesについて
---------------------------
$ 接頭辞を持つキャプチャ変数を宣言することにより、読み取りや書き込みのパスの一部をキャプチャできます。これはワイルドカードとして機能し、ルール宣言の内部で使用するために該当のキーの値を保存します
---------------------------

ユーザーごとの名前、クリア時間、クリア日時、ユーザーIDを保存するルールを作成しました。

ルール
{
  /* Visit https://firebase.google.com/docs/database/security to learn more about security rules. */
  "rules": {
     "info": {
      ".read": true,
      ".write": true,
      "$user_id": {
        "name": {
          ".validate": "newData.isString() &&
                          newData.val().length < 9"
        },
        "time": {
          ".validate": "newData.isNumber()"
        },
        "date": {
          ".validate": "newData.isString()"
        },
        "user_id": {
          ".validate": "newData.isString()"
        }
      }
    }
  }
}

"$user_id"の項目の中に"user_id"があるのは気持ちが悪いですが、同じ階層のデータを引き抜くイメージなのであると便利です。

データ登録

まずデータ保存、取得に利用するクラスを作成。

User
public static class User {
    public int rankingNo;
    public String name;
    public Double time;
    public String date;
    public String userId;

    // 空のコンストラクタの宣言が必須
    public User() {
    }

    public User(String _name, Double _time,String _date,     String _userId) {
        name = _name;
        time = _time;
        date = _date;
        userId = _userId;
    }
    public void setRankingNo( int _rankingNo ){
        rankingNo = _rankingNo;
    }

    public Integer getRankingNo(){
        return rankingNo;
    }
    public String getName(){
        return name;
    }
    public Double getTime(){
        return time;
    }
    public String getDate(){
        return date;
    }
    public String getUserId(){
        return userId;
    }
}
データ登録
// とりあえずUserIdはUUIDで作成。(その後、毎回変わらないようにプリファランスに保存するなどが必要)
String sUserId = UUID.randomUUID().toString();

User user = new User( "UMEHARA",5.3,"2019-10-21 09:00:27" ,sUserId);

// インスタンスの取得
FirebaseDatabase database = FirebaseDatabase.getInstance();

// ファイルパスを指定してリファレンスを取得
DatabaseReference ref = database.getReference("info");

// データを登録
ref.child(sUserId).setValue(user);

データ取得

取得前に一度だけ終端データを登録しておきます。(なぜ必要かは後で説明)

終端データ登録
public void SaveTerminal(){
    String userId = TARMINAL;
    String userName = "ターミナル";
    Double time = 99999.9;
    String date = "1999-01-01 00:00:00";

    FirebaseDatabase database = FirebaseDatabase.getInstance();
    DatabaseReference ref = database.getReference("info");

    User user = new User( userName,time,date,userId );
    ref.child(userId).setValue(user);
}
データ取得
// ユーザーデータ配列
public static ArrayList<User> sUsers;
// ランキングの最大取得数
final int OUTPUT_RANKING_NUM = 100;

FirebaseDatabase database = FirebaseDatabase.getInstance();
// ファイルパスを指定してリファレンスを取得
final DatabaseReference refUser = database.getReference("info");
// クリア時間でソート、最大取得数を設定
refUser.orderByChild("time").limitToFirst(OUTPUT_RANKING_NUM + 1).addChildEventListener(new ChildEventListener() {
    @Override
    public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) {
        User user = dataSnapshot.getValue(User.class);

        // ランキング順位もオブジェクトに保存
        sRankNo++;
        user.setRankingNo(sRankNo);

        // 終端データを受け取ったら、アダプターに渡し、リストビューに表示
        if( dataSnapshot.getKey().equals(TARMINAL) || sRankNo == OUTPUT_RANKING_NUM + 1 ){
            UserAdapter adapter = new UserAdapter(getApplicationContext(), 0, sUsers);
            sListView.setAdapter(adapter);
        }
        // 配列に保存
        else {
            sUsers.add(user);
        }
    }
    @Override
    public void onChildChanged(DataSnapshot dataSnapshot, String s) {
    }
    @Override
    public void onChildRemoved(DataSnapshot dataSnapshot) {
    }
    @Override
    public void onChildMoved(DataSnapshot dataSnapshot, String s) {
    }
    @Override
    public void onCancelled(DatabaseError databaseError) {
    }
});

取得したデータを配列に入れて、アダプターに渡し、ListViewで表示します。
データはクリア時間でソートされ、最大100件の取得に設定しています。
データの取得完了が判断できないので終端データ(必ず最後に取得するデータ)を登録してデータの終わりを判断しています。ルール文で"$user_id"の項目の中に"user_id"があるなど、もっとよい書き方があるかもしれませんが、一応これでも動くということでご参考にして頂けたらと思います。
Realtime Databaseは癖がすごくて使いこなすのは大変ですね。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1