From c1d66ef4adfb0b0219e2b68fe07f3a9bf4cb3af3 Mon Sep 17 00:00:00 2001 From: Saulo Gil Date: Thu, 4 May 2017 17:58:32 -0300 Subject: [PATCH 1/9] Support null values when loading data from cursor --- .../internal/AnnotationProcessor.java | 63 ++++++++++++------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/src/com/activeandroid/internal/AnnotationProcessor.java b/src/com/activeandroid/internal/AnnotationProcessor.java index d9b3dc3ea..cab758d4d 100644 --- a/src/com/activeandroid/internal/AnnotationProcessor.java +++ b/src/com/activeandroid/internal/AnnotationProcessor.java @@ -134,7 +134,8 @@ private void generate(TypeElement tableElement, Set columns) { private String getLoadFromCursorCode(Set columns) { StringBuilder stringBuilder = new StringBuilder(); - + stringBuilder.append(" int i = -1; // column index \n"); + final String nullCheck = CURSOR + ".isNull(i) ? null : "; for (VariableElement column : columns) { Column annotation = column.getAnnotation(Column.class); @@ -147,40 +148,56 @@ private String getLoadFromCursorCode(Set columns) { boolean notPrimitiveType = typeMirror instanceof DeclaredType; String type = typeMirror.toString() + ".class"; String getColumnIndex = COLUMNS_ORDERED + ".indexOf(\"" + fieldName + "\")"; + String getColumnIndexAssignment = "i = " + getColumnIndex + "; \n"; + stringBuilder.append(" " + getColumnIndexAssignment ); if (notPrimitiveType) { stringBuilder.append(" if (ModelHelper.isSerializable(" + type + ")) {\n"); - stringBuilder.append(" " + MODEL + "." + column.getSimpleName() + " = (" + typeMirror.toString() + ") ModelHelper.getSerializable(cursor, " + type + ", " + getColumnIndex + ");\n"); + stringBuilder.append(" " + MODEL + "." + column.getSimpleName() + " = (" + typeMirror.toString() + ") ModelHelper.getSerializable(cursor, " + type + ", i);\n"); stringBuilder.append(" } else {\n"); stringBuilder.append(" " + MODEL + "." + column.getSimpleName() + " = "); } else { stringBuilder.append(" " + MODEL + "." + column.getSimpleName() + " = "); } - if (isTypeOf(typeMirror, Integer.class) || isTypeOf(typeMirror, int.class)) - stringBuilder.append(CURSOR + ".getInt(" + getColumnIndex + ");\n"); - else if (isTypeOf(typeMirror, Byte.class) || isTypeOf(typeMirror, byte.class)) - stringBuilder.append(CURSOR + ".getInt(" + getColumnIndex + ");\n"); - else if (isTypeOf(typeMirror, Short.class) || isTypeOf(typeMirror, short.class)) - stringBuilder.append(CURSOR + ".getInt(" + getColumnIndex + ");\n"); - else if (isTypeOf(typeMirror, Long.class) || isTypeOf(typeMirror, long.class)) - stringBuilder.append(CURSOR + ".getLong(" + getColumnIndex + ");\n"); - else if (isTypeOf(typeMirror, Float.class) || isTypeOf(typeMirror, float.class)) - stringBuilder.append(CURSOR + ".getFloat(" + getColumnIndex + ");\n"); - else if (isTypeOf(typeMirror, Double.class) || isTypeOf(typeMirror, double.class)) - stringBuilder.append(CURSOR + ".getDouble(" + getColumnIndex + ");\n"); - else if (isTypeOf(typeMirror, Boolean.class) || isTypeOf(typeMirror, boolean.class)) - stringBuilder.append(CURSOR + ".getInt(" + getColumnIndex + ") != 0;\n"); - else if (isTypeOf(typeMirror, Character.class) || isTypeOf(typeMirror, char.class)) - stringBuilder.append(CURSOR + ".getString(" + getColumnIndex + ");\n"); + if (isTypeOf(typeMirror, Integer.class) || isTypeOf(typeMirror, Byte.class) || isTypeOf(typeMirror, Short.class) ) + stringBuilder.append(nullCheck).append(CURSOR + ".getInt(i);\n"); + else if (isTypeOf(typeMirror, Long.class)) + stringBuilder.append(nullCheck).append(CURSOR + ".getLong(i);\n"); + else if (isTypeOf(typeMirror, Float.class)) + stringBuilder.append(nullCheck).append(CURSOR + ".getFloat(i);\n"); + else if (isTypeOf(typeMirror, Double.class)) + stringBuilder.append(nullCheck).append(CURSOR + ".getDouble(i);\n"); + else if (isTypeOf(typeMirror, int.class)) + stringBuilder.append(CURSOR + ".getInt(i);\n"); + else if (isTypeOf(typeMirror, byte.class)) + stringBuilder.append(CURSOR + ".getInt(i);\n"); + else if (isTypeOf(typeMirror, short.class)) + stringBuilder.append(CURSOR + ".getInt(i);\n"); + else if (isTypeOf(typeMirror, long.class)) + stringBuilder.append(CURSOR + ".getLong(i);\n"); + else if (isTypeOf(typeMirror, float.class)) + stringBuilder.append(CURSOR + ".getFloat(i);\n"); + else if (isTypeOf(typeMirror, double.class)) + stringBuilder.append(CURSOR + ".getDouble(i);\n"); + else if (isTypeOf(typeMirror, Boolean.class)) + stringBuilder.append(nullCheck).append(CURSOR + ".getInt(i) != 0;\n"); + else if (isTypeOf(typeMirror, boolean.class)) + stringBuilder.append(CURSOR + ".getInt(i) != 0;\n"); + else if (isTypeOf(typeMirror, char.class)) + stringBuilder.append(CURSOR + ".getString(i);\n"); + else if (isTypeOf(typeMirror, Character.class)) + stringBuilder.append(nullCheck).append(CURSOR + ".getString(i);\n"); else if (isTypeOf(typeMirror, String.class)) - stringBuilder.append(CURSOR + ".getString(" + getColumnIndex + ");\n"); - else if (isTypeOf(typeMirror, Byte[].class) || isTypeOf(typeMirror, byte[].class)) - stringBuilder.append(CURSOR + ".getBlob(" + getColumnIndex + ");\n"); + stringBuilder.append(nullCheck).append(CURSOR + ".getString(i);\n"); + else if (isTypeOf(typeMirror, byte[].class)) + stringBuilder.append(CURSOR + ".getBlob(i);\n"); + else if (isTypeOf(typeMirror, Byte[].class)) + stringBuilder.append(nullCheck).append(CURSOR + ".getBlob(i);\n"); else if (isTypeOf(typeMirror, Model.class)) - stringBuilder.append("(" + typeMirror.toString() + ") ModelHelper.getModel(cursor, " + type + ", " + getColumnIndex + ");\n"); + stringBuilder.append("(" + typeMirror.toString() + ") ModelHelper.getModel(cursor, " + type + ", i);\n"); else if (isTypeOf(typeMirror, Enum.class)) - stringBuilder.append("(" + typeMirror.toString() + ") ModelHelper.getEnum(cursor, " + type + ", " + getColumnIndex + ");\n"); + stringBuilder.append("(" + typeMirror.toString() + ") ModelHelper.getEnum(cursor, " + type + ", i);\n"); else stringBuilder.append(" null;\n"); if (notPrimitiveType) { From 50d3934de11064c73de38271d3196744bfd0254f Mon Sep 17 00:00:00 2001 From: Saulo Gil Date: Thu, 4 May 2017 19:48:46 -0300 Subject: [PATCH 2/9] Optional read cache usage. Consistent read cache implementation. The read cache can be avoided when querying the database, by using the new method com.activeandroid.query.From#setUseCache. Additionally we've fixed the read cache implementation, which was used only by the reflective (legacy) model filler. Now the read cache is applied regardless of the particular model filler in use. We keep the read cache enabled by default mainly for backwards compatibility reasons. --- src/com/activeandroid/Model.java | 4 --- src/com/activeandroid/query/From.java | 16 ++++++++-- src/com/activeandroid/util/SQLiteUtils.java | 35 +++++++++++++++++---- 3 files changed, 43 insertions(+), 12 deletions(-) diff --git a/src/com/activeandroid/Model.java b/src/com/activeandroid/Model.java index 276b10c9c..fe1b14b87 100644 --- a/src/com/activeandroid/Model.java +++ b/src/com/activeandroid/Model.java @@ -293,10 +293,6 @@ else if (ReflectionUtils.isSubclassOf(fieldType, Enum.class)) { Log.e(e.getClass().getName(), e); } } - - if (mId != null) { - Cache.addEntity(this); - } } diff --git a/src/com/activeandroid/query/From.java b/src/com/activeandroid/query/From.java index ab3837a90..f2f1cea91 100644 --- a/src/com/activeandroid/query/From.java +++ b/src/com/activeandroid/query/From.java @@ -40,6 +40,7 @@ public final class From implements Sqlable { private String mOrderBy; private String mLimit; private String mOffset; + private boolean useCache = true; private List mArguments; @@ -295,7 +296,7 @@ public String toCountSql() { public List execute() { if (mQueryBase instanceof Select) { - return SQLiteUtils.rawQuery(mType, toSql(), getArguments()); + return SQLiteUtils.rawQuery(mType, toSql(), getArguments(), useCache); } else { SQLiteUtils.execSql(toSql(), getArguments()); @@ -308,7 +309,7 @@ public List execute() { public T executeSingle() { if (mQueryBase instanceof Select) { limit(1); - return (T) SQLiteUtils.rawQuerySingle(mType, toSql(), getArguments()); + return (T) SQLiteUtils.rawQuerySingle(mType, toSql(), getArguments(), useCache); } else { limit(1); @@ -343,4 +344,15 @@ public String[] getArguments() { return args; } + + /** + * Retrieve entities from ActiveAndroid's cache. The cache is enabled by default. + * @param useCache + * @return + */ + public From setUseCache(boolean useCache) { + this.useCache = useCache; + return this; + } + } diff --git a/src/com/activeandroid/util/SQLiteUtils.java b/src/com/activeandroid/util/SQLiteUtils.java index c4b545505..01958529a 100644 --- a/src/com/activeandroid/util/SQLiteUtils.java +++ b/src/com/activeandroid/util/SQLiteUtils.java @@ -100,13 +100,17 @@ public static void execSql(String sql, Object[] bindArgs) { Cache.openDatabase().execSQL(sql, bindArgs); } - public static List rawQuery(Class type, String sql, String[] selectionArgs) { + public static List rawQuery(Class type, String sql, String[] selectionArgs, boolean useCache) { Cursor cursor = Cache.openDatabase().rawQuery(sql, selectionArgs); - List entities = processCursor(type, cursor); + List entities = processCursor(type, cursor, useCache); cursor.close(); return entities; } + + public static List rawQuery(Class type, String sql, String[] selectionArgs){ + return rawQuery(type, sql, selectionArgs, true); + } public static int intQuery(final String sql, final String[] selectionArgs) { final Cursor cursor = Cache.openDatabase().rawQuery(sql, selectionArgs); @@ -116,8 +120,8 @@ public static int intQuery(final String sql, final String[] selectionArgs) { return number; } - public static T rawQuerySingle(Class type, String sql, String[] selectionArgs) { - List entities = rawQuery(type, sql, selectionArgs); + public static T rawQuerySingle(Class type, String sql, String[] selectionArgs, boolean useCache) { + List entities = rawQuery(type, sql, selectionArgs, useCache); if (entities.size() > 0) { return entities.get(0); @@ -126,6 +130,10 @@ public static T rawQuerySingle(Class type, St return null; } + public static T rawQuerySingle(Class type, String sql, String[] selectionArgs){ + return rawQuerySingle(type, sql, selectionArgs, true); + } + // Database creation public static ArrayList createUniqueDefinition(TableInfo tableInfo) { @@ -358,7 +366,7 @@ else if (ReflectionUtils.isSubclassOf(type, Enum.class)) { } @SuppressWarnings("unchecked") - public static List processCursor(Class type, Cursor cursor) { + public static List processCursor(Class type, Cursor cursor, boolean useCache) { TableInfo tableInfo = Cache.getTableInfo(type); String idName = tableInfo.getIdName(); final List entities = new ArrayList(); @@ -373,13 +381,24 @@ public static List processCursor(Class typ */ List columnsOrdered = new ArrayList(Arrays.asList(cursor.getColumnNames())); do { - Model entity = Cache.getEntity(type, cursor.getLong(columnsOrdered.indexOf(idName))); + Model entity; + + if(useCache) { + entity = Cache.getEntity(type, cursor.getLong(columnsOrdered.indexOf(idName))); + } else { + entity = null; + } + if (entity == null) { entity = (T) entityConstructor.newInstance(); } entity.loadFromCursor(cursor); entities.add((T) entity); + + // add to cache + if (entity.getId() != null) + Cache.addEntity(entity); } while (cursor.moveToNext()); } @@ -402,6 +421,10 @@ public static List processCursor(Class typ return entities; } + public static List processCursor(Class type, Cursor cursor){ + return processCursor(type, cursor, true); + } + private static int processIntCursor(final Cursor cursor) { if (cursor.moveToFirst()) { return cursor.getInt(0); From afd3c7e9688ca708b2671131432bef878e37e969 Mon Sep 17 00:00:00 2001 From: jlhonora Date: Tue, 27 Jan 2015 17:12:10 -0300 Subject: [PATCH 3/9] Better concurrency support DB concurrency is tricky in Android. The following changes allow a better handling of multithreaded db access: - Write ahead logging is enabled - Connection is configured in onConfigure (SQLiteOpenHelper) - Transactions are made in non-exclusive mode References: - http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#enableWriteAheadLogging() - http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html#onConfigure(android.database.sqlite.SQLiteDatabase) - http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.1_r1/android/database/sqlite/SQLiteDatabase.java#SQLiteDatabase.beginTransaction%28android.database.sqlite.SQLiteTransactionListener%2Cboolean%29 - https://www.sqlite.org/lockingv3.html#reserved_lock - https://www.sqlite.org/lang_transaction.html - http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#beginTransactionNonExclusive() --- src/com/activeandroid/ActiveAndroid.java | 11 ++++++++++- src/com/activeandroid/DatabaseHelper.java | 20 ++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/com/activeandroid/ActiveAndroid.java b/src/com/activeandroid/ActiveAndroid.java index c58c8efd8..60237c8f8 100644 --- a/src/com/activeandroid/ActiveAndroid.java +++ b/src/com/activeandroid/ActiveAndroid.java @@ -20,6 +20,7 @@ import android.database.sqlite.SQLiteDatabase; import com.activeandroid.util.Log; +import android.os.Build; public final class ActiveAndroid { ////////////////////////////////////////////////////////////////////////////////////// @@ -60,8 +61,16 @@ public static SQLiteDatabase getDatabase() { return Cache.openDatabase(); } + /** + * Non-exclusive transactions allows BEGIN IMMEDIATE + * blocks, allowing better read concurrency. + */ public static void beginTransaction() { - Cache.openDatabase().beginTransaction(); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { + Cache.openDatabase().beginTransaction(); + } else { + Cache.openDatabase().beginTransactionNonExclusive(); + } } public static void endTransaction() { diff --git a/src/com/activeandroid/DatabaseHelper.java b/src/com/activeandroid/DatabaseHelper.java index cc3bebec7..77072dfd7 100644 --- a/src/com/activeandroid/DatabaseHelper.java +++ b/src/com/activeandroid/DatabaseHelper.java @@ -38,6 +38,7 @@ import com.activeandroid.util.NaturalOrderComparator; import com.activeandroid.util.SQLiteUtils; import com.activeandroid.util.SqlParser; +import android.os.Build; public final class DatabaseHelper extends SQLiteOpenHelper { ////////////////////////////////////////////////////////////////////////////////////// @@ -66,6 +67,25 @@ public DatabaseHelper(Configuration configuration) { // OVERRIDEN METHODS ////////////////////////////////////////////////////////////////////////////////////// + /** + * onConfigure is called when the db connection + * is being configured. It's the right place + * to enable write-ahead logging or foreign + * key support. + * + * Available for API level 16 (JellyBean) and above. + */ + @Override + public void onConfigure(SQLiteDatabase db) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + db.enableWriteAheadLogging(); + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + db.setForeignKeyConstraintsEnabled(true); + } + executePragmas(db); + } + @Override public void onOpen(SQLiteDatabase db) { executePragmas(db); From 0c1378995cb3d9bdc48f0af1f70421ca8f28bfc4 Mon Sep 17 00:00:00 2001 From: Saulo Gil Date: Fri, 23 Jun 2017 12:56:08 -0300 Subject: [PATCH 4/9] Fix detection of arrays on the annotation processor --- src/com/activeandroid/internal/AnnotationProcessor.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/com/activeandroid/internal/AnnotationProcessor.java b/src/com/activeandroid/internal/AnnotationProcessor.java index cab758d4d..94c359d6b 100644 --- a/src/com/activeandroid/internal/AnnotationProcessor.java +++ b/src/com/activeandroid/internal/AnnotationProcessor.java @@ -16,6 +16,7 @@ import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.tools.Diagnostic.Kind; import javax.tools.JavaFileObject; @@ -222,7 +223,7 @@ private String getFillContentValuesCode(Set columns) { boolean notPrimitiveType = typeMirror instanceof DeclaredType; String type = typeMirror.toString() + ".class"; String getValue = MODEL + "." + column.getSimpleName(); - + if (notPrimitiveType) { stringBuilder.append(" if (ModelHelper.isSerializable(" + type + ")) {\n"); stringBuilder.append(" ModelHelper.setSerializable(" + CONTENT_VALUES + ", " + type + ", " + getValue + ", \"" + fieldName + "\");\n"); @@ -273,6 +274,9 @@ private boolean isTypeOf(TypeMirror typeMirror, Class type) { if (type.getName().equals(typeMirror.toString())) return true; + if ((typeMirror.getKind() == TypeKind.ARRAY) && type.isArray()) + return typeMirror.toString().equals(type.getComponentType() + "[]"); + if (typeMirror instanceof DeclaredType == false) return false; From 92590776e133a114f1002743e1af3fc878309fe2 Mon Sep 17 00:00:00 2001 From: Saulo Gil Date: Fri, 21 Jul 2017 13:10:44 -0300 Subject: [PATCH 5/9] Allow column type changes, letting SQLite attempt to perform the casting --- src/com/activeandroid/automigration/TableDifference.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/com/activeandroid/automigration/TableDifference.java b/src/com/activeandroid/automigration/TableDifference.java index d7356985b..78c92814c 100644 --- a/src/com/activeandroid/automigration/TableDifference.java +++ b/src/com/activeandroid/automigration/TableDifference.java @@ -1,5 +1,7 @@ package com.activeandroid.automigration; +import android.util.Log; + import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; @@ -39,7 +41,12 @@ public TableDifference(TableInfo tableInfo, SQLTableInfo sqlTableInfo) { if (existingColumnInfo.getType() == sqlColumnInfo.getType()) { mDifferences.put(sqlColumnInfo, existingColumnInfo); } else { - throw new IncompatibleColumnTypesException(tableInfo.getTableName(), existingColumnInfo.getName(), existingColumnInfo.getType(), sqlColumnInfo.getType()); + // allow column type changes just to let SQLite attempt to cast these values + Log.w(TableDifference.class.getName(), "potentially incompatible column types (table='" + + tableInfo.getTableName() + "' column='" + existingColumnInfo.getName() + + "' current type='" + existingColumnInfo.getType() + "' new type='" + + sqlColumnInfo.getType() + "')"); + mDifferences.put(sqlColumnInfo, existingColumnInfo); } } break; From 29105cb9731af62518d316b5ceb6b7d9c3083ad3 Mon Sep 17 00:00:00 2001 From: Saulo Gil Date: Fri, 6 Apr 2018 13:48:48 -0300 Subject: [PATCH 6/9] Improved MultiDex support --- src/com/activeandroid/ModelInfo.java | 81 ++++++++++++++++++++++------ 1 file changed, 65 insertions(+), 16 deletions(-) diff --git a/src/com/activeandroid/ModelInfo.java b/src/com/activeandroid/ModelInfo.java index f983cacf8..ac50fc87c 100644 --- a/src/com/activeandroid/ModelInfo.java +++ b/src/com/activeandroid/ModelInfo.java @@ -29,6 +29,8 @@ import java.util.Map; import android.content.Context; +import android.content.SharedPreferences; +import android.content.pm.ApplicationInfo; import com.activeandroid.serializer.CalendarSerializer; import com.activeandroid.serializer.FileSerializer; @@ -41,6 +43,12 @@ import dalvik.system.DexFile; final class ModelInfo { + private static final String PREFS_FILE = "multidex.version"; + private static final String SECONDARY_FOLDER_NAME = "code_cache" + File.separator + "secondary-dexes"; + private static final String EXTRACTED_NAME_EXT = ".classes"; + private static final String KEY_DEX_NUMBER = "dex.number"; + private static final String EXTRACTED_SUFFIX = ".zip"; + ////////////////////////////////////////////////////////////////////////////////////// // PRIVATE METHODS ////////////////////////////////////////////////////////////////////////////////////// @@ -125,28 +133,41 @@ private boolean loadModelFromMetaData(Configuration configuration) { private void scanForModel(Context context) throws IOException { String packageName = context.getPackageName(); - String sourcePath = context.getApplicationInfo().sourceDir; List paths = new ArrayList(); - if (sourcePath != null && !(new File(sourcePath).isDirectory())) { - DexFile dexfile = new DexFile(sourcePath); - Enumeration entries = dexfile.entries(); + try { + for (String sourcePath : getSourcePaths(context)) { + try { + if (sourcePath != null && !(new File(sourcePath).isDirectory())) { + DexFile dexfile; + if (sourcePath.endsWith(EXTRACTED_SUFFIX)) + dexfile = DexFile.loadDex(sourcePath, sourcePath + ".tmp", 0); + else + dexfile = new DexFile(sourcePath); + Enumeration entries = dexfile.entries(); - while (entries.hasMoreElements()) { - paths.add(entries.nextElement()); - } - } - // Robolectric fallback - else { - ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - Enumeration resources = classLoader.getResources(""); + while (entries.hasMoreElements()) { + paths.add(entries.nextElement()); + } + } + // Robolectric fallback + else { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + Enumeration resources = classLoader.getResources(""); - while (resources.hasMoreElements()) { - String path = resources.nextElement().getFile(); - if (path.contains("bin") || path.contains("classes")) { - paths.add(path); + while (resources.hasMoreElements()) { + String path = resources.nextElement().getFile(); + if (path.contains("bin") || path.contains("classes")) { + paths.add(path); + } + } + } + } catch (Exception e) { + e.printStackTrace(); } } + } catch (Exception e) { + e.printStackTrace(); } for (String path : paths) { @@ -155,6 +176,34 @@ private void scanForModel(Context context) throws IOException { } } + private static SharedPreferences getMultiDexPreferences(Context context) { + int mode = Context.MODE_PRIVATE | Context.MODE_MULTI_PROCESS; + return context.getSharedPreferences(PREFS_FILE, mode); + } + + private static List getSourcePaths(Context context) throws Exception { + ApplicationInfo applicationInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(), 0); + File sourceApk = new File(applicationInfo.sourceDir); + File dexDir = new File(applicationInfo.dataDir, SECONDARY_FOLDER_NAME); + + List sourcePaths = new ArrayList(); + sourcePaths.add(applicationInfo.sourceDir); + + String extractedFilePrefix = sourceApk.getName() + EXTRACTED_NAME_EXT; + int totalDexNumber = getMultiDexPreferences(context).getInt(KEY_DEX_NUMBER, 1); + + for (int secondaryNumber = 2; secondaryNumber <= totalDexNumber; secondaryNumber++) { + String fileName = extractedFilePrefix + secondaryNumber + EXTRACTED_SUFFIX; + File extractedFile = new File(dexDir, fileName); + if (extractedFile.isFile()) + sourcePaths.add(extractedFile.getAbsolutePath()); + else + throw new Exception("Missing extracted secondary dex file '" + extractedFile.getPath() + "'"); + } + + return sourcePaths; + } + private void scanForModelClasses(File path, String packageName, ClassLoader classLoader) { if (path.isDirectory()) { for (File file : path.listFiles()) { From 34bbab788a9e8fc2ff9d870d8e5ab06894ca4a72 Mon Sep 17 00:00:00 2001 From: Saulo Gil Date: Fri, 7 Dec 2018 18:07:29 -0300 Subject: [PATCH 7/9] Fix cache usage when trying to avoid the cache entirely --- src/com/activeandroid/util/SQLiteUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/activeandroid/util/SQLiteUtils.java b/src/com/activeandroid/util/SQLiteUtils.java index 01958529a..ba0bd2e91 100644 --- a/src/com/activeandroid/util/SQLiteUtils.java +++ b/src/com/activeandroid/util/SQLiteUtils.java @@ -397,7 +397,7 @@ public static List processCursor(Class typ entities.add((T) entity); // add to cache - if (entity.getId() != null) + if (useCache && entity.getId() != null) Cache.addEntity(entity); } while (cursor.moveToNext()); From c27d33011888e2b3278d772438b93f5cdc58ba0a Mon Sep 17 00:00:00 2001 From: Saulo Gil Date: Fri, 7 Dec 2018 20:03:01 -0300 Subject: [PATCH 8/9] Added test for non-cached reads --- tests/src/com/activeandroid/test/ModelTest.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/src/com/activeandroid/test/ModelTest.java b/tests/src/com/activeandroid/test/ModelTest.java index a86ad0b0f..1ae136599 100644 --- a/tests/src/com/activeandroid/test/ModelTest.java +++ b/tests/src/com/activeandroid/test/ModelTest.java @@ -232,6 +232,16 @@ public void testJoinWithSameNames() { } + public void testNonCachedReads(){ + MockModel cached = new MockModel(); + cached.save(); + + MockModel notCached = new Select().from(MockModel.class).where("id = ?", cached.getId()) + .setUseCache(false).executeSingle(); + + assertTrue(cached!=notCached); + } + /** * Mock model as we need 2 different model classes. */ From 552e633de8f370cae4dcecae7d5a44ad047549fa Mon Sep 17 00:00:00 2001 From: Saulo Gil Date: Sat, 25 Mar 2023 11:13:28 -0300 Subject: [PATCH 9/9] Added maven-publish plugin --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 5594e43b5..90157a8f7 100644 --- a/build.gradle +++ b/build.gradle @@ -1,4 +1,5 @@ apply plugin: 'java' +apply plugin: 'maven-publish' apply from: 'gradle-mvn-push.gradle' targetCompatibility = '1.6'