【Android数据库优化】利用注解实现SQLite通用框架抽取

在开发Android应用的过程中,少不了要用到SQLite数据库操作,各种增删查改。。。一般看来,对于不同的实体类的数据库操作,貌似我们只能使用不同的“增删查改”方法来实现,本次的想法就是,能不能抽取出一个通用的框架,使得对于不同的实体类的数据库操作,可以使用同一个接口的实现来做。。。废话少说,进入正题。

一、普通的数据库操作的实现

现在有一个Book的类,里面有三个成员变量,id,tittle和summary,其中id将会作为主键,且自增。Book代码如下:

package com.alex.db.domain;

public class Book {
	private int id;
	private String tittle;
	private String summary;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getTittle() {
		return tittle;
	}

	public void setTittle(String tittle) {
		this.tittle = tittle;
	}

	public String getSummary() {
		return summary;
	}

	public void setSummary(String summary) {
		this.summary = summary;
	}

	@Override
	public String toString() {
		return "Book [id=" + id + ", tittle=" + tittle + ", summary=" + summary
				+ "]";
	}

	public Book(int id, String tittle, String summary) {
		super();
		this.id = id;
		this.tittle = tittle;
		this.summary = summary;
	}

	public Book() {
		super();
	}

}

一般来说,都会使用SQLiteOpenHelper这个类来打开/创建 一个数据库,这里也一样,我们创建一个DBHelper的类来继承SQLiteOpenHelper,并在DBHelper放入一些public的常量,来代表数据库要创建的表名,表里的字段名,以供使用。

package com.alex.db.dao;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;

public class DBHelper extends SQLiteOpenHelper {

	private static final String NAME = "my.db";
	private static final CursorFactory FACTORY = null;
	private static final int VERSION = 1;

	public static final String COLUMN_ID = "_id";
	public static final String COLUMN_TITLE = "title";
	public static final String COLUMN_SUMMARY = "summary";
	public static final String TABLE_BOOK_NAME = "books";

	public DBHelper(Context context) {
		super(context, NAME, FACTORY, VERSION);
	}

	@Override
	public void onCreate(SQLiteDatabase db) {
		String sql = "create table " + TABLE_BOOK_NAME + "(" + COLUMN_ID
				+ " integer primary key autoincrement," + COLUMN_TITLE
				+ " varchar(50)," + COLUMN_SUMMARY + " varchar(200));";

		System.out.println("sql=" + sql);

		db.execSQL(sql);
	}

	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		// TODO Auto-generated method stub

	}

}

到此,就可以来进行数据库操作了,一般的,我们会写一个IBookDao的接口,里面包含“增删查改”等方法;然后再写一个实现类BookDaoImpl的实现类来实现这个接口,这样能达到隔离业务的目的。为了简便,我们这里查找暂时只实现findAll(全部查找无条件限制)。

IBookDao:

package com.alex.db.dao;

import java.util.List;

import com.alex.db.domain.Book;

public interface IBookDao {

	/**
	 * 插入一个条目
	 *
	 * @param book
	 * @return
	 */
	long insert(Book book);

	/**
	 * 根据id来删除一个条目
	 *
	 * @param id
	 * @return
	 */
	int delete(int id);

	/**
	 * 更新一个条目
	 *
	 * @param book
	 * @return
	 */
	int update(Book book);

	/**
	 * 查找所有的表中的所有条目,并且返回一个List集合
	 *
	 * @return
	 */
	List<Book> findAll();

}

BookDaoImpl实现类:

package com.alex.db.dao.impl;

import java.util.ArrayList;
import java.util.List;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import com.alex.db.dao.DBHelper;
import com.alex.db.dao.IBookDao;
import com.alex.db.domain.Book;

public class BookDaoImpl implements IBookDao {

	private Context context;
	private DBHelper helper;
	private SQLiteDatabase db;

	public BookDaoImpl(Context context) {
		this.context = context;

		helper = new DBHelper(context);
		db = helper.getWritableDatabase();
	}

