データ一覧画面の実装

実装の解説の最後に、データ一覧画面の実装を説明します。MainActivity.java ファイルに実装されています。

データ一覧画面は、レイアウトファイル main.xml で定義されており、クラス内の実装と次のように結びついています。

  • ListView を Java のフィールド mListView で保持します。

  • mListView のデータは ObjectAdapter クラスのインスタンス mListAdapter から供給します。

  • mListAdapter で扱うデータの実体は ArrayList クラスの配列に格納した KiiObject です。

データ構造

この画面では、JSON 形式のキーと値のペアを保持する KiiObject を作成し、それを Kii Cloud とやりとりします。データはログイン中のユーザーのスコープの Bucket myBucket に格納されます。

ここでは、KiiObject に格納するデータの作成、一覧取得(表示)、削除の各処理を実装します。

格納するデータ

Kii Cloud では任意の値や型を持ったデータを JSON 形式のキーと値のペアとして扱うことができます。

Hello Kii で扱うデータのキー名はプログラムで myObjectValue と指定されるため、上の図のような JSON 文字列として処理されます。

実際の開発時には、キー名も値の型もモバイルアプリの仕様に合わせて自由に決めることができます(ネストした JSON データも扱えます)。

値の型をスキーマなどの形で事前に指定する必要はありません。プログラムから KiiObject を作成するだけで、データの格納と取得を実行できます。また、JSON データの 1 階層目に格納された値からは自動的にインデックスが作成されるため、高速な検索を行うことができます。

データの作成

まずはデータの作成処理を説明します。

画面の "Add Item" ボタンがタップされると、addItem() メソッドが呼び出されます。このメソッドのコードを抜粋すると、以下のようになります。

String value = "MyObject " + (++mObjectCount);

KiiBucket bucket = KiiUser.getCurrentUser().bucket(BUCKET_NAME);

// Create a new KiiObject instance and set the key-value pair.
KiiObject obj = bucket.object();
obj.set(OBJECT_KEY, value);

// Save the object asynchronously.
obj.save(new KiiObjectCallBack() {
  public void onSaveCompleted(int token, KiiObject o, Exception e) {
    if (e == null) {
      // Insert the object at the beginning of the list adapter.
      MainActivity.this.mListAdapter.insert(o, 0);
    } else {
      showToast("Error creating object: " + e.getLocalizedMessage());
    }
  }
});

上のサンプルコードに示す mObjectCountBUCKET_NAMEOBJECT_KEY は以下のように宣言されています。

private int mObjectCount = 0;
private static final String BUCKET_NAME = "myBucket";
private static final String OBJECT_KEY = "myObjectValue";

ここでは、次の処理を順に行います。

  1. 格納するデータの作成

    KiiObject へ格納するデータ値を value に作成します。ここでは、連番を振り出して、MyObject 1 のような適当な文字列を作成しています。

  2. Bucket の準備

    ログイン中のユーザーのスコープの Bucket を準備します。

    前のページに示したように、getCurrentUser() メソッドによってログイン中のユーザーの KiiUser インスタンスを取得できます。このインスタンスに対して bucket() メソッドを実行すると、このユーザーのスコープの Bucket を取得できます。取得したい Bucket 名を保持する変数 BUCKET_NAME を引数に指定します。

    Bucket が存在しない場合は、データ作成のタイミングで新規に作成されます。既存の Bucket がある場合はその Bucket が取得されます。

  3. KiiObject の準備

    object() メソッドによって Bucket 内に KiiObject を作成します。

    set() メソッドによって KiiObject の JSON データの第 1 階層にキーと値のペアを設定します。以下のような JSON データが作成されます。

    {
      "myObjectValue" : "MyObject 1"
    }
    
  4. KiiObject の保存

    save() メソッドによって KiiObject を保存します。手順 3 までの処理はデバイス上で実行されていましたが、ここで Kii Cloud と通信して Kii Cloud 上に KiiObject を保存します。通信を行うため、ここでもノンブロッキング API を使用しています。

    保存処理が完了すると、onSaveCompleted() メソッドがコールバックとして呼び出されます。エラーがない場合は insert() メソッドによって、登録した KiiObject を mListAdapter の先頭に追加し、画面に反映します。エラーの場合はトーストを表示します。

    save() メソッドによって Kii Cloud 上のデータを更新すると同時に、insert() メソッドによってデバイス側のデータも更新している点にご注意ください。

データの一覧処理

データの一覧処理はデータ一覧画面の起動時に実行されます。onCreate() メソッドの最後で loadObjects() メソッドが呼び出されます。

@Override
public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  ......
  // Query for any objects created previously.
  this.loadObjects();
}

データの取得

一覧取得は、Bucket 内データの全件取得のクエリーを実行することで実現します。loadObjects() メソッドの処理を抜粋すると、以下のようになります。

private void loadObjects() {
  // Empty the adapter.
  mListAdapter.clear();

  // Create an empty KiiQuery. This query will retrieve all results sorted by the creation date.
  KiiQuery query = new KiiQuery(null);
  query.sortByDesc("_created");

  // Define the bucket to query.
  KiiBucket bucket = KiiUser.getCurrentUser().bucket(BUCKET_NAME);

  // Perform the query.
  bucket.query(new KiiQueryCallBack<KiiObject>() {
      public void onQueryCompleted(int token, KiiQueryResult<KiiObject> result, Exception e) {
          ...
      }
  }, query);
}

