ListViewで表示する
ここからは集計結果をListViewに追加していく処理に進んでいきます。getTaskNameメソッドは引数として渡されたtaskIdを使い、taskオブジェクトを取得して、そこからtaskNameを取得、集計した時間(sumTime)とともにaddToListviewメソッドに引数として渡して、呼び出します(1)。
private void getTaskName(String taskId,final int sumTime) { NCMBQuery<NCMBObject> query = NCMBQuery.getQuery("TaskClass"); query.getInBackground(taskId, new GetCallback<NCMBObject>() { @Override public void done(NCMBObject task, NCMBException e) { if (e == null) { // 成功 addToListview(task.getString("taskName"),sumTime);(1) } else { // エラー } } }); } private void addToListview(String taskName,int sumTime) { int hour = sumTime / 60; int min = sumTime % 60; dataList.add(new SumLog(taskName,String.format("%4d",hour)+ "時間" + String.format("%02d",min)+"分"));(2) adapter.notifyDataSetChanged();(3) }
addToListviewメソッドはそのタスク名と集計した時間をListViewへ追加します。
以下は、ListViewに集計結果を追加した画像です。
これだけのことなのですが、このあとまだたくさんコードが出てきます。ListViewにタスク名と集計した時間を2列表示したいので、ListViewをカスタマイズしているからです。
本連載のテーマはMBaaSであるNCMBとの連携ですので、ListViewのカスタマイズについてはなるべくかいつまんで説明します。
addToListviewメソッドのなかで、SumLogクラスのオブジェクトをaddしているdataListはSumActivityの先頭で宣言しているSumLog型のListです(2)。このdataListがListViewの表示の元になります。
SumLogクラスはtaskNameとsumTimeプロパティを持ちます。
package jp.co.easier.stamptime; public class SumLog { String taskName; String sumTime; public SumLog(String taskName, String sumTime){ this.taskName = taskName; this.sumTime = sumTime; } public String getTaskName(){ return taskName; } public String getSumTime(){ return sumTime; } }
次に、adapterオブジェクトのnotifyDataSetChangedメソッドを呼び出していますが(3)、 adapterはSumLogAdapterクラスのオブジェクトです。
private class SumLogAdapter extends BaseAdapter { @Override public int getCount() {(1) return dataList.size(); } @Override public Object getItem(int position) {(2) return dataList.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView((3) int position, View convertView, ViewGroup parent) { TextView textView1; TextView textView2; View v = convertView; if(v==null){ LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); v = inflater.inflate(R.layout.row,null);(4) } SumLog sumLog = (SumLog)getItem(position);(5) if(sumLog != null){ textView1 = (TextView) v.findViewById(R.id.textView1); textView2 = (TextView) v.findViewById(R.id.textView2); textView1.setText(sumLog.taskName); textView2.setText(sumLog.sumTime); } return v; } }
SumLogAdapterクラスはSumActivityクラスのインナークラスであり、ListViewの基本的なアダプタであるBaseAdapterを継承しています。リスト8のSumActivityクラスのonCreateメソッドでlistView.setAdapter(adapter)として、listViewにこのadapterをセットしています(a)。
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(); } });
SumLogAdapterクラスの処理を読んでいくと、ListViewへのdataListからの表示の仕組みがわかります。
まず、SumLogAdapterクラスはSumActivityクラスのインナークラスなので、getCountメソッド(1)やgetItemメソッド(2)でdataListに直接アクセスできます。
ListViewの1行の見た目を作っているのが、getViewメソッドです(3)。getViewメソッドではinflater.inflateメソッドでR.layout.rowをインフレートします。inflateは訳すると「膨らます」という意味です。アクティビティのonCreateメソッドでよく使うsetContentView(R.layout.レイアウトファイル名)と同様の効果があります。
R.layout.rowはres/layoutに作成したrow.xmlです。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:textSize="20sp" android:id="@+id/textView1" android:layout_height="wrap_content" android:layout_width="240dp"/>(1) <TextView android:textSize="20sp" android:id="@+id/textView2" android:gravity="right"(2) android:layout_height="wrap_content" android:layout_width="wrap_content"/> </LinearLayout>
row.xmlがListViewの1行のレイアウトになります。一つめのTextViewにはlayout_width="240dp"を指定しています(1)。これがtaskNameを表示する幅になります。
集計した時間を表示するTextViewは、gravity="right"で右寄せしています(2)。
リスト17に戻りましょう。(SumLog)getItem(position)でdataListのSumLogオブジェクトを一つ取得することができます(5)。そこから、どちらも文字列であるtaskNameとsumTimeをTextViewにセットしています。
最後に
さて、今回はLogClassからレコードを抽出してタスクごとに費やした時間を集計する処理を作ってみました。Key-Value形式のレコードをキーブレイク処理で集計してみました。NCMBに集計クエリや更新クエリがあったら便利だなという感じはしましたが、それでも短いコードで集計ができました。
タスクタイマをアプリとして考えると、あと必要な機能は、もう使わなくなった古いタスク名の削除とそのTaskを関連オブジェクトとして持つLogClassのレコードの削除ですが、そこは各自で実装してください。次回はプッシュ通知を試してみたいと思います。