2014-09-18 4 views
4

я вижу в Crashlytics-Лог моего андроида приложения NullPointerException в этом коде:getReadableDatabase часто, но не всегда возвращает нуль

try { 
    mSQLDBreader = this.getReadableDatabase(); 
} catch (SQLException e) { 
    if (mSQLDBreader != null) { 
     mSQLDBreader.close(); 
     mSQLDBreader = this.getReadableDatabase(); 
    } 
} 

mSQLDBreader... // NPE 

Как предыдущий разработчик не доступен больше, я не знаете, почему это делается два раза, но код, кажется, работает иногда, но часто нет. Каковы могут быть причины, по которым этот вызов возвращает null?

Похоже, что если это происходит только на устройствах 2.3.x, в моих авариях все уязвимые устройства - 2.3.5 и 2.3.6.

enter image description here

ответ

0

Я столкнулся с аналогичной проблемой в прошлом. Похоже, держать закрытие и открытие базы данных создало эту проблему для меня. Если вы используете SQLLiteOpenHelper, вы не должны закрывать свою базу данных, если у вас нет по-настоящему веской причины. См CommonsWare ответа here, который говорит

SQLiteOpenHelper держит в базе данных извлекаются с getReadableDatabase()/getWritableDatabase(), и точка для вас для повторного использования, которые открыли объект SQLiteDatabase, в частности, как вы делаете работы по несколько потоков.

1

У вас есть какие-либо потоки вашего собственного творения? Некоторый код, который может быть сброшен mSQLDBreader другим способом. Возможно, этот поток иногда запускает и уничтожает значение mSQLDBreader перед его использованием?

Вы когда-нибудь видели это на эмуляторе под управлением 2.3.x?

Я посмотрел код google для getReadableDatabase, и я не вижу способа вернуть его. Если вы заинтересованы, подробности ниже. Основываясь на том, что я вижу, я бы заподозрил либо многопоточную ошибку в вашем коде, либо ошибку, внесенную настройками в код андроида производителем тестируемых устройств (если это даже правдоподобно.)

Gory details Все пути через getReadableDatabase вызывают методы на возвращаемом объекте после его создания. Таким образом, значение не может быть нулевым в этой точке. В противном случае NPE будет поднят изнутри.

Ниже приведен фрагмент кода 2.3.6 для getReadableDatabase. Фактический источник доступен по адресу grepcode.

public synchronized SQLiteDatabase getReadableDatabase() { 
    if (mDatabase != null && mDatabase.isOpen()) { 
     return mDatabase; // The database is already open for business 
    } 

    if (mIsInitializing) { /* snip throw ISE */ } 

    try { 
     return getWritableDatabase(); 
    } catch (SQLiteException e) { 
     // snip : throws or falls through below 
    } 

    SQLiteDatabase db = null; 
    try { 
     mIsInitializing = true; 
     String path = mContext.getDatabasePath(mName).getPath(); 
     db = SQLiteDatabase.openDatabase(path, mFactory, SQLiteDatabase.OPEN_READONLY); 

     // *** next line calls method on db. NPE would be here if db was null at this point. *** 
     if (db.getVersion() != mNewVersion) { 
      // snip throw. 
     } 

     onOpen(db); 
     Log.w(TAG, "Opened " + mName + " in read-only mode"); 
     mDatabase = db; 
     return mDatabase; 
    } finally { 
     // snip : not relevant 
    } 
} 

Обратите внимание, что getReadableDatabase обычно возвращает результат getWritableDatabase. Он выглядит следующим образом:

public synchronized SQLiteDatabase getWritableDatabase() { 
    if (mDatabase != null && mDatabase.isOpen() && !mDatabase.isReadOnly()) { 
     return mDatabase; // The database is already open for business 
    } 

    if (mIsInitializing) { 
     throw new IllegalStateException("getWritableDatabase called recursively"); 
    } 

    // snip comment about locking 
    boolean success = false; 
    SQLiteDatabase db = null; 
    if (mDatabase != null) mDatabase.lock(); 
    try { 
     mIsInitializing = true; 
     if (mName == null) { 
      db = SQLiteDatabase.create(null); 
     } else { 
      db = mContext.openOrCreateDatabase(mName, 0, mFactory); 
     } 

     int version = db.getVersion(); // ** method called on result! 
     // snip block that has more method calls and never nulls out db 
     onOpen(db); 
     success = true; 
     return db; 
    } finally { 
     // snip 

     mDatabase = db; 

     // snip rest of finally block that isn't relevant. 
    } 
} 

Наконец, важно отметить, что оба эти методы, а также близкий метода SqliteOpenHelper, помечаются синхронизацией, так что нет никакого способа один способ громить состояние других, если у вас есть несколько потоков, призывающих эти методы в то же время ..

0

открыть базы данных перед использованием

if (mDatabase != null && mDatabase.isOpen()) { 
    return mDatabase; // The database is already open for business 
} else { 
    return mDatabase.open(); 
} 
Смежные вопросы