ここでは、次の処理を行っています。

  1. リストのクリア

    念のため mListAdapter に格納されている KiiObject を全件クリアしておきます。

  2. クエリーの準備

    全件取得のクエリーを準備します。

    まず、KiiQuery() コンストラクタによってクエリーオブジェクト query を作成します。ここでは、全件取得を意味する空のクエリー(null)としています。

    さらに、取得時のソート条件を sortByDesc("_created") で指定しています。これは、KiiObject の作成日時(_created フィールド)の降順でのソートを意味します。すでに見たように、データの作成時には新しい KiiObject を先頭に追加しているため、降順でのソートが適切です。

    検索 API では、文字列や数値の比較によるクエリーや、And や Or などの検索条件の組み合わせもサポートしています。SQL ではなく、オブジェクトの構造によって条件式を表現します。

  3. Bucket の用意

    次に、検索対象の Bucket を用意します。データ作成時と同様に、取得したい Bucket 名(ログイン中のユーザーのスコープの myBucket)を保持する変数 BUCKET_NAME を引数に指定します。

  4. クエリーの実行

    手順 2 で作成した querybucketquery() メソッドの第 2 引数 に指定して、クエリーを実行します。

    今まで見てきた処理と同様に、クエリーの実行も Kii Cloud へのアクセスが必要なため、ノンブロッキング API で実行します。コールバックの onQueryCompleted() メソッドの詳細は次のセクションで説明します。

取得したデータの処理

クエリーを実行し、Bucket 内のデータを全件取得できた場合、コールバックの onQueryCompleted() メソッドでそれを画面表示します。

bucket.query(new KiiQueryCallBack<KiiObject>() {
  public void onQueryCompleted(int token, KiiQueryResult<KiiObject> result, Exception e) {
    if (e == null) {
      // Add the objects to the list view via the adapter.
      List<KiiObject> objLists = result.getResult();
      for (KiiObject obj : objLists) {
        mListAdapter.add(obj);
      }
    } else {
      showToast("Error loading objects: " + e.getLocalizedMessage());
    }
  }
}, query);

取得に成功した場合(e が null の場合)、次の処理を行います。

onQueryCompleted() メソッドの引数 result として、クエリーの実行結果が渡されます。result 内には、取得できた KiiObject の一覧が格納されており、getResult() メソッドで取り出せます。これをループによって 1 件ずつ mListAdapter に格納すると、ObjectAdapter クラスの機能により画面に反映されます。

この実装は、取得件数が多くなると正しく動作しません。件数が多い場合、query() メソッドは ページネーション の機能によって、結果を複数のページに分割して返します。Hello Kii では実装の複雑化の防止のため、初めの 1 ページだけを処理しています。

ListView への表示

データの表示処理は、Android の ListView の実装方法に従って ArrayAdapter クラスのサブクラスである ObjectAdapter クラスに実装します。

ListView に表示する各行の形式はレイアウトファイル row.xml で定義されています。各行に対して、次の図のように値を設定してデータを表示します。

ObjectAdapter クラスの処理を以下に示します。

public class ObjectAdapter extends ArrayAdapter<KiiObject> {
  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
    KiiObject obj = getItem(position);

    LinearLayout rowView = ...

    // Get the text fields for the row.
    TextView titleText = (TextView) rowView.findViewById(R.id.rowTextTitle);
    TextView subtitleText = (TextView) rowView.findViewById(R.id.rowTextSubtitle);

    // Set the content of the row text.
    titleText.setText(obj.getString(OBJECT_KEY));
    subtitleText.setText(obj.toUri().toString());

    return rowView;
  }
}

KiiObject のデータを LinearLayout のビューに設定します。

まず、引数 position によって、処理中の要素のインデックス番号(0, 1, 2, …)が渡されます。このインデックスに対応する KiiObject を取得して obj に保持します。

次に、obj から値を取り出して、LinearLayout 内の TextView に設定します。ここで定義する TextView には rowTextTitlerowTextSubtitle があります。

  • rowTextTitle

    タイトルとして、OBJECT_KEY(KiiObject の myObjectValue フィールド)の値を設定します。KiiObject の getString() メソッドによって、MyObject 1 のような値を文字列で取得できます。

  • rowTextSubtitle

    サブタイトルとして、KiiObject の URI を設定します。

    URI は Kii Cloud SDK において、アプリケーション内の KiiObject を一意に表現する文字列です。REST API では URI による表現を使用できません。

データの削除

一覧内で項目をタップすると、その項目を削除できます。項目の削除時には、確認メッセージを表示し、削除を実行する場合は次の performDelete() メソッドが実行されます。引数 position には、削除対象の項目のインデックス番号(0, 1, 2, …)が渡されます。

void performDelete(int position) {
  // Get the object to delete with the index number of the tapped row.
  final KiiObject o = MainActivity.this.mListAdapter.getItem(position);
  // Delete the object asynchronously.
  o.delete(new KiiObjectCallBack() {
    public void onDeleteCompleted(int token, Exception e) {
      if (e == null) {
        // Remove the object from the list adapter.
        MainActivity.this.mListAdapter.remove(o);
      } else {
        showToast("Error deleting object: " + e.getLocalizedMessage());
      }
    }
  });
}

実行している処理はここまで見てきた内容と同様です。mListAdapter から KiiObject を取り出し、ノンブロッキング API で Kii Cloud 上のデータを削除します。成功時は、項目を画面から削除します。


プログラムの説明は以上です。

Kii Cloud SDK の API を呼び出すだけでクラウド上のデータを操作できる点や、実装方法にはノンブロッキング API の呼び出しを利用するという特定のパターンがある点を理解できれば、他の機能も容易に実装できるはずです。


次は...

次は、リファレンスガイドを参照しながら機能を追加する手順を説明します。

プログラムの変更 に移動してください。

より詳しく学びたい方へ