	public long insert(Book book) {
		ContentValues values = new ContentValues();

		// values.put(DBHelper.COLUMN_ID, book.getId());//这一句不要,因为id是主键且自增
		values.put(DBHelper.COLUMN_TITLE, book.getTittle());
		values.put(DBHelper.COLUMN_SUMMARY, book.getSummary());
		return db.insert(DBHelper.TABLE_BOOK_NAME , null, values);
	}

	@Override
	public int delete(int id) {

		return db.delete(DBHelper.TABLE_NAME, DBHelper.COLUMN_ID + "=?",
				new String[] { String.valueOf(id) });
	}

	@Override
	public int update(Book book) {
		ContentValues values = new ContentValues();
		values.put(DBHelper.COLUMN_SUMMARY, book.getSummary());
		values.put(DBHelper.COLUMN_TITLE, book.getTittle());
		return db.update(DBHelper.TABLE_NAME, values,
				DBHelper.COLUMN_ID + "=?",
				new String[] { String.valueOf(book.getId()) });
	}

	@Override
	public List<Book> findAll() {

		List<Book> books = null;

		Cursor cursor = db.query(DBHelper.TABLE_NAME, null, null, null, null,
				null, null);

		if (cursor != null && cursor.getCount() > 0) {
			books = new ArrayList<Book>();
			while (cursor.moveToNext()) {
				Book book = new Book();

				book.setId(cursor.getInt(cursor
						.getColumnIndex(DBHelper.COLUMN_ID)));

				book.setSummary(cursor.getString(cursor
						.getColumnIndex(DBHelper.COLUMN_SUMMARY)));

				book.setTittle(cursor.getString(cursor
						.getColumnIndex(DBHelper.COLUMN_TITLE)));

				books.add(book);
			}
		}

		return books;
	}
}

至此,基本的一个数据库操作就构建完毕了,写一个简单的TestCase来看看:

package com.alex.db.test;

import java.util.List;

import com.alex.db.dao.IBookDao;
import com.alex.db.dao.impl.BookDaoImpl;
import com.alex.db.domain.Book;

import android.test.AndroidTestCase;

public class DBTest extends AndroidTestCase {

	public void testDB() {
		IBookDao bookDao = new BookDaoImpl(getContext());

		bookDao.insert(new Book(0, "测试标题一", "测试摘要一"));
		bookDao.insert(new Book(0, "测试标题二", "测试摘要二"));
		bookDao.insert(new Book(0, "测试标题三", "测试摘要三"));

		List<Book> books = bookDao.findAll();

		for (Book item : books) {
			System.out.println(item.toString());
		}

		System.out.println("------删除操作分割线------");

		bookDao.delete(3);

		books = bookDao.findAll();

		for (Book item : books) {
			System.out.println(item.toString());
		}

	}
}

结果:

二、抽取通用框架要解决的问题:

经过上面的工作,我们基本可以实现Book类的数据库操作了,但是如果现在多出来一个别的类,比如News类,如果按照之前的思路就不得不重新写一套数据库操作接口及其实现类了。但是我们现在不想这样做,我们想抽取一个框架来,让别的类News也能通过它来实现基本数据库的操作。怎么做呢?

既然需要用到不同的类,那么就势必要用到泛型。思路是:

a、写一个带泛型的接口IDaoSupport<M>来让IBookDao去extends;

b、写一个带泛型的抽象类DaoSupportImpl<M> implements IDaoSupport<M>,然后让我们的实现类BookDaoImpl extends DaoSupportImpl<Book>;

1、IDaoSupport<M>

对于第一点而言,实现起来比较简单,可以简单的将IBookDao里的内容 剪切之后,将Book改为泛型M,然后粘贴到 IDaoSupport<M>中。但是要注意一点,原来的int delete(int id);方法,参数id是int类型的主键,但是不一定所有的类都是integer类型作为主键,也有可能是String或者long等类型的,我们可以去数据手册上翻看一下integer,string和long这三个类,会发现他们都实现了Serializable这个接口:

所以,这里选择Serializable来作为id的类型。

IDaoSupport<M>:

package com.alex.db.dao.base;

import java.io.Serializable;
import java.util.List;

import com.alex.db.domain.Book;

public interface IDaoSupport<M> {
	/**
	 * 插入一个条目
	 *
	 * @param book
	 * @return
	 */
	long insert(M m);

