Перезаписывается база данных (нужно дважды открыть приложение для корректного отображения)?

#java #android

#java #Android

Вопрос:

ПОСЛЕДНЕЕ: проверьте код внизу для моего решения для взлома..

ОРИГИНАЛ: Я следовал некоторым руководствам и примерам и пошел и создал свою собственную базу данных. Проблема в том, что когда я загружаю базу данных на телефон, она должна быть прочитана и заполнить счетчик.. я обнаружил, что загруженная база данных не повреждена, но когда она считывается dbhelper, она каким-то образом перезаписывается в пустую таблицу. Я не могу понять, почему.

ПРАВКА1: Извините, я должен был выразиться более ясно. База данных поступает с сервера. оно загружается непосредственно в /data/data / project/databases / . Именно там я проверил файл после его загрузки. Все было хорошо, пока я не вызвал ‘DBAdapter mDbHelper = новый DBAdapter (контекст); mDbHelper.open («имена»);’ после чего таблица метаданных Android и таблица имен и таблица sqlite все еще находятся в базе данных, столбцы имеют имена, но в них нет записей, поэтому таблица по существу пуста.

ПРАВКА2: (извините, что так длинно)

Я прокомментировал следующее:

 c = initSpinner(c);
  

это метод, который я написал на случай, если курсор вернется! moveToFirst() . в этом методе создается база данных и «добавить имя» вставляется в таблицу.

Затем я немного поиграл с приложением, и вот что я нашел:

когда я впервые открываю приложение на своем устройстве при чистой установке, счетчик показывает значение по умолчанию «добавить имя». итак, я добавляю имя.. Я снова открываю приложение, и введенное мной имя появляется там вместе с надписью «добавить имя»… перейдите к эмулятору после очистки всех данных и удаления .. откройте приложение, и там только «добавить имя» .. вернитесь и снова откройте, и на счетчике есть «добавить имя» и имя, которое я ввел на своем телефоне… итак, я добавляю имя в эмулятор, возвращаюсь к своему телефону, закрываю и снова открываю приложение, и теперь там есть 2 имени и «добавить имя»…

Резюме: Это работает, но я должен повторно открыть приложение после первоначальной установки, чтобы прочитать базу данных и правильно заполнить счетчик. Почему?

ПРАВКА 3 (последняя): смотрите код в конце для решения взлома..

