編輯:關於Android編程
SQLite中所有SQL語句都需要先編譯為stmt,然後執行。
首先看一個SQLiteDatabase.update()的過程。
// SQLiteDatabase.java
public int update(String table, ContentValues values, String whereClause, String[] whereArgs) {
return updateWithOnConflict(table, values, whereClause, whereArgs, CONFLICT_NONE);
}
public int updateWithOnConflict(String table, ContentValues values,
String whereClause, String[] whereArgs, int conflictAlgorithm) {
acquireReference();
try {
// 構造sql語句
......
SQLiteStatement statement = new SQLiteStatement(this, sql.toString(), bindArgs);
try {
return statement.executeUpdateDelete();
} finally {
statement.close();
}
} finally {
releaseReference();
}
}
// SQLiteStamente.java
public int executeUpdateDelete() {
acquireReference();
try {
return getSession().executeForChangedRowCount(
getSql(), getBindArgs(), getConnectionFlags(), null);
} catch (SQLiteDatabaseCorruptException ex) {
onCorruption();
throw ex;
} finally {
releaseReference();
}
}
// SQLiteSeesion.java
public int executeForChangedRowCount(String sql, Object[] bindArgs, int connectionFlags,
CancellationSignal cancellationSignal) {
......
acquireConnection(sql, connectionFlags, cancellationSignal);
try {
return mConnection.executeForChangedRowCount(sql, bindArgs,
cancellationSignal);
} finally {
releaseConnection();
}
}
// SQLiteConnection.java
public int executeForChangedRowCount(String sql, Object[] bindArgs,
CancellationSignal cancellationSignal) {
......
try {
final PreparedStatement statement = acquirePreparedStatement(sql);
try {
......
try {
// !!! 開始執行 實質為調用jni中的executeNonQuery
changedRows = nativeExecuteForChangedRowCount(
mConnectionPtr, statement.mStatementPtr);
return changedRows;
} finally {
detachCancellationSignal(cancellationSignal);
}
} finally {
releasePreparedStatement(statement);
}
} catch (RuntimeException ex) {
mRecentOperations.failOperation(cookie, ex);
throw ex;
} finally {
if (mRecentOperations.endOperationDeferLog(cookie)) {
mRecentOperations.logOperation(cookie, "changedRows=" + changedRows);
}
}
}public final class SQLiteStatement extends SQLiteProgram {
SQLiteStatement(SQLiteDatabase db, String sql, Object[] bindArgs) {
super(db, sql, bindArgs, null);
}
}
public abstract class SQLiteProgram extends SQLiteClosable {
private static final String[] EMPTY_STRING_ARRAY = new String[0];
private final SQLiteDatabase mDatabase;
private final String mSql;
private final boolean mReadOnly;
private final String[] mColumnNames;
private final int mNumParameters;
private final Object[] mBindArgs;
}
private static final class PreparedStatement {
public PreparedStatement mPoolNext;
public String mSql;
public int mStatementPtr; // 指向native中stmt的指針
public int mNumParameters;
public int mType;
public boolean mReadOnly;
public boolean mInCache;
public boolean mInUse;
}SQLiteProgram(SQLiteDatabase db, String sql, Object[] bindArgs,
CancellationSignal cancellationSignalForPrepare) {
mDatabase = db;
mSql = sql.trim();
int n = DatabaseUtils.getSqlStatementType(mSql);
switch (n) {
case DatabaseUtils.STATEMENT_BEGIN:
case DatabaseUtils.STATEMENT_COMMIT:
case DatabaseUtils.STATEMENT_ABORT:
mReadOnly = false;
mColumnNames = EMPTY_STRING_ARRAY;
mNumParameters = 0;
break;
default:
boolean assumeReadOnly = (n == DatabaseUtils.STATEMENT_SELECT);
SQLiteStatementInfo info = new SQLiteStatementInfo();
db.getThreadSession().prepare(mSql,
db.getThreadDefaultConnectionFlags(assumeReadOnly),
cancellationSignalForPrepare, info);
mReadOnly = info.readOnly;
mColumnNames = info.columnNames;
mNumParameters = info.numParameters;
break;
}
if (bindArgs != null && bindArgs.length > mNumParameters) {
throw new IllegalArgumentException("Too many bind arguments. "
+ bindArgs.length + " arguments were provided but the statement needs "
+ mNumParameters + " arguments.");
}
if (mNumParameters != 0) {
mBindArgs = new Object[mNumParameters];
if (bindArgs != null) {
System.arraycopy(bindArgs, 0, mBindArgs, 0, bindArgs.length);
}
} else {
mBindArgs = null;
}
}//SQLiteSeesion.java
public void prepare(String sql, int connectionFlags, CancellationSignal cancelationSignal,
SQLiteStatementInfo outStatementInfo) {
acquireConnection(sql, connectionFlags, cancellationSignal);
try {
mConnection.prepare(sql, outStatementInfo);
} finally {
releaseConnection();
}
}
// SQLiteConnection.java
public void prepare(String sql, SQLiteStatementInfo outStatementInfo) {
try {
final PrepraedStatement statement = acquirePreparedStatement(sql);
try {
if (outStatementInfo != null) {
outStatementInfo.numParameters = statement.mNumParameters;
outStatementInfo.readOnly = statement.mReadOnly;
final int columnCount = nativeGetColumnCount(// native得到結果的列的個數
mConnectionPtr, statement.mStatementPtr);
if (columnCount == 0) {
outStatementInfo.columnNames = EMPTY_STRING_ARRAY;
} else {
outStatementInfo.columnNames = new String[olumnCount]; //native獲取列的名稱
for (int i = 0; i < columnCount; i++) {
outStatementInfo.columnNames[i] = nativeGetColumnName(
mConnectionPtr, statement.mStatementPtr, i);
}
}
}
} finally {
releasePreparedStatement(statement);
}
} catch (RuntimeException ex) {
mRecentOperations.failOperation(cookie, ex);
throw ex;
} finally {
mRecentOperations.endOperation(cookie);
}
}
private PreparedStatement acquirePreparedStatement(String sql) {
PreparedStatement statement = mPreparedStatementCache.get(sql);
boolean skipCache = false;
if (statement != null) { // 如果緩存中存在
if (!statement.mInUse) { // 並且不在使用中
return statement; // 返回該statement
}
skipCache = true; // 如果已在使用 另備一份並不再緩存
}
final int statementPtr = nativePrepareStatement(mConnectionPtr, sql); //native
try {
final int numParameters = nativeGetParameterCount(mConnectionPtr, statementPtr);
final int type = DatabaseUtils.getSqlStatementType(sql);
final boolean readOnly = nativeIsReadOnly(mConnectionPtr, statementPtr);
statement = obtainPreparedStatement(sql, statementPtr, numParameters, type, readOnly);
if (!skipCache && isCacheable(type)) {
mPreparedStatementCache.put(sql, statement); // 將statement放入緩存中
statement.mInCache = true;
}
} catch (RuntimeException ex) {
if (statement == null || !statement.mInCache) {
nativeFinalizeStatement(mConnectionPtr, statementPtr);
}
throw ex;
}
statement.mInUse = true;
return statement;
}private final class PreparedStatementCache
extends LruCache {
public PreparedStatementCache(int size) {
super(size);
}
}
private PreparedStatement obtainPreparedStatement(String sql, int statementPtr,
int numParameters, int type, boolean readOnly) {
// 從池中獲取一個statement,並將其從池中移除
PreparedStatement statement = mPreparedStatementPool;
if (statement != null) { //
mPreparedStatementPool = statement.mPoolNext;
statement.mPoolNext = null;
statement.mInCache = false;
} else {
statement = new PreparedStatement();
}
statement.mSql = sql;
statement.mStatementPtr = statementPtr;
statement.mNumParameters = numParameters;
statement.mType = type;
statement.mReadOnly = readOnly;
return statement;
} private void releasePreparedStatement(PreparedStatement statement) {
statement.mInUse = false;
if (statement.mInCache) {
// 如果在緩存中重置stmt
nativeResetStatementAndClearBindings(mConnectionPtr, statement.mStatementPtr);
} else {// 如果不在緩存,即緩存中已經有相同一份
finalizePreparedStatement(statement);
}
}
private void finalizePreparedStatement(PreparedStatement statement) {
// 銷毀指向的stmt
nativeFinalizeStatement(mConnectionPtr, statement.mStatementPtr);
// 將statement放入mPreparedStatementPool
recyclePreparedStatement(statement);
}
private void recyclePreparedStatement(PreparedStatement statement) {
statement.mSql = null;
statement.mPoolNext = mPreparedStatementPool;
mPreparedStatementPool = statement;
}① 每個connection維護著多個PreparedStatement,可以直接使用的在緩存中,只有外殼沒有stmt已被銷毀的放在池中。
② SQLiteStatement prepare時,多次調用到connection中,先在緩存中獲取相應PreparedStatement,如果獲取不到在池中獲取只有外殼的PreparedStatement對其重新構建。
③ SQLiteStatement 執行時,通過acquireConnection獲取到最佳connection,通過connection執行相應PreparedStatement;如果不巧最佳connection被其他線程搶走,不含相應PreparedStatement的connection會先行構建PreparedStatement,然後執行。
Android自定義組件ListView
下面代碼設計了異步任務、JSon解析、自定義組件、IO流、文件下載、適配器原理等知識點。 代碼實現從服務器上讀取Json字符串。 Json字符串如下。 {object:{
Android 輕松實現網絡交互模板
看完本文,您可以學到:1.Android與後台交互的模板化方法 2.JSON的使用3.檢查網絡連接4.AsyncTask的使用我們簡單的以登錄為例,來實現整個的
Android 屬性動畫(Property Animation)
1. Property Animation屬性動畫,這個是在Android 3.0中才引進的,以前學WPF時裡面的動畫機制好像就是這個,它更改的是對象的實際屬性,在Vie
四大組件的工作過程探索(一)
四大組件的運行狀態: Android中的四大組件中除了BroadcastReceiver以外,其他三種組件都必須在Android Mainfrst中注冊。對於,Bro