	/**
	 * 根据id来删除一个条目
	 *
	 * @param id
	 * @return
	 */
	int delete(Serializable id);

	/**
	 * 更新一个条目
	 *
	 * @param book
	 * @return
	 */
	int update(M m);

	/**
	 * 查找所有的表中的所有条目,并且返回一个List集合
	 *
	 * @return
	 */
	List<M> findAll();
}

IBookDao:

package com.alex.db.dao;

import com.alex.db.dao.base.IDaoSupport;
import com.alex.db.domain.Book;

public interface IBookDao extends IDaoSupport<Book> {

}

2、DaoSupportImpl<M>

先来看一下继承关系:public class BookDaoImpl extends DaoSupportImpl<Book> implements IBookDao

DaoSupportImpl<M>将要作为所有实体类数据库操作实现的一个公共类,所以原来在BookDaoImpl中的增删查改方法,还有一些成员变量都要放到DaoSupportImpl<M>里面去。但是在这里,不能单纯的剪切粘贴了,有一些麻烦的问题需要解决,我们一个个的来看是些什么问题:

对于insert和delete方法:

	public long insert(Book book) {
		ContentValues values = new ContentValues();

		// values.put(DBHelper.COLUMN_ID, book.getId());//这一句不要,因为id是主键且自增
		values.put(DBHelper.COLUMN_TITLE, book.getTittle());
		values.put(DBHelper.COLUMN_SUMMARY, book.getSummary());
		return db.insert(DBHelper.TABLE_BOOK_NAME, null, values);
	}
	@Override
	public int delete(Serializable id) {

		return db.delete(DBHelper.TABLE_BOOK_NAME, DBHelper.COLUMN_ID + "=?",
				new String[] { String.valueOf(id) });
	}

如果一旦改为

public long insert(M m)

那么:

(一)、如何知道M对应的那个表的表名?

我们知道每个实体类一般都会对应一个单独的表,比如Book对应books表,News对应news表;而上面是使用的DBHelper.TABLE_BOOK_NAME来获取的,这显然不合适,因为不可能每个实体类对应的表名都用DBHelper.TABLE_BOOK_NAME来获取,关键在于DaoSupportImpl<M>里,我们只有泛型M,而不知道具体是哪个实体类。

(二)、如何将实体中的数据,按照对应关系导入到数据库表中?

对于上面的insert操作,会将title,summary的内容导入数据库中,那么对于别的实体类呢?它们不一定是这几个成员变量,如何确定实体类的Field和数据库表中的字段的对应关系?

对于update和findAll方法:

@Override
	public int update(Book book) {
		ContentValues values = new ContentValues();
		values.put(DBHelper.COLUMN_SUMMARY, book.getSummary());
		values.put(DBHelper.COLUMN_TITLE, book.getTittle());
		return db.update(DBHelper.TABLE_BOOK_NAME, values,
				DBHelper.COLUMN_ID + "=?",
				new String[] { String.valueOf(book.getId()) });
	}

	@Override
	public List<Book> findAll() {

		List<Book> books = null;

		Cursor cursor = db.query(DBHelper.TABLE_BOOK_NAME, null, null, null, null,
				null, null);

		if (cursor != null && cursor.getCount() > 0) {
			books = new ArrayList<Book>();
			while (cursor.moveToNext()) {
				Book book = new Book();

				book.setId(cursor.getInt(cursor
						.getColumnIndex(DBHelper.COLUMN_ID)));

				book.setSummary(cursor.getString(cursor
						.getColumnIndex(DBHelper.COLUMN_SUMMARY)));

				book.setTittle(cursor.getString(cursor
						.getColumnIndex(DBHelper.COLUMN_TITLE)));

				books.add(book);
			}
		}

		return books;
	}

出去上面两个问题之外,还需要解决三个问题:

(三)、如何将数据表中列的数据,按照对应关系导入到实体中

这个问题跟问题二是相反的过程,在于update时从数据库中拿数据的过程

(四)、明确实体中主键,获取到主键中封装的值

对于update方法,参数为一个对象,我们要拿到对象中的主键,然后才能去数据库中查到需要更新的那个对应的条目。

(五)、实体的对象创建