вот код, который заполняет счетчик.

     private void fillSpinner(){

    DbAdapter mDbHelper = new DbAdapter(context);
    mDbHelper.open("names");

    Cursor c = mDbHelper.fetchAllRows();
    ArrayList<String> a = new ArrayList<String>();

    if ( c.getPosition() != 0 amp;amp; c.moveToFirst() == (false) ){
//          c = initSpinner(c); //commented out to prevent creating a new     //database.
    }
  

вот код DBAdapter.

 public class DbAdapter {

// Database fields
public static final String KEY_ROWID = "_id";
public static final String KEY_NAME = "name";

static final String DATABASE_TABLE = "names";
private Context context;
private SQLiteDatabase database;
private DbHelper dbHelper;


public DbAdapter(Context ctx) {
    context = ctx;

}

public SQLiteDatabase openToRead() throws SQLException {
    dbHelper = new DbHelper(context);
    database = dbHelper.getReadableDatabase();

    return database;
}

public SQLiteDatabase open(String dbname) throws SQLException {
    dbHelper = new DbHelper(context);
    database = dbHelper.getWritableDatabase();
    return database;
}

public void close() {
    dbHelper.close();
}

//  
/**
 * Create a new todo If the todo is successfully created return the new
 * rowId for that note, otherwise return a -1 to indicate failure.
 */

public long createRow(String name) {
    ContentValues initialValues = createContentValues(name);
    return database.insert(DATABASE_TABLE, null, initialValues);
}

public long createRowWithAL(ArrayList<String> values){

    ContentValues v = ArrayListToContentValues(values);

    return database.insert(DATABASE_TABLE, null, v);

}

private ContentValues ArrayListToContentValues(ArrayList<String> parcel){

    ContentValues values = new ContentValues();

//      values.put(KEY_ROWID, _id);
    values.put(KEY_NAME, parcel.get(0));
    return values;
}



/**
 * Update the todo
 */

public boolean updateRows(long rowId, 
        String name) {

    ContentValues updateValues = createContentValues(
            name);

    return database.update(DATABASE_TABLE, updateValues, KEY_ROWID   "="
              rowId, null) > 0;
}


/**
 * Deletes todo
 */

public boolean deleteRow(long rowId) {
    return database.delete(DATABASE_TABLE, KEY_ROWID   "="   rowId, null) > 0;
}


/**
 * Return a Cursor over the list of all todo in the database
 * 
 * @return Cursor over all notes
 */

public Cursor fetchAllRows() {
    return database.query(DATABASE_TABLE, null, null, null, null,
            null, null);
}


/**
 * Return a Cursor positioned at the defined todo
 */

public Cursor fetchRow(long rowId) throws SQLException {
    Cursor mCursor = database.query(true, DATABASE_TABLE, new String[] {
            KEY_ROWID ,KEY_NAME},
            KEY_ROWID   "="   rowId, null, null, null, null, null);
    if (mCursor != null) {
        mCursor.moveToFirst();
    }
    return mCursor;
}


private ContentValues createContentValues(String name){

    ContentValues values = new ContentValues();

    values.put(KEY_NAME, name);
    return values;
}

//returns (an) entire column(s), all rows
public Cursor fetchColumns(String[] colnames) {
    Cursor mCursor = database.query(DATABASE_TABLE, colnames, null, 
            null, null, null, null);
    if (mCursor != null) {
        mCursor.moveToFirst();
    }
    return mCursor;
}
  

}

Вот код DBHelper.

 public class DbHelper extends SQLiteOpenHelper {

Context context;

private static final String DATABASE_NAME = "names";
private static final int DATABASE_VERSION = 1;

// Database creation sql statement
private static final String DATABASE_CREATE = "create table if not exists " DATABASE_NAME " (_id integer primary key autoincrement, "  
    "name text not null);";

public DbHelper(Context context) {
    super(context, DATABASE_NAME, null, DATABASE_VERSION);

}

// Method is called during creation of the database
@Override
public void onCreate(SQLiteDatabase database) {

    database.execSQL(DATABASE_CREATE);
}

// Method is called during an upgrade of the database, e.g. if you increase
// the database version
@Override
public void onUpgrade(SQLiteDatabase database, int oldVersion,
        int newVersion) {
    Log.w(DbHelper.class.getName(),
            "Upgrading database from version "   oldVersion   " to "
                      newVersion   ", which will destroy all old data");
    database.execSQL("DROP TABLE IF EXISTS names");
    onCreate(database);
  

}
}

—ВЗЛОМАТЬ КОД:

     private void fillSpinner(){

    DbAdapter mDbHelper = new DbAdapter(context);
    mDbHelper.open("name");
        mDbHelper.createRow("Add Name"); //added this
    mDbHelper.close();               //added this
    downloadFile();                  //added this
    mDbHelper.open("names");

    Cursor c = mDbHelper.fetchAllRows();
    ArrayList<String> a = new ArrayList<String>();

    if ( c.getPosition() != 0 amp;amp; c.moveToFirst() == (false) ){
        c.close();          

        mDbHelper.createRow("Add Name");
        c = mDbHelper.fetchColumns(new String[] {"_id","name"});
    }
  

Комментарии:

1. onUpgrade Когда-нибудь вызывается во время этого? Похоже, это единственное место в вашем коде, где вы явно удаляете записи в базе данных и воссоздаете таблицу заново, поэтому это кажется вероятным подозрением.

2. я почти уверен, что это не так, поскольку версия db не меняется.. проверьте код взлома, я заставил его работать. все еще не понимаю, почему..

Ответ №1:

Что вы подразумеваете под «когда я загружаю базу данных на телефон»? Я предполагаю, что вы включаете свою базу данных в свои ресурсы? Если это так…

SQLiteOpenHelper ищет базу данных в частном внутреннем хранилище приложений. Он не найдет ни одной и, следовательно, создаст новую базу данных во внутреннем хранилище. Это база данных, из которой он затем будет считывать.

Пара вариантов, которые приходят мне в голову:

  1. Создайте и заполните базу данных в вашем DbHelper onCreate (вместо того, чтобы просто создавать пустую базу данных, как вы делаете в данный момент). Если это небольшая простая база данных, я бы сделал это.
  2. Копирование из ресурсов во внутреннее хранилище. Пример http://www.reigndesign.com/blog/using-your-own-sqlite-database-in-android-applications /

Комментарии:

1. Извините, я должен был выразиться более ясно. База данных поступает с сервера. оно загружается непосредственно в /data/data / project/databases / . Именно там я проверил файл после его загрузки. Все было хорошо, пока я не вызвал ‘DBAdapter mDbHelper = новый DBAdapter (контекст); mDbHelper.open («имена»);’ после чего таблица метаданных Android и таблица имен и таблица sqlite все еще находятся в базе данных, столбцы имеют имена, но в них нет записей, поэтому таблица по существу пуста.

2. Я предполагаю, что поля первичного ключа также уже названы _id? В этом случае мое ограниченное количество идей выполнено.

3. они называются _id, да. каким-то образом, когда я вызываю db для открытия и начинаю чтение, вместо этого создается новая база данных с пустой таблицей внутри.

Ответ №2:

Я нашел этот хак / обходной путь, но почему он работает?

 private void fillSpinner(){

DbAdapter mDbHelper = new DbAdapter(context);
mDbHelper.open("name");
    mDbHelper.createRow("Add Name"); //added this
mDbHelper.close();               //added this
downloadFile();                  //added this
mDbHelper.open("names");

Cursor c = mDbHelper.fetchAllRows();
ArrayList<String> a = new ArrayList<String>();

if ( c.getPosition() != 0 amp;amp; c.moveToFirst() == (false) ){
    c.close();          

    mDbHelper.createRow("Add Name");
    c = mDbHelper.fetchColumns(new String[] {"_id","name"});
}