本例代碼以SQLite為數據存取載體。
在"SharedPreferences篇"中,已知數據的自動存儲原理是使用Java反射的方法獲取數據實體類中的Field進行的存儲的。
當以SQLite為數據存取載體時,需要解決一個問題是:如何標明類中的某個Field是primary key(主鍵)呢。
為解決此問題,此處引入並使用瞭Java Annotation(內註)。Annotation可以保留一些自定義的註釋信息並且這些可以在被編譯後仍保留著甚至被JVM運行時獲取。相應文章請查看:[Java] Annotation(內註)實例一則
本示例代碼實現瞭一個Mark Annotation(標記內註),用於修飾Field標明其為主鍵。
被修飾的主鍵將影響自動生成的sql執行語句。如下代碼:
[java]
/** 根據類結構構造表。 */
private String getTableBuildingSQL(Class<?> clazz) {
StringBuilder strBuilder = new StringBuilder("create table if not exists ");
strBuilder.append(clazz.getSimpleName());
strBuilder.append("(");
// getDeclaredFields():隻獲取該類文件中聲明的字段
// getFields():獲取該類文件、其父類、接口的聲明字段
Field[] arrField = clazz.getFields();
for (int i = arrField.length – 1; i >= 0; i–) {
Field f = arrField[i];
String type = TYPES.get(f.getType());
if (type == null) {
continue;
} else {
strBuilder.append(f.getName() + " " + type);
if (f.isAnnotationPresent(primary.class)) {
strBuilder.append(" PRIMARY KEY");
}
if (i > 0) {
strBuilder.append(",");
}
}
}
strBuilder.append(")");
return strBuilder.toString();
}
其餘的代碼是普通的SQLite操作及與“SharedPreferences篇”中的處理手法一致。不再冗述。
本文為Sodino所有,轉載請註明出處:http://blog.csdn.net/sodino/article/details/7996088
上代碼:lab.sodino.autosave.annotation.primary
[java]
package lab.sodino.autosave.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface primary {
}
lab.sodino.autosave.db.DBHelper
[java]
package lab.sodino.autosave.db;
import java.io.File;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import lab.sodino.autosave.GoodsBean;
import lab.sodino.autosave.LogOut;
import lab.sodino.autosave.annotation.primary;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class DBHelper extends SQLiteOpenHelper {
private SQLiteDatabase sqlDb;
public static final int VERSION = 1;
public static final Map<Class<?>, String> TYPES;
static {
TYPES = new HashMap<Class<?>, String>();
TYPES.put(byte.class, "BYTE");
TYPES.put(boolean.class, "INTEGER");
TYPES.put(short.class, "SHORT");
TYPES.put(int.class, "INTEGER");
TYPES.put(long.class, "LONG");
TYPES.put(String.class, "TEXT");
TYPES.put(byte[].class, "BLOB");
TYPES.put(float.class, "FLOAT"); // REAL
TYPES.put(double.class, "DOUBLE"); // REAL
}
public DBHelper(Context context) {
super(context, context.getPackageName(), null, VERSION);
File dbFile = context.getDatabasePath(context.getPackageName());
if (dbFile.exists() == false) {
LogOut.out(this, "DBFile does not exist.");
// 去調用onCreate()和onUpgrade()建表
getWritableDatabase();
// initAllDBItem();
close();
LogOut.out(this, "InitDB finished!!!");
} else {
LogOut.out(this, "DBFile does exist.");
}
}
public void openDBHelper() {
sqlDb = getWritableDatabase();
}
public void close() {
if (sqlDb != null) {
sqlDb.close();
}
super.close();
}
@Override
public void onCreate(SQLiteDatabase db) {
String sqlTableBuilding = getTableBuildingSQL(GoodsBean.class);
LogOut.out(this, "sql[" + sqlTableBuilding + "]");
db.execSQL(sqlTableBuilding);
}
/** 根據類結構構造表。 */
private String getTableBuildingSQL(Class<?> clazz) {
StringBuilder strBuilder = new StringBuilder("create table if not exists ");
strBuilder.append(clazz.getSimpleName());
strBuilder.append("(");
// getDeclaredFields():隻獲取該類文件中聲明的字段
// getFields():獲取該類文件、其父類、接口的聲明字段
Field[] arrField = clazz.getFields();
for (int i = arrField.length – 1; i >= 0; i–) {
Field f = arrField[i];
String type = TYPES.get(f.getType());
if (type == null) {
continue;
} else {
strBuilder.append(f.getName() + " " + type);
if (f.isAnnotationPresent(primary.class)) {
strBuilder.append(" PRIMARY KEY");
}
if (i > 0) {
strBuilder.append(",");
}
}
}
strBuilder.append(")");
return strBuilder.toString();
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
LogOut.out(this, "onUpgrade");
String sql = "drop table if exists" + GoodsBean.class.getSimpleName();
db.execSQL(sql);
}
public int insert(GoodsBean bean) {
int row = -1;
row = (int) sqlDb.insert(GoodsBean.class.getSimpleName(), null, GoodsBean.translate2ContentValues(bean));
LogOut.out(this, "row=" + row);
return row;
}
public GoodsBean query() {
Cursor cursor = sqlDb.rawQuery("select * from " + GoodsBean.class.getSimpleName(), null);
GoodsBean bean = GoodsBean.cursor2GoodsBean(cursor);
cursor.close();
return bean;
}
}
lab.sodino.autosave.ActAutoSave
[java]
package lab.sodino.autosave;
import lab.sodino.autosave.db.DBHelper;
import lab.sodino.autosave_sqlite.R;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class ActAutoSave extends Activity implements OnClickListener {
private DBHelper dbHelper;
private Button btnAction;
private GoodsBean goodsBean;
private TextView txtDetail, txtRead;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.act_auto_save);
LogOut.out(this, "onCreate");
dbHelper = new DBHelper(this);
btnAction = (Button) findViewById(R.id.btnAction);
btnAction.setOnClickListener(this);
txtDetail = (TextView) findViewById(R.id.txtDetail);
txtRead = (TextView) findViewById(R.id.txtRead);
goodsBean = GoodsBean.newInstance();
txtDetail.setText(goodsBean.toString());
}
public void onClick(View v) {
if (v == btnAction) {
doSave(goodsBean);
GoodsBean beanRead = doRead();
showReadBean(beanRead);
}
}
private void showReadBean(GoodsBean bean) {
txtRead.setText(bean.toString());
}
private GoodsBean doRead() {
dbHelper.openDBHelper();
GoodsBean bean = dbHelper.query();
return bean;
}
private void doSave(GoodsBean bean) {
dbHelper.openDBHelper();
dbHelper.insert(bean);
dbHelper.close();
}
}
lab.sodino.autosave.GoodsBean
[java]
package lab.sodino.autosave;
import java.lang.reflect.Field;
import android.content.ContentValues;
import android.database.Cursor;
import lab.sodino.autosave.annotation.primary;
public class GoodsBean {
@primary
/** 標明瞭是主鍵*/
public long _id;
public String name;
public int price;
public boolean isPaid;
/** 測試用。 */
public byte testByte;
public byte[] arrByte;
/** 測試用。 */
public short testShort;
public float cicle;
public double testDouble;
public String toString() {
StringBuffer strBuffer = new StringBuffer();
strBuffer.append("_id[" + _id + "]\n");
strBuffer.append("name[" + name + "]\n");
strBuffer.append("price[" + price + "]\n");
strBuffer.append("isPaid[" + isPaid + "]\n");
strBuffer.append("cicle[" + cicle + "]\n");
strBuffer.append("testByte[" + testByte + "]\n");
strBuffer.append("arrByte.len[" + (arrByte == null ? "N/A" : arrByte.length) + "]\n");
strBuffer.append("testShort[" + testShort + "]\n");
strBuffer.append("testDouble[" + testDouble + "]\n");
return strBuffer.toString();
}
public static GoodsBean newInstance() {
GoodsBean bean = new GoodsBean();
bean._id = 128l;
bean.name = "AutoSave";
bean.price = 1024;
bean.isPaid = true;
bean.cicle = 2.356f;
bean.arrByte = new String("SodinoArrBytes").getBytes();
bean.testByte = 8;
bean.testShort = 128;
bean.testDouble = 9856.2145d;
return bean;
}
public static ContentValues translate2ContentValues(GoodsBean bean) {
ContentValues cv = new ContentValues();
Field[] arrField = GoodsBean.class.getFields();
try {
for (Field f : arrField) {
if (f.isAccessible() == false) {
f.setAccessible(true);
}
String name = f.getName();
Object value = f.get(bean);
LogOut.out(GoodsBean.class.getName(), "name:" + name + " " + String.valueOf(value));
if (value instanceof Byte) {
cv.put(name, (Byte) value);
} else if (value instanceof Short) {
cv.put(name, (Short) value);
} else if (value instanceof Integer) {
cv.put(name, (Integer) value);
} else if (value instanceof Long) {
cv.put(name, (Long) value);
} else if (value instanceof String) {
cv.put(name, (String) value);
} else if (value instanceof byte[]) {
cv.put(name, (byte[]) value);
} else if (value instanceof Boolean) {
cv.put(name, (Boolean) value);
} else if (value instanceof Float) {
cv.put(name, (Float) value);
} else if (value instanceof Double) {
cv.put(name, (Double) value);
}
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return cv;
}
public static GoodsBean cursor2GoodsBean(Cursor cursor) {
GoodsBean bean = new GoodsBean();
if (cursor.isBeforeFirst()) {
cursor.moveToFirst();
}
Field[] arrField = GoodsBean.class.getFields();
try {
for (Field f : arrField) {
String columnName = f.getName();
int columnIdx = cursor.getColumnIndex(columnName);
if (columnIdx != -1) {
if (f.isAccessible()) {
f.setAccessible(true);
}
Class<?> type = f.getType();
if (type == byte.class) {
f.set(bean, (byte) cursor.getShort(columnIdx));
} else if (type == short.class) {
f.set(bean, cursor.getShort(columnIdx));
} else if (type == int.class) {
f.set(bean, cursor.getInt(columnIdx));
} else if (type == long.class) {
f.set(bean, cursor.getLong(columnIdx));
} else if (type == String.class) {
f.set(bean, cursor.getString(columnIdx));
} else if (type == byte[].class) {
f.set(bean, cursor.getBlob(columnIdx));
} else if (type == boolean.class) {
f.set(bean, cursor.getInt(columnIdx) == 1);
} else if (type == float.class) {
f.set(bean, cursor.getFloat(columnIdx));
} else if (type == double.class) {
f.set(bean, cursor.getDouble(columnIdx));
}
}
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return bean;
}
}