クエリを組み立てる
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)。