findAll方法返回一个List<M>,而对应的M的对象要如何创建呢?

三、问题的解决

下面就是要解决的五个问题:

	// 问题一:表名的获取
	// 问题二:如何将实体中的数据,按照对应关系导入到数据库表中
	// 问题三:如何将数据表中列的数据,按照对应关系导入到实体中
	// 问题四:明确实体中主键,获取到主键中封装的值
	// 问题五:实体的对象创建

问题一:表名的获取

如何获得实体类对应的表名,有两种方案:

1、如果能够获取到实体,获取都该实体的简单名称,然后将首字母小写,比如Book类,取表名为book,News类,取表名为news

这种方法是可行的,但是有其局限性,我们需要在刚写代码的时候,就将数据库的表名也一起定好,而且不方便改动,如果一旦中途改了类名,那么数据库的表名也要改。。。

2、利用注解来获得实体类对应的表名,让实体名和数据库表名脱离关系。

这种方法比较合适,通用,但是需要用到注解。下面就来看看如何利用注解来获得实体类对应的表名吧:

实际上,要解决问题一,需要先解决问题五:如何获得实体类对象的问题,显然不能用new来获得M m = new M();这里暂时用getInstance()方法来代替。

我们在DaoSupportImpl<M>里写一个方法getTableName()来获取表名:

1、先获得一个M的对象:

M  m = getInstance();

2、添加注解:

在Book类的头上加上一行注解:@TableName(DBHelper.TABLE_BOOK_NAME),同时在工程中新建一个注解类TableName,在其中添加方法:String value();,代码如下:

package com.alex.db.dao.annotation;

public @interface TableName {

	String value();

}
@TableName(DBHelper.TABLE_BOOK_NAME)
public class Book {
	private int id;
	private String tittle;
	private String summary;
        ......
}

做完这些之后,我们就可以从Book类中拿到注解的value()方法返回的值,也就是DBHelper.TABLE_BOOK_NAME了。

3、如何拿到Book的类

但是问题又来了,我们在DaoSupportImpl<M>使用的是M泛型,我们如何拿到Book的类呢,这里就需要看一下文档了,getClass方法,返回的是运行时的那个类,所以我们运行时,泛型载入的是Book类,拿到的就是Book的class,载入的是News类,拿到的就是News的class。

所以我们根据class,就可以拿到该类对应的注解对象:

TableName tableName = m.getClass().getAnnotation(TableName.class);

然后调用value方法就可以得到类对应的表名:

if (tableName != null) {
			return tableName.value();
		}

这样问题一就解决了。

问题二:如何将实体中的数据,按照对应关系导入到数据库表中

问题二,也可以按照问题一的思路来解决。在问题一中,我们在Book类上添加注解来在表名和Book类上建立起了对应关系,那么我们也可以在Book类的几个成员变量(Field)上添加注解,来让它们与对应的表中的字段名建立起关系。如下:

@TableName(DBHelper.TABLE_BOOK_NAME)
public class Book {

	@ColumnName(DBHelper.COLUMN_ID)
	private int id;

	@ColumnName(DBHelper.COLUMN_TITLE)
	private String tittle;

	@ColumnName(DBHelper.COLUMN_SUMMARY)
	private String summary;
...
}

然后再新建对应的ColumnName注解类,并实现value方法。

package com.alex.db.dao.annotation;

public @interface ColumnName {

	String value();

}

通过上面的操作,我们就可以实现insert操作了:

	public long insert(M m) {
		ContentValues values = new ContentValues();

		fillColumn(m, values);
		return db.insert(getTableName(), null, values);
	}

	//解决问题二
	private void fillColumn(M m, ContentValues values) {
		Field[] fields = m.getClass().getDeclaredFields();

		for (Field item : fields) {
			ColumnName columnName = item.getAnnotation(ColumnName.class);

			if (columnName != null) {
				String key = columnName.value();
				String value;
				try {
					item.setAccessible(true);//让私有的Field也可以被操作,赋予权限
					value = item.get(m).toString();
					values.put(key, value);// 会存在问题,没有把主键id给剔除,也存进去;而且id是int类型,类型转换异常
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				}
			}
		}
	}

问题四:明确实体中主键,获取到主键中封装的值

