編輯:關於Android編程
ORMLite是常用的一個ORM框架,她不止可以用在Android的sqlite數據庫,也可以使用她操作其他常見的數據庫。這兒是根據官方文檔抽取來的android用法。
導入ormlite-core.jar和ormlite-android.jar:下載jar
或者build.gradle中添加:
compile 'com.j256.ormlite:ormlite-android:5.0' compile 'com.j256.ormlite:ormlite-core:5.0'
1>類使用@DatabaseTable注解,標識一個表。
2>成員變量使用 @DatabaseField 注解,表示表中的列。
3>相關屬性設置可以查詢其依賴包中的DatabaseTable和Column注解類。持久化的數據類型可以查閱ORMLite官方文檔或庫源碼。
4>添加一個無參的構造函數。當執行查詢返回結果時,ORMLite會使用Java反射構造函數創建對象。
@DatabaseTable(tableName = "accounts") public class Account { //generatedId = true表示id主鍵自動生成 @DatabaseField(generatedId = true) private int id; //id = true表示這個列可以通過ID方法執行查詢,更新,刪除 @DatabaseField(id = true) private String name; //canBeNull = false表示不可以為空 @DatabaseField(canBeNull = false) private String password; public Account() { // ORMLite 需要一個無參構造器 } public Account(String name, String password) { this.name = name; this.password = password; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
1>繼承OrmLiteSqliteOpenHelper 創建database helper;
2>在onCreate方法中調用TableUtils.createTable創建表,onUpgrade方法執行數據庫更新。TableUtils類提供了一些創建和刪除表的靜態方法,參考源代碼。
public class DatabaseHelper extends OrmLiteSqliteOpenHelper { private static final String TABLE_NAME = "sqlite.db"; public DatabaseHelper(Context context) { super(context, TABLE_NAME, null, 2); } @Override public void onCreate(SQLiteDatabase database, ConnectionSource connectionSource) { try { TableUtils.createTable(connectionSource, Bean.class); } catch (java.sql.SQLException e) { e.printStackTrace(); } } @Override public void onUpgrade(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) { } }
在數據訪問對象(Data Access Objects (DAO))類中隔離數據庫操作,提供創建,刪除,更新,等等操作。每個表都對應一個DAO,每個DAO有兩個參數:使用DAO持久化數據的實體類和用來標示指定表中行的ID列,如果類中沒設置ID列,可以把對象或null作為第二個參數。例如,在上面Account類中,“name”成員是ID列(id = true),所以ID列是字符串。
創建DAO的最簡單的方法是調用DaoManager.createDao(),這樣如果它們被內部ORMLite功能需要,可以重復使用,而不是重新創建(創建DAO很消耗資源,應該盡可能重復利用):
accountDao =DaoManager.createDao(connectionSource, Account.class); DaoorderDao =DaoManager.createDao(connectionSource, Order.class); " data-snippet-id="ext.98e0cedd8126286a7e4c0dff75edc3a5" data-snippet-saved="false" data-codota-status="done"> Dao accountDao =DaoManager.createDao(connectionSource, Account.class); Dao orderDao =DaoManager.createDao(connectionSource, Order.class);
使用這種方式需要ConnectionSource參數,和實體類的Class對象,ConnectionSource參數可以通過OrmLiteSqliteOpenHelper的getConnectionSource()方法獲得:
ConnectionSource connectionSource = OrmLiteSqliteOpenHelper.getConnectionSource();
如果想要一個更好的類層次結構,或者在DAO中需要添加較多的方法,可以定義一個接口,繼承Dao接口,接口不是必須的,但這樣做可以減少耦合:
{ // 添加 DAO的方法 }" data-snippet-id="ext.abc5a99cb3e88c78298e6d53cfd4a45a" data-snippet-saved="false" data-codota-status="done"> /** Account DAO ,具有字符串id (Account.name) */ public interface AccountDao extends Dao { // 添加 DAO的方法 }
然後實現類繼承BaseDaoImpl並實現上面定義的接口:
implements AccountDao { // 這個構造器必須有 public AccountDaoImpl(ConnectionSource connectionSource) throws SQLException { super(connectionSource, Account.class); } }" data-snippet-id="ext.96f06e0a55435e06f4132fdd6659e58b" data-snippet-saved="false" data-codota-status="done"> /** JDBC implementation of the AccountDao interface. */ public class AccountDaoImpl extends BaseDaoImplimplements AccountDao { // 這個構造器必須有 public AccountDaoImpl(ConnectionSource connectionSource) throws SQLException { super(connectionSource, Account.class); } }
要使用自定義DAO類的,需要到相應的實體類@DatabaseTable注解中添加daoClass屬性:
@DatabaseTable(daoClass = AccountDaoImpl.class) public class Account { … }
也可以在DatabaseHelper中調用OrmLiteSqliteOpenHelper.getDao創建:
accountDao; public Dao getAccountDao() throws SQLException { if (AccountDao == null) { AccountDao = getDao(Account.class); } return accountDao; } " data-snippet-id="ext.27729b99b905a23e2d73b8b151a26d9e" data-snippet-saved="false" data-codota-status="done"> private Dao accountDao; public Dao getAccountDao() throws SQLException { if (AccountDao == null) { AccountDao = getDao(Account.class); } return accountDao; }
默認情況下,大多數的DAO方法都會拋出SQLException,大部分的異常繼承RuntimeException,所以會需要大量的try … catch語句,出於這個原因,RuntimeExceptionDao包裝了調用DAO方法會出現的運行時異常SQL exceptions:
dao = DaoManager.createDao(connectionSource, Account.class); RuntimeExceptionDao accountDao = new RuntimeExceptionDao(dao);" data-snippet-id="ext.14f5706125d032443fe80d49b9544470" data-snippet-saved="false" data-codota-status="done">Dao dao = DaoManager.createDao(connectionSource, Account.class); RuntimeExceptionDao accountDao = new RuntimeExceptionDao(dao);
或者直接使用其createDao方法:
accountDao =RuntimeExceptionDao.createDao(connectionSource, Account.class);" data-snippet-id="ext.0122d7c2b19f78dfc2172afec37136f2" data-snippet-saved="false" data-codota-status="done"> RuntimeExceptionDao accountDao =RuntimeExceptionDao.createDao(connectionSource, Account.class);
在DatabaseHelper中可以調用OrmLiteSqliteOpenHelper.getRuntimeExceptionDao。
插入新的行到數據庫:
Account account = new Account(); account.name = "Jim Coakley"; accountDao.create(account);
如果對象具有注解定義的id屬性,那麼我們就可以使用其ID在數據庫中查找此對象:
Account account = accountDao.queryForId(name); if (account == null) { account not found handling … }
如果改變對象的成員屬性,必須調用update()將改變更新到數據庫中:
account.password = "_secret"; accountDao.update(account);
如果數據空正使用的某個對象被其他實體改變,需要刷新這個對象,保證這個對象是實時的:
accountDao.refresh(account);
刪除對象對應的數據庫中的行,一旦對象已經從數據庫中刪除,您可以繼續使用在內存中的該對象,但任何更新或刷新會失效:
accountDao.delete(account);
該DAO本身也是一個迭代器,因此可以直接遍歷數據庫數據中表的行:
// page through all of the accounts in the database for (Account account : accountDao) { System.out.println(account.getName()); }
這種方式必須遍歷數據庫中表的所有行,然後才會關閉潛在的sql對象。 如果沒有通過循環遍歷所有的行,
ORMLite並不會關閉sql對象,數據庫的連接會被弱化並且只有GC回收才會被關閉,這樣會導致程序Bug,所以最好使用
try…finally迭代器。以下for循環,是一個非常糟糕的代碼:
for (Account account : accountDao) { if (account.getName().equals("Bob Smith")) { // you can't return, break, or throw from here return account; } }
也可以選擇直接使用迭代器,因為for循環式並不總是最佳的。這樣允許使用try…finally,達到一種更優化的代碼:
iterator = accountDao.closeableIterator(); try { while (iterator.hasNext()) { Account account = iterator.next(); System.out.println(account.getName()); } } finally { // close it at the end to close underlying SQL statement iterator.close(); }" data-snippet-id="ext.926d5f5967589295339990e5986edd6c" data-snippet-saved="false" data-codota-status="done"> CloseableIterator iterator = accountDao.closeableIterator(); try { while (iterator.hasNext()) { Account account = iterator.next(); System.out.println(account.getName()); } } finally { // close it at the end to close underlying SQL statement iterator.close(); }
或者使用迭代包裝器,for循環之後仍然可以關閉:
wrappedIterable = accountDao.getWrappedIterable(); try { for (Account account : wrappedIterable) { … } } finally { wrappedIterable.close(); }" data-snippet-id="ext.b835ceda01d366e72c4f35316bdf5d79" data-snippet-saved="false" data-codota-status="done"> CloseableWrappedIterable wrappedIterable = accountDao.getWrappedIterable(); try { for (Account account : wrappedIterable) { … } } finally { wrappedIterable.close(); }
DatabaseHelper可能在App或多個Activity的線程中被多次實例化使用,如果同時有多個對象,可能會出現過時的數據和意外的結果。所以建議使用OpenHelperManager管理DatabaseHelper的使用:
private DatabaseHelper databaseHelper = null; private void releaseHelper() { if (databaseHelper != null) { OpenHelperManager.releaseHelper(); databaseHelper = null; } } private DatabaseHelper getHelper() { if (databaseHelper == null) { databaseHelper = OpenHelperManager.getHelper(this, DatabaseHelper.class); } return databaseHelper; }
還可以讓Activity繼承OrmLiteBaseActivity,OrmLiteBaseActivity對OpenHelperManager的使用做了進一步封裝,還有OrmLiteBaseListActivity, OrmLiteBaseService, OrmLiteBaseTabActivity等,不過一般不這麼做。但是可以在使用OpenHelperManager的時候拿來參考。
然後通過databaseHelper操作數據庫:
accountDao = getHelper().getAccountDao(); Account account = new Account (); account.setName("one"); account.setPassword("123"); accountDao.create(account);" data-snippet-id="ext.1a91cad287de61973f0b43e7a31309cd" data-snippet-saved="false" data-codota-status="done"> Dao accountDao = getHelper().getAccountDao(); Account account = new Account (); account.setName("one"); account.setPassword("123"); accountDao.create(account);
ORMLite支持外鍵的概念,既一個對象的一個或者多個屬性保存在相同數據庫中其他表中。比如數據庫中有一個Order對象,每個Order對象都對應一個Account對象,然後就說Order(是一個表)對象的Account(也是一個表)成員有外鍵屬性。id成員在表創建的時候會生成”account_id”列:
@DatabaseTable(tableName = "orders") public class Order { @DatabaseField(generatedId = true) private int id; @DatabaseField(canBeNull = false, foreign = true) private Account account; … }
當創建有外鍵屬性成員的對象(Order)時,外鍵對象(Account)不會被自動創建(Account表不會自動創建)。如果外鍵對象(Account對象)在數據庫中有generated id(Order對象有 id成員),應該在創建引用這個對象(Order對象有Account成員)的對象(Order對象)之前創建外鍵對象(Account表):
Account account = new Account("Jim Coakley"); accountDao.create(account); // 這時會創建一個account對象,並且設置generated ids // 現在用order設置account,創建並插入account表 Order order = new Order("Jim Sanders", 12.34); order.setAccount(account); … orderDao.create(order);
某些情況下如果希望外鍵自建,可以在外鍵(account)的注解中設置foreignAutoCreate屬性。
當你查詢一個Order時,會獲得一個account對象,這個對象只有id屬性被設定了值,其他屬性都是默認值(null, 0, false, etc.)。如果需要使用這個account對象的其他值,則必須調用accountDao類的refresh方法獲得這個Account對象的屬性:
Order order = orderDao.queryForId(orderId); System.out.println("Account-id on the order should be set: " + order.account.id); // 此時 order.account.name為null System.out.println("But other fields on the account should not be set: " + order.account.name); // 用AccountDao刷新一下account accountDao.refresh(order.getAccount()); System.out.println("Now the account fields will be set: " + order.account.name);
也可以在注解中添加foreignAutoRefresh屬性值設置自動刷新外鍵對象的數據。
有不同的方式查詢外鍵的屬性值,比如查詢匹配某個account的所有Order,通過ID屬性的成員和account的name查詢:
results = orderDao.queryBuilder().where(). eq("account_id", account.getName()).query();" data-snippet-id="ext.a699e320b81ca15e56b3eb94a02bf65f" data-snippet-saved="false" data-codota-status="done">// query for all orders that match a certain account Listresults = orderDao.queryBuilder().where(). eq("account_id", account.getName()).query();
也可以讓ORMLite從該account中自動提取id獲得:
results = orderDao.queryBuilder().where(). eq("account_id", account).query();" data-snippet-id="ext.99c3edc607b3f0302518eab05a90b720" data-snippet-saved="false" data-codota-status="done">// ORMLite will extract and use the id field internally Listresults = orderDao.queryBuilder().where(). eq("account_id", account).query();
上面說了Account是Order的外鍵,如果一個Account對象對應多個Order對象,則可以將其以成員的形式通過 @ForeignCollectionField注解以以下形式添加到Account中去:
orders; … }" data-snippet-id="ext.6dd39c929a6e50cdacdc2d048b4f02ed" data-snippet-saved="false" data-codota-status="done">public class Account { … @ForeignCollectionField(eager = false) ForeignCollectionorders; … }
成員類型只可以使用ForeignCollection< T> 或 Collection< T>。注解屬性可以查閱庫中的ForeignCollectionField類。
當改變了Collection中的order時,需要調用update在數據庫中更新它:
for (Order order : account.orders()) { // 如果改變了order的某些成員 order.setAmount(123); // 必須在數據庫中更新account account.orders.update(order); }
當對數據庫有較多的執行動作時,用事務處理比較好,圖個方便,下段代碼摘自ormlite的事務使用
private boolean doBatchInTransaction(final Listlist, final int batchType) { boolean doBatch = false; ConnectionSource connectionSource = ormLiteDao.getConnectionSource(); TransactionManager transactionManager = new TransactionManager(connectionSource); Callable callable = new Callable () { @Override public Boolean call() throws Exception { return doBatch(list, batchType); } }; try { doBatch = transactionManager.callInTransaction(callable); } catch (SQLException e) { LogUtil.e(e); } return doBatch; } private boolean doBatch(List list, int batchType) { int result = 0; try { for (T t : list) { switch (batchType) { case DaoOperation.INSERT: result += ormLiteDao.create(t); break; case DaoOperation.DELETE: result += ormLiteDao.delete(t); break; case DaoOperation.UPDATE: result += updateIfValueNotNull(t); break; default: LogUtil.w("no this type."); break; } } } catch (SQLException e) { LogUtil.e(e); } return result == list.size(); }
更新app時,可能會修改現有的數據庫,這時就需要在 創建的DatabaseHelper的onUpgrade方法中進行一些工作了。比如在表中增加一列,可以在onUpgrade方法中這麼做:
dao = getHelper().getAccountDao(); // 在表account中增加 "age" 列 dao.executeRaw("ALTER TABLE `account` ADD COLUMN age INTEGER;");" data-snippet-id="ext.9f8b7e3adee599a394d40511d3bc585e" data-snippet-saved="false" data-codota-status="done">Dao dao = getHelper().getAccountDao(); // 在表account中增加 "age" 列 dao.executeRaw("ALTER TABLE `account` ADD COLUMN age INTEGER;");
所有能做的就是重新命名表名和添加新列,不要重命名或刪除列或更改列的屬性。
最常用的,是根據版本條件更改數據庫:
if (oldVersion < 2) { // we added the age column in version 2 dao.executeRaw("ALTER TABLE `account` ADD COLUMN age INTEGER;"); } if (oldVersion < 3) { // we added the weight column in version 3 dao.executeRaw("ALTER TABLE `account` ADD COLUMN weight INTEGER;"); }
或者:
0;");" data-snippet-id="ext.048d4e7dc2deaa6650350707374732c3" data-snippet-saved="false" data-codota-status="done">dao.executeRaw( "ALTER TABLE `account` ADD COLUMN hasDog BOOLEAN DEFAULT 0;"); dao.updateRaw("UPDATE `account` SET hasDog = 1 WHERE dogCount > 0;");
這兒用到了數據庫語句,可以查閱sqlite官方文檔。
更多請參考 ORMLite官方文檔 ,
最近在學習android底層的一些東西,看了一些大神的博客,整體上有了一點把握,也產生了很多疑惑,於是再次把鄧大神的深入系列翻出來仔細看看,下面主要是一些閱讀筆記。JNI
本文主要介紹如何使用tcpdump和wireshark對Android應用程序進行抓包並分析,需要說明的是在抓包之前,你的Android設備必須root過了,另外你的電腦
本文實例講述了Android獲取手機屏幕大小的方法。分享給大家供大家參考,具體如下:這裡主要用了三個對象TextView ,Button ,以及DisplayMetric
普通按鈕也就那麼幾種樣式,看著都審美疲勞,先放效果圖: 你會不會以為這個按鈕是集結了很多動畫的產物,我告訴你,並沒有。所有的實現都是基於自定義View,采用最底