キマグレラジオステーション

IT周りで勉強したことをぼんやり残してみます

Android-イベント記録アプリ制作10:リスト表示機能を作る

登録したデータを一覧表示する機能を追加します。

evereco_ucd_02.jpg

ユースケース的にこんな感じに拡張。

まずはデータを取得して加工するModelクラス

EventSelectModel

package jp.sheepman.evereco.model;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import jp.sheepman.evereco.bean.entity.BaseEntity;
import jp.sheepman.evereco.bean.entity.EventEntity;
import jp.sheepman.evereco.bean.form.EventListForm;
import jp.sheepman.evereco.util.DatabaseUtil;
import android.content.Context;

public class EventSelectModel extends BaseModel {
//検索用のSQL
final String sql = "SELECT * FROM event";

public List<EventListForm> selectAll(Context context){
//日付変換用のフォーマット
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//検索結果のコレクション
List<EventListForm> formlist = new ArrayList<EventListForm>();

DatabaseUtil util = new DatabaseUtil(context);
try {
//DBをオープン
util.open();
//SQLのパラメータ(全件検索するのでnull
String[] params = null;
//DatabaseUtilの検索メソッドでsqlを実行
//第三匹数はModelクラスをセットするので、自分をセット
List<BaseEntity> entitylist = util.select(sql, params, this);

//検索結果を処理
for(BaseEntity e : entitylist){
//日付
Date eventDate = sdf.parse(((EventEntity)e).getEvent_date());
//今日からの経過日数を算出
long dateDiff = ((new Date().getTime()) - eventDate.getTime())
/ (1000 * 60 * 60 * 24);
//表示用のFormオブジェクトに値をセット
EventListForm form = new EventListForm();
//DBのPK
form.setId(((EventEntity)e).getId());
//イベント名をセット
form.setEventName(((EventEntity)e).getEvent_name());
//イベント日付をセット
form.setEventDate(((EventEntity)e).getEvent_date());
//経過日数をセット
form.setDateDiff(String.valueOf(dateDiff));
//コレクションにadd
formlist.add(form);
}
} catch (ParseException e1) {
// TODO 自動生成された catch ブロック
e1.printStackTrace();
} finally {
util.close();
}
return formlist;
}

@Override
public BaseEntity getEntity() {
return new EventEntity();
}

}

やってることは単純に検索結果を受け取って、加工して呼び出し元のActivityに返すだけ。

DatabaseUtilに検索用のメソッドを追加。
ちょっと汎用的にしてみた。

DatabaseUtil#select

public List<BaseEntity> select(String sql, String[] params, BaseModel model){
List<BaseEntity> list = new ArrayList<BaseEntity>();
try{
Map<String, Method> map = new HashMap<String, Method>();
for(Method m : model.getEntity().getClass().getDeclaredMethods()){
if(m.getName().startsWith(KEYWORD_SETTER)){
map.put(m.getName()
.replaceFirst(KEYWORD_SETTER, "")
.toLowerCase(Locale.ENGLISH)
, m);
}
}

Cursor c = db.rawQuery(sql, params);
while(c.moveToNext()){
BaseEntity entity = model.getEntity();
for(int i = 0; i < c.getColumnCount(); i++){
String key = c.getColumnName(i)
.replaceFirst(KEYWORD_SETTER, "")
.toLowerCase(Locale.ENGLISH);
if(map.containsKey(key)){
Object value;
if(c.getType(i) == Cursor.FIELD_TYPE_BLOB){
value = c.getBlob(i);
} else if(c.getType(i) == Cursor.FIELD_TYPE_BLOB){
value = c.getBlob(i);
} else if(c.getType(i) == Cursor.FIELD_TYPE_FLOAT){
value = c.getFloat(i);
} else if(c.getType(i) == Cursor.FIELD_TYPE_INTEGER){
value = c.getInt(i);
} else if(c.getType(i) == Cursor.FIELD_TYPE_STRING){
value = c.getString(i);
} else if(c.getType(i) == Cursor.FIELD_TYPE_NULL){
value = null;
} else {
value = c.getString(i);
}
map.get(key).invoke(entity, value);
}
}
list.add(entity);
}
c.close();
} catch (IllegalAccessException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
}
return list;
}