我们先来解决问题四,再来看问题三。这是因为上面的insert操作是存在漏洞的,可以看上面的注解,那就是主键自增和类型的问题没有解决。在插入数据库的时候,我们循环所有的Field的集合fields ,来获得每一个Filed,这里面势必会包含我们自增的主键id,而由于是自增的,我们不应该将id的值也设置到数据库,这样会让SQLite的主键值出现错误。所以这里我们必须要能够标记出主键具体是哪个Field。这里我们也可以用注解来实现。

可以在id的注解上在加一行注解,来标记该Field是主键:

@TableName(DBHelper.TABLE_BOOK_NAME)
public class Book {

	@PrimaryKey(autoincrement=true)
	@ColumnName(DBHelper.COLUMN_ID)
	private int id;
......
}

然后再新建一个名为PrimaryKey的注解类,并添加boolean autoincrement();方法:

package com.alex.db.dao.annotation;

public @interface PrimaryKey {

	boolean autoincrement();

}

这里注意到,我们没有使用一个值,而是一个boolean型的表达式:autoincrement=true,用来标记该Field是不是主键。

到这里我们就可以标识出主键,实现一个getIdName()的方法,来获取主键在表中的字段名称,因为不是所有的类的主键都会叫做_id;和一个getIdValue()方法,来获得Id的值:

	private String getIdName(M m) {
		Field[] declaredFields = m.getClass().getDeclaredFields();

		for (Field item : declaredFields) {
			item.setAccessible(true);// 添加权限
			PrimaryKey annotation_id = item.getAnnotation(PrimaryKey.class);
			if (annotation_id != null) {
				try {
					// return item.get(m).toString();

					ColumnName columnName = item
							.getAnnotation(ColumnName.class);
					if (columnName != null) {
						return columnName.value();
					}

				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				}
			}
		}
		return null;
	}

	private String getIdValue(M m) {
		Field[] fields = m.getClass().getDeclaredFields();
		for (Field item : fields) {
			item.setAccessible(true);
			PrimaryKey primaryKey = item.getAnnotation(PrimaryKey.class);
			if (primaryKey != null) {
				try {
					return item.get(m).toString();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				}
			}
		}
		return null;
	}

然后,我们就可以将上面的insert方法中调用的fillColumn()方法完善,加入剔除主键的部分:

// 解决问题二
	private void fillColumn(M m, ContentValues values) {
		Field[] fields = m.getClass().getDeclaredFields();

		for (Field item : fields) {
			ColumnName columnName = item.getAnnotation(ColumnName.class);

			if (columnName != null) {
				String key = columnName.value();
				try {
					item.setAccessible(true);

					PrimaryKey primaryKey = item
							.getAnnotation(PrimaryKey.class);

					if (primaryKey != null && primaryKey.autoincrement()) {
						// 说明是主键,且是自增长的,则什么都不做,跳到下一个循环
						continue;
					}
					String value = item.get(m).toString();
					values.put(key, value);// 会存在问题,没有把主键id给剔除,也存进去;而且id是int类型,类型转换异常
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				}
			}
		}
	}

同时,也可以给出删除操作的方法delete():

@Override
	public int delete(Serializable id) {

		return db.delete(getTableName(), getIdName(getInstance()) + "=?",
				new String[] { String.valueOf(id) });
	}

问题三:如何将数据表中列的数据,按照对应关系导入到实体中

问题三与问题二是相反方向的问题,解决的思路比较类似,要注意的就是主键id这里是int类型,需要判断主键,然后转换类型,否则会出类型转换错误,可以直接给出findAll和update方法的代码:

findAll方法:

