クエリを組み立てる
SumActivityは、MainActivityから呼びされる集計処理用アクティビティです。レイアウトファイルはactivity_sum.xmlです(1)。
public class SumActivity extends Activity {
private TextView mTextFrom;
private TextView mTextTo;
private RadioGroup mRgSum;
private List<SumLog> dataList = new ArrayList<SumLog>();
private SumLogAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO 自動生成されたメソッド・スタブ
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sum);(1)
mTextFrom = (TextView)findViewById(R.id.textViewFrom);
mTextTo = (TextView) findViewById(R.id.textViewTo);
mRgSum = (RadioGroup) findViewById(R.id.rgSum);
ListView listView = (ListView) findViewById(R.id.listView1);
adapter = new SumLogAdapter();
listView.setAdapter(adapter);(a)
Calendar calendar = Calendar.getInstance();(2)
final int year = calendar.get(Calendar.YEAR);
final int month = calendar.get(Calendar.MONTH);
final int day = calendar.get(Calendar.DAY_OF_MONTH);
// 開始日付を選択
Button btnFrom = (Button) findViewById(R.id.buttonFrom);
btnFrom.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// DatePickerDialogを表示
DatePickerDialog datePickerDialog = new DatePickerDialog(
SumActivity.this,
new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker picker, int year, int month, int day) {
mTextFrom.setText(String.format("%04d",year) + "-" + (3)
String.format("%02d",month + 1) + "-" +
String.format("%02d",day));
}
},
year,
month,
day);
datePickerDialog.show();
}
});
onCreateメソッドでは、それぞれのボタンが押されたときの処理を指定しています。ざっと、みていきましょう。Calendar.getInstance()でCalendarオブジェクトを取得します(2)。Calendarオブジェクトには現在の日時が入っていますので、年、月、日を取り出します。
開始日付を選択のボタンが押されたら、DatePickerDialogを生成します。引数はcontext、callBack、year(年の初期値)、monthOfYear(月の初期値)、dayOfMonth(日の初期値)です。callBackには、OnDateSetListenerを指定します。ダイアログ上の設定ボタンを押したときにonDateSetメソッドが呼び出されます。onDateSetメソッドでは、年を4桁、月を2桁、日を2桁に0埋めし、ハイフンで接続します(3)。
終了日付の選択処理も同様です。
// 終了日付を選択
Button btnTo = (Button) findViewById(R.id.buttonTo);
btnTo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// DatePickerDialogを表示
DatePickerDialog datePickerDialog = new DatePickerDialog(
SumActivity.this,
new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker picker, int year, int month, int day) {
mTextTo.setText(String.format("%04d",year) + "-" +
String.format("%02d",month + 1) + "-" +
String.format("%02d",day));
}
},
year,
month,
day);
datePickerDialog.show();
}
});
集計実行ボタンが押された場合の処理をみていきましょう(4)。
Button btnSum = (Button) findViewById(R.id.buttonSum);
btnSum.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {(4)
dataList.clear();
int id = mRgSum.getCheckedRadioButtonId();(5)
// LogClassの読み込み
NCMBQuery<NCMBObject> query = NCMBQuery.getQuery("LogClass");(6)
query.orderByAscending("task");
if (id == R.id.rbMeOnly) {(7)
//自分だけ
NCMBUser currentUser = NCMBUser.getCurrentUser();
query.whereEqualTo("UserName", currentUser.getUsername());
}
RadioGroupオブジェクトのmRgSumのgetCheckedRadioButtonIdメソッドで、チェックされているRadioButtonを取得します(5)。
NCMBQuery.getQueryメソッドでLogClassに対するクエリを作成します(6)。query.orderByAscendingでtaskフィールドの昇順に並び替えます。
逆に降順で並び替えたいときはorderByDescendingを指定します。複数の並び替え条件を指定したいときは、addAscendingOrderやaddDescendingOrderを使います。
| 昇順で並び替え | orderByAscending("フィールド名") |
|---|---|
| 降順で並び替え | orderByDescending("フィールド名") |
| 昇順の条件追加 | addAscendingOrder("フィールド名") |
|---|---|
| 降順の条件追加 | addDescendingOrder("フィールド名") |
チェックされているRadioButtonのIDが自分(R.id.rbMeOnly)のときは(7)、ログインしているユーザーを取得し、ユーザー名をクエリのwhereEqualTo条件に指定しています。whereEqualToは指定した値と等しいフィールド値を持つレコードを抽出する条件です。
さて、その次の日付の処理には注意が必要です。
LogClassのstartTimeフィールドなどをみるとわかるようにNCMBのデータストアオブジェクトの日付はyyyy-mm-ddTHH:MM:ss.SSSZ形式(SSSはミリ秒、Zはタイムゾーン)のUTC(世界協定時)の日付です。タイムゾーンはUTC以外を設定することはできません。ですから、日本時間とは9時間ずれています。
// 開始日付が入力されていたら
if (mTextFrom.getText().length() > 9) {
String strFrDate = mTextFrom.getText().toString();(8)
String strFrTime = "T00:00:00.000";
Date fromDate = cvtStringToDate(strFrDate + strFrTime);
query.whereGreaterThanOrEqualTo("startTime", fromDate);(9)
}
開始日付が入力されている場合は、TextViewから日付を取得します(8)。先ほど説明したようにTextViewの日付はyyyy-mm-ddという形式になっています。これにTをはさんで、開始時間ですから、00:00:00.000を連結して、cvtStringToDate関数に渡します。
static public final String DATE_PATTERN ="yyyy-MM-dd'T'HH:mm:ss";
// String型のオブジェクトをDate型に変換します.
public Date cvtStringToDate(String strDate) {
try {
return (new SimpleDateFormat(DATE_PATTERN,Locale.JAPAN)).parse(strDate);
} catch (ParseException e) {
return null;
}
}
cvtStringToDateは、SimpleDateFormat関数にDATE_PATTERNとロケールにJAPANを指定して、引数として渡した日付文字列を日付に変換します。
この日付をstartTimeにwhereGreaterThanOrEqualTo条件で指定します(9)。
以下の表のように、whereGreaterThanOrEqualToは大きいか、等しいなので「以上」を意味します。
| 等しい | whereEqualTo("フィールド名",値) |
|---|---|
| 等しくない | whereNotEqualTo("フィールド名",値) |
| 小さい | whereLessThan("フィールド名",値) |
| 以下 | whereLessThanOrEqualTo("フィールド名",値) |
| 大きい | whereGreaterThan("フィールド名",値) |
| 以上 | whereGreaterThanOrEqualTo("フィールド名",値) |
終了日付が入力されている場合は、その逆です。
// 終了日付が入力されていたら
if (mTextTo.getText().length() > 9) {
String strToDate = mTextTo.getText().toString();
String strToTime = "T23:59:59.999";(10)
Date toDate = cvtStringToDate(strToDate + strToTime);
query.whereLessThanOrEqualTo("startTime", toDate);(11)
}
一日の終わりの時間を文字列として指定して(10)、TextViewの日付文字列に連結して日付に変換します。そして、whereLessThanOrEqualTo(以下)条件に指定します(11)。
検索条件が整ったら、findInBackgroundメソッドで非同期にレコードを取得します(12)。
query.findInBackground(new FindCallback<NCMBObject>() {(12)
@Override
public void done(List<NCMBObject> result, NCMBException e){
String new_key="";
String old_key="";
int sumTime =0;
for (int i =0 ,n = result.size(); i < n; i++ ) {
NCMBObject logdata = result.get(i);(13)
// ObjectIdだけなら以下でも取れる
NCMBObject task = logdata.getNCMBObject("task");
new_key=task.getObjectId();(14)
if (i==0) {
old_key = new_key;
}
if (!new_key.equals(old_key)) {
getTaskName(old_key,sumTime);(15)
old_key = new_key;
sumTime=0;
}
sumTime += logdata.getInt("elapsedTime");
}
getTaskName(old_key,sumTime);(16)
}
});
条件に合うレコードが取得できたら、doneメソッドが呼び出されます。
取得したレコードはNCMBObject型のListであるresultに格納されていますので、result.get(i)で一つずつ取り出して(13)、キーブレイク処理で経過時間(elapsedTime)を集計します。
キーに指定しているのは関連オブジェクトtaskのObjectIdです。通常、関連オブジェクトのフィールド値はfetchIfNeededInBackgroundメソッドなどで別途取得する必要があるのですが、ObjectIdはtask.getObjectId()のように取得することができます(14)。
キーが割れたら、getTaskNameメソッドを呼び出すだけでなく、最後のレコードを処理した後でもgetTaskNameメソッドを呼び出します(15)(16)。