Entityクラスは親クラスのBaseEntityをかえすようにして、
セットされたModelクラスのgetEntity()から使用する子クラスのEntityを取得。
そのクラスのプロパティに値を入れてListにして返却します。

プロパティの取得は、Entityクラスのsetterメソッドから自動判別。
これである程度汎用的になったかな。

あとは表示用のActivity。

ListActivity

package jp.sheepman.evereco;

import java.util.List;

import jp.sheepman.evereco.adapter.BaseCustomAdapter;
import jp.sheepman.evereco.bean.form.EventListForm;
import jp.sheepman.evereco.model.EventSelectModel;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class ListActivity extends Activity {

private ListView lvEventList;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list);

//ListViewを取得
lvEventList = (ListView)findViewById(R.id.lvEventList);
//ListViewのアイテム操作のためのアダプタ
EventListAdapter adapter = new EventListAdapter(this);
//ListViewにアダプタをセット
lvEventList.setAdapter(adapter);
//ListViewのアイテムをクリックした際のイベントをセット
lvEventList.setOnItemClickListener(lsnrEventListItem);

//イベント一覧となるformのリストを取得するModelクラスから取得する
EventSelectModel model = new EventSelectModel();
List list = model.selectAll(this);
//取得したformクラスをListViewに追加する
for(EventListForm form : list){
adapter.add(form);
}
//ListViewへの変更を反映させる
adapter.notifyDataSetChanged();
}

/**
* ListViewのアイテムをクリックしたときのイベントリスナ
*/
private OnItemClickListener lsnrEventListItem = new OnItemClickListener() {
@Override
public void onItemClick(AdapterView parent, View item, int position, long id) {
Toast.makeText(item.getContext() , "click", Toast.LENGTH_LONG).show();
}
};

/**
* ListViewのアイテムを操作するためのアダプタ
* @author sheepman
*/
private class EventListAdapter extends BaseCustomAdapter {
//レイアウトをViewに変換するインフレータ
private LayoutInflater inflater;

/**
* コンストラクタ
* @param context
*/
public EventListAdapter(Context context) {
super(context);
inflater = (LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);
}

@Override
public View getView(int position, View currentView, ViewGroup parent) {
EventListForm data = (EventListForm)list.get(position);

if(currentView == null){
currentView = inflater.inflate(R.layout.layout_list_row, null);
}
((TextView)currentView.findViewById(R.id.tvListEventDate)).setText(data.getEventDate());
((TextView)currentView.findViewById(R.id.tvListEventName)).setText(data.getEventName());
((TextView)currentView.findViewById(R.id.tvListDateDiff)).setText(data.getDateDiff());

currentView.setTag(data.getId());

return currentView;
}
}

}

ListViewに自作のAdapterでデータを流し込んであげます。
AdapterのgetViewメソッドをオーバーライドして、
受け取ったデータをセットした一行分のViewを作成してリターン。

レイアウトのXMLは以下。

activity_list.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="${relativePackage}.${activityClass}" >

<ListView
android:id="@+id/lvEventList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:dividerHeight="20dp"
/>
</RelativeLayout>


layout_list_row.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:tools="http://schemas.android.com/tools">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_alignParentBottom="true"
android:orientation="horizontal"
android:id="@+id/llListItemText"
>
<TextView
android:id="@+id/tvListEventDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="5"
android:height="50dp"
android:gravity="center" />

<TextView
android:id="@+id/tvListEventName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:height="50dp"
android:gravity="left|center_vertical"
/>
</LinearLayout>
<TextView
android:id="@+id/tvListDateDiff"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_marginRight="15dp"
android:gravity="center"
android:textSize="25sp"
/>
</RelativeLayout>


実行してこんなもん。
evereco_shot_list01.png




ブログランキング・にほんブログ村へ FC2Blog Ranking




テーマ:プログラミング - ジャンル:コンピュータ

  1. 2014/11/01(土) 11:48:00|
  2. Android
  3. | トラックバック:0
  4. | コメント:0
<<iOS 8.1.1をiPad2に入れたら息を吹き返した | ホーム | Android-イベント記録アプリ制作⑨:役割ごとにBeanを作る>>

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック

トラックバック URL
http://kimasute.blog.fc2.com/tb.php/14-d8c0faa2
この記事にトラックバックする(FC2ブログユーザー)