@Override
	public List<M> findAll() {

		List<M> result = null;

		Cursor cursor = db.query(getTableName(), null, null, null, null, null,
				null);

		if (cursor != null && cursor.getCount() > 0) {
			result = new ArrayList<M>();
			while (cursor.moveToNext()) {

				M m = getInstance();

				fillField(cursor, m);

				cursor.close();

				result.add(m);
			}
		}
		return result;
	}

	// 解决问题三
	private void fillField(Cursor cursor, M m) {

		Field[] fields = m.getClass().getDeclaredFields();
		for (Field item : fields) {

			item.setAccessible(true);
			ColumnName columnName = item.getClass().getAnnotation(
					ColumnName.class);
			if (columnName != null) {
				String key = columnName.value();
				int columnIndex = cursor.getColumnIndex(key);
				String value = cursor.getString(columnIndex);
				PrimaryKey primaryKey = m.getClass().getAnnotation(
						PrimaryKey.class);
				try {
					if (primaryKey != null) {
						item.set(m, Integer.parseInt(value));
					} else {
						item.set(m, value);
					}
				} catch (NumberFormatException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				}
			}
		}
	}

update()方法:

	@Override
	public int update(M m) {
		ContentValues values = new ContentValues();

		fillColumn(m, values);

		return db.update(getTableName(), values, getIdName(m) + "=?",
				new String[] { getIdValue(m) });
	}

问题五:实体的对象创建

问题五也是最后一个问题,要解决的是getInstance()这个方法如何实现。这里也要涉及到反射,通过上面的研究,我们知道了getClass()获得的是正在运行的那个类的Class,如果是Book类,实际跑的泛型就是Book,然后通过Class可以拿到所有泛型类的集合,就可以得到我们的类,因为这我们的泛型只有一个。然后再通过反射,就可以得到对象了。那么如何通过Class对象拿到所有泛型集合呢?实际上jdk会让泛型实现一个接口(参数化的类型--这个接口),所有的泛型都会实现这个接口(ParameterizedType),规定了泛型的通用操作。而通过ParameterizedType就可以拿到所有被使用的泛型的集合。这里要注意的一点是,在拿所有泛型类的集合的时候,要使用带泛型的那个API:getGenericSuperclass(),否则拿不到泛型集合:

/**
	 * 问题五:实体的对象创建
	 *
	 * @return
	 */
	public M getInstance() {
		// 实体是何时确定的

		// ①哪个孩子调用的该方法
		Class clazz = getClass();// 获取到了正在运行时的那个类,这里就会拿到实际在跑的那个impl类
		// System.out.println(clazz.toString());
		Log.i(TAG, clazz.toString());

		// ②获取该孩子的父类(是支持泛型的父类)
		// clazz.getSuperclass();// 这个方法不行,拿不到泛型
		Type genericSuperclass = clazz.getGenericSuperclass();// 可以拿到泛型

		// jdk会让泛型实现一个接口(参数化的类型--这个接口),所有的泛型都会实现这个接口(ParameterizedType),规定了泛型的通用操作

		if (genericSuperclass != null
				&& genericSuperclass instanceof ParameterizedType) {
			Type[] arguments = ((ParameterizedType) genericSuperclass)
					.getActualTypeArguments();

			try {
				return ((Class<M>) arguments[0]).newInstance();
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}

		}

		// ③获取到泛型中的参数

		return null;
	}

至此,我们就完成了数据库操作框架的抽取,如果我们再要写一个实体类,比如User的数据库操作,只要像Book类那样处理,加入对应的注释,即可使用啦!

最后附一张工程目录结构:

时间: 2024-10-30 18:38:47

【Android数据库优化】利用注解实现SQLite通用框架抽取的相关文章

模仿spring-aop的功能,利用注解搭建自己的框架。

入JAVA坑7月有余,也尝试自己手动搭建框架,最近对spring aop的这种切面很着迷,为此记录下自己目前搭出来的小小的demo,后续有时间也会继续改进自己的demo.望大神们不吝赐教. 主要还是运用反射和java自带的代理类.理论知识就不说了,因为我目前也不是很清楚,避免误导,还是避而不谈吧.好了,直接根据代码撸吧. 结构: 接口 Person.java public interface Person { void say(); } 接口实现类 Man.java public class M

Android性能优化-SQLite数据库

