Предполагая, что вы не ошибочно полагаете, что запуск приложения на эмуляторе (или на любом устройстве) изменит пакет так, что в дистрибутив будет включена заполненная база данных
тогда я подозреваю, что вы преждевременно вызываете: -
database = this.openOrCreateDatabase("person", MODE_PRIVATE, null);
В результате будет создана база данных людей без человекатаблицы и, следовательно, приведет к ошибке, которую вы описали.
Вам необходимо загрузить данные перед использованием вышеуказанной строки.
Альтернативно, если вы добавили следующий код сразу после database = this.openOrCreateDatabase("person", MODE_PRIVATE, null);
Cursor csr = database.query("sqlite_master",null,"name='person'",null,null,null,null);
if (csr.getCount() < 1) {
database.execSQL("CREATE TABLE IF NOT EXISTS person (name VARCHAR, name_size INT(8))");
........ rest of the code that inserts data from the person.txt asset
}
Таблица будет создана.Тем не менее, он будет пустым (вы можете скопировать данные из ресурса person.txt здесь)
Дополнительный комментарий: -
Спасибо за ответ.Не уверен, что вы пропустили ту часть, где я упоминал, что создание базы данных уже сделано, и эта часть была закомментирована.Я однажды вызвал создание БД и загрузил его с данными, а БД сейчас просто сидит в приложении (по крайней мере, для эмулятора).Упомянутая вами инициализация должна открыть существующую базу данных с существующей таблицей, поэтому я не понимаю, почему это было бы преждевременно.
Ниже приведена довольно солидная переделка вашего кода, которая будет обслуживать то, что яПоверьте, это может быть наиболее вероятными причинами: -
public class MainActivity extends AppCompatActivity {
public static final String DBNAME = "person";
public static final String TBNAME = "person";
public static final String COL_NAME = "name";
public static final String COL_NAME_SIZE = "name_size";
public static final String ASSET_FILENAME = "person.txt";
public static final String SQLITE_MASTER_TABLE = "sqlite_master";
public static final String COL_SQLITE_MATSER_NAME = "name";
static final int MIMINUM_ROWS_IN_PERSONTABLE = 1;
SQLiteDatabase db;
BufferedReader br;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
checkPersonTable(); // Notes sets db either way
// FOR TESTING
long rows_in_person_table = DatabaseUtils.queryNumEntries(db,TBNAME);
Log.d(
"PERSON ROW COUNT",
"The number of rows in the " +
TBNAME +
" table is " +
String.valueOf(rows_in_person_table)
);
}
private void checkPersonTable() {
db = this.openOrCreateDatabase(DBNAME, Context.MODE_PRIVATE,null);
// Database will now exist but it may or may not contain the person table so check sqlite_master
Cursor csr = db.query(
SQLITE_MASTER_TABLE,
new String[]{COL_SQLITE_MATSER_NAME},
COL_SQLITE_MATSER_NAME + "=?",
new String[]{TBNAME},
null,null,null
);
// Cursor will contain 1 row if the person table exists so check count
int person_table_count = csr.getCount();
csr.close();
// Before attemtping to create the Person table ensure that the assets file exists
// If not then throw a RunTime exception
if (person_table_count < 1) {
try {
if (!Arrays.asList(getResources().getAssets().list("")).contains(ASSET_FILENAME)) {
StringBuilder sb = new StringBuilder();
throw new RuntimeException("Asset file " +
ASSET_FILENAME +
" not found in the assets folder." +
" The following assets were found" +
sb
);
}
} catch (IOException e) {
e.printStackTrace();
}
}
if (person_table_count < 1) {
db.execSQL("CREATE TABLE IF NOT EXISTS " + TBNAME +
"(" +
COL_NAME + " TEXT," +
COL_NAME_SIZE + " INTEGER" +
")"
);
loadPersonsFromAssets();
} else {
// <<<<<<<<<< NOTE Optional will load data from assets if miminum nuber of rows
// aren't in the person table
if (DatabaseUtils.queryNumEntries(db,TBNAME) < MIMINUM_ROWS_IN_PERSONTABLE) {
loadPersonsFromAssets();
}
}
}
// Load the person table from the Assets File
private void loadPersonsFromAssets() {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(getAssets().open(ASSET_FILENAME)));
String line, sql;
int lines_read = 0;
db.beginTransaction();
while ((line = br.readLine()) != null) {
sql = "INSERT INTO " + TBNAME + " VALUES('" + line + "'," + String.valueOf(line.length()) + ")";
db.execSQL(sql);
lines_read++;
}
db.setTransactionSuccessful();
db.endTransaction();
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("Asset File " + ASSET_FILENAME + " not found in the assets folder.");
}
}
}
Это будет: -
- попытаться открыть базу данных только один раз, установив объект SQliteDatabase, когда это произойдет.
- создаст базу данных person , если она не существует, а затем создаст таблицу person.
- Даже если база данных существует, она продолжает проверять, существует ли таблицаи создаст его, если этого не произойдет.
- Исключением является случай, если файл ресурса не существует в папке ресурсов, и в этом случае будет сгенерировано исключение времени выполнения (как если бы этого не было,что-то радикально неправильное, так как оно всегда должно существовать как часть пакета)в нескольких строках (в зависимости от значения MIMINUM_ROWS_IN_PERSONTABLE ).
Если файл активов person.txt не существует, вы получите исключение, аналогичное: -
06-10 03:58:43.503 3097-3097/personthing.so50777840 E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity ComponentInfo{personthing.so50777840/personthing.so50777840.MainActivity}: java.lang.RuntimeException: Asset file person.txt not found in the assets folder. The following assets were found
found asset file :- images
found asset file :- notperson.txt
found asset file :- sounds
found asset file :- webkit
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2059)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
at android.app.ActivityThread.access$600(ActivityThread.java:130)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4745)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.RuntimeException: Asset file person.txt not found in the assets folder. The following assets were found
found asset file :- images
found asset file :- notperson.txt
found asset file :- sounds
found asset file :- webkit
at personthing.so50777840.MainActivity.checkPersonTable(MainActivity.java:83)
at personthing.so50777840.MainActivity.onCreate(MainActivity.java:39)
at android.app.Activity.performCreate(Activity.java:5008)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023)
... 11 more
- Примечание Как видно, person.txt "неправильно" названо notperson.txt чтобы вызвать ошибку.
Обратите внимание, что на этом этапе база данных будет существовать (из-за openOrCreateDatabase
) и будет содержать две таблицы (sqlite_master и android_metadata), но не таблицу person, например: -

Однако создание правильного файла активов person.txt (переименование notperson.txt в person.text) приведет ктаблица создается и загружается с данными: -
например, если person.txt: -

После запуска приложениярезультат в журнале, содержащем: -
06-10 04:39:04.277 3325-3325/? D/PERSON ROW COUNT: The number of rows in the person table is 11