ListView+SimpleCursorAdapter練習
練習に郵便番号をリストビューに表示する。
元データはこちら。
http://www.post.japanpost.jp/zipcode/dl/kogaki-zip.html
ListView, SimpleCursorAdapter, SQLiteOpenHelper, AssetManager, CSVReaderあたり。
プロジェクト生成
プロジェクト名zipcodeとした。
$ mvn archetype:generate -DarchetypeArtifactId=android-quickstart -DarchetypeGroupId=de.akquinet.android.archetes [INFO] Scanning for projects... [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building Maven Stub Project (No POM) 1 [INFO] ------------------------------------------------------------------------ [INFO] [INFO] >>> maven-archetype-plugin:2.2:generate (default-cli) @ standalone-pom >>> [INFO] [INFO] <<< maven-archetype-plugin:2.2:generate (default-cli) @ standalone-pom <<< [INFO] [INFO] --- maven-archetype-plugin:2.2:generate (default-cli) @ standalone-pom --- [INFO] Generating project in Interactive mode [INFO] Archetype [de.akquinet.android.archetypes:android-quickstart:1.0.6] found in catalog remote Define value for property 'groupId': : jp.ousttrue.postcode Define value for property 'artifactId': : postcode Define value for property 'version': 1.0-SNAPSHOT: : Define value for property 'package': jp.ousttrue.postcode: : [INFO] Using property: android-plugin-version = 2.8.4 [INFO] Using property: emulator = not-specified [INFO] Using property: platform = 7 Confirm properties configuration: groupId: jp.ousttrue.zipcode artifactId: zipcode version: 1.0-SNAPSHOT package: jp.ousttrue.zipcode android-plugin-version: 2.8.4 emulator: not-specified platform: 7 Y: :
適当にgitとかに登録しながら進める。
レイアウト
レイアウト。リストがあれば十分。
res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <ListView android:id="@+id/list" android:layout_width="fill_parent" android:layout_height="fill_parent" /> </LinearLayout>
行のレイアウト。郵便番号と住所を表示する想定。
res/layout/row.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:id="@+id/zipcode" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/address" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout>
とりあえずビルド。
$ mvn install android:deploy
まだ空のリストがあるだけなので真っ黒になるだけ。
DBのフィールドを決める
http://www.post.japanpost.jp/zipcode/dl/readme.html
を見て1列から9列までを格納することにした。
CREATE TABLE IF NOT EXISTS zipcode ( _id integer primary key autoincrement, jis integer, old_zipcode text, zipcode text, prefectureKana text, cityKana text, townKana text, prefecture text, city text, town text );
実装
src/main/java/jp/ousttrue/zipcode/HelloAndroidActivity.java
を
src/main/java/jp/ousttrue/zipcode/ZipcodeActivity.java
に変える。
AndroidManifest.xml
<activity android:name=".ZipcodeActivity">
ZipcodeActivity.java
package jp.ousttrue.zipcode; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteDatabase; import android.database.Cursor; import android.view.View; import android.widget.ListView; import android.widget.SimpleCursorAdapter; import android.widget.TextView; import android.content.Context; import android.content.res.AssetManager; import au.com.bytecode.opencsv.CSVReader; import android.content.ContentValues; public class ZipcodeActivity extends Activity { private static String TAG = "zipcode"; /** * Called when the activity is first created. * @param savedInstanceState If the activity is being re-initialized after * previously being shut down then this Bundle contains the data it most * recently supplied in onSaveInstanceState(Bundle). <b>Note: Otherwise it is null.</b> */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.i(TAG, "onCreate"); setContentView(R.layout.main); // db ZipcodeOpenHelper helper = new ZipcodeOpenHelper(getApplicationContext(), "zpicode.db", 6); SQLiteDatabase db = helper.getReadableDatabase(); // adapter SimpleCursorAdapter adapter = new SimpleCursorAdapter(getApplicationContext(), R.layout.row, db.query("zipcode", null, null, null, null, null, null), new String[]{"zipcode", "prefecture"}, new int[]{R.id.zipcode, R.id.address}); adapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() { @Override public boolean setViewValue(View view, Cursor cursor, int columnIndex) { Log.d(TAG, "setViewValue: "+columnIndex); switch (columnIndex) { case 7: ((TextView)view).setText( cursor.getString(7)+cursor.getString(8)+cursor.getString(9)); return true; default: return false; } } }); ((ListView)findViewById(R.id.list)).setAdapter(adapter); } class ZipcodeOpenHelper extends SQLiteOpenHelper { public ZipcodeOpenHelper(Context context, String name, int version){ super(context, name, null, version); } @Override public void onCreate(SQLiteDatabase db){ Log.w(TAG, "create zipcode..."); db.execSQL( "CREATE TABLE IF NOT EXISTS zipcode ("+ " _id integer primary key autoincrement,"+ " jis integer,"+ " old_zipcode text,"+ " zipcode text,"+ " prefectureKana text,"+ " cityKana text,"+ " townKana text,"+ " prefecture text,"+ " city text,"+ " town text"+ ");" ); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){ Log.w(TAG, "drop zipcode"); db.execSQL("DROP TABLE IF EXISTS zipcode"); onCreate(db); } } }
とりあえずビルド。
$ mvn install android:deploy
まだDBが空なので真っ黒になるだけ。
assetsからのcsv読み込み
assets/13TOKYO.CSVを追加
はじめはKEN_ALL.CSVを読み込むつもりだったのだが、assetsには1M以上のファイルをおけないそうなので
とりあえずTOKYO13.CSVにした。
pom.xmlにCSVReader追加
<dependency> <groupId>net.sf.opencsv</groupId> <artifactId>opencsv</artifactId> <version>2.0</version> </dependency>
// 追加 import android.content.res.AssetManager; import au.com.bytecode.opencsv.CSVReader; import android.content.ContentValues; // onCreate(SQLiteDatabase db)のCREATE TABLEの後に追記 AssetManager as = getResources().getAssets(); java.io.InputStream is; try{ is = as.open("13TOKYO.CSV"); } catch(java.io.IOException e){ Log.e(TAG, "fail to open csv"); return; } CSVReader csv; try{ csv = new CSVReader(new java.io.InputStreamReader(is, "SJIS")); Log.d(TAG, "each lines..."); String[] line; while ((line = csv.readNext()) != null) { ContentValues cv = new ContentValues(); cv.put("jis", line[0]); cv.put("old_zipcode", line[1]); cv.put("zipcode", line[2]); cv.put("prefectureKana", line[3]); cv.put("cityKana", line[4]); cv.put("townKana", line[5]); cv.put("prefecture", line[6]); cv.put("city", line[7]); cv.put("town", line[8]); db.insert("zipcode", "", cv); } csv.close(); is.close(); } catch(java.io.UnsupportedEncodingException e){ Log.e(TAG, "UnsupportedEncodingException"); return; } catch(java.io.IOException e){ Log.e(TAG, "csv error"); return; }
ビルド。
$ mvn install android:deploy
リスト表示成功。
(追記)assetsからzipファイルの読み込み
import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; AssetManager as = getResources().getAssets(); try{ java.io.InputStream is = as.open("13tokyo.zip"); Log.d(TAG, "open 13tokyo.zip"); ZipInputStream zip=new ZipInputStream(is); ZipEntry zipEntry; while( (zipEntry = zip.getNextEntry()) != null ){ Log.d(TAG, "zipEntry: "+zipEntry.getName()); CSVReader csv=new CSVReader(new InputStreamReader(zip, "SJIS")); Log.d(TAG, "each lines..."); String[] line; while ((line = csv.readNext()) != null) { ContentValues cv = new ContentValues(); cv.put("jis", line[0]); cv.put("old_zipcode", line[1]); cv.put("zipcode", line[2]); cv.put("prefectureKana", line[3]); cv.put("cityKana", line[4]); cv.put("townKana", line[5]); cv.put("prefecture", line[6]); cv.put("city", line[7]); cv.put("town", line[8]); db.insert("zipcode", "", cv); } csv.close(); } zip.close(); } catch(java.io.UnsupportedEncodingException e){ Log.e(TAG, e.getMessage()); return; } catch(java.io.IOException e){ Log.e(TAG, e.getMessage()); return; }