本系列博文我想围绕在Android中的一些优化细节和大家进行分享.Android中的优化可谓又是一重任,Android不足以像PC端具有很高的内存执行空间给我们用来重量级使用开销.有限的内存资源限制了我们的扩展方向.所以,在Android中的内存优化以及性能优化成为了一个攻城狮不可忽略的重点所在.本系列博文关于性能优化我会分为一下4个模块来和大家分享: (1)Android性能优化 一 SQLite数据库 (2)Android性能优化 一 布局优化 (3)Android性能优化 一 数据优化 (

如何将Android数据库操作通用化(三)

概述 悠悠绿水傍林侵日落观山四望回 幽林古寺孤明月冷井寒泉碧映台 鸥飞满浦渔舟泛鹤伴闲亭仙客来 游径踏花烟上走流溪远棹一篷开 概述 一个不小心都写了三篇了,也不知道大家还看得懂不?如果看不懂最好给我留个言,我好下一次改正. 接着上次的说,准备工作都已经做好了,现在咱们就要开始着手解决阻挡Android数据库操作通用化的五个问题了. 我们先回顾一下问题: 问题1:表名的获取 问题2:如何将实体中的数据,按照对应关系导入到数据库中 问题3:明确实体中主键是谁?获取到主键中封装的值 问题4:如何将数据

Android开发之利用SQLite进行数据存储

Android开发之利用SQLite进行数据存储 Android开发之利用SQLite进行数据存储 SQLite数据库简单介绍 Android中怎样使用SQLite 1 创建SQLiteOpenHelper对象并创建表 2 通过SQLiteDatabase对象运行增删改查操作 3 SQLiteDatabase之事务transaction 1.SQLite数据库简单介绍 SQLite.是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包括在一个相对小的C库中.它是D.RichardHip

Android数据库框架——GreenDao轻量级的对象关系映射框架,永久告别sqlite

Android数据库框架--GreenDao轻量级的对象关系映射框架,永久告别sqlite 前不久,我在写了ORMLite这个框架的博文 Android数据库框架--ORMLite轻量级的对象关系映射(ORM)Java包 但是对于我个人来说,我可能更加倾向于用GreenDao,所以今天也为大家带来了GreenDao的详细博客,希望大家喜欢,之前也详细介绍了ORM的思想,如果不明白可以先看一下前面的博文,这里就不多赘述了,我们新建一个工程 一.相关介绍 官方网站 : http://greendao

基础篇:6.Android数据库编程---SQLite

简介: 在Android平台上,继承了一个嵌入式关系型数据库---SQLite.SQLite具有跨平台特性,可以在所有主要的操作系统上运行.SQLite通过独占性和共享锁实现独立事务处理,因此多个进程可以在同一时间从同一数据库读取数据,但只有一个可以写入数据,在进行写操作之前,必须先获得独占锁.另一方面,SQLite采取动态数据类型,当某个值插入数据库时,SQLite会检查它的类型,如果该类型与所关联的列不匹配,SQLite则会进行强制转换.SQLite支持以下几种数据类型:NULL(空值).I

Android数据库SQLite表内设置外键

Android数据库SQLite表内设置外键 介绍 Android默认的数据是SQLite,但SQLite3.6.19之前(在2.2版本中使用的是3.6.22,因此如果你的应用只兼容到2.2版本就可以放心使用外键功能)是不支持外键的,如果有两张表需要关联,用外键是最省事的,但不支持的话怎么办呢?这里就有一个解决办法,就是用事务将两张表关联起来,并且最后生成一张视图. 现有两张表 Employees Dept 视图 ViewEmps:显示雇员信息和他所在的部门 创建数据库 自定义一个辅助类继承SQ

转载-Android数据库高手秘籍(一)——SQLite命令

原文地址: http://blog.csdn.net/guolin_blog/article/details/38461239 Android数据库高手秘籍(一)——SQLite命令 分类: Android数据库高手秘籍2014-09-04 09:10 7310人阅读 评论(42) 收藏 举报 Android数据库SQLite高手秘籍LitePal 转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/38461239 要想熟练地操作任

Android数据库高手秘籍(一)——SQLite命令

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/38461239 要想熟练地操作任何一个数据库,最最基本的要求就是要懂SQL语言,这也是每个程序员都应该掌握的技能.虽说SQL博大精深,要想精通确实很难,但最基本的一些建表命令,增删改查,大家还是必须要学会的. SQL(Structured Query Language)是一种标准的数据库查询语言,即所有的关系型数据库都会支持它,只不过每种数据库对SQL语言的支持与标准存在着细微的不