2014-09-18 3 views
4
내 안드로이드 응용 프로그램의 Crashlytics - 로그이 코드는 NullPointerException에서 볼

: 이전 개발자가 더 이상 사용할 수없는 것처럼getReadableDatabase은 종종하지만 항상 null을 반환

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

mSQLDBreader... // NPE 

, 내가하지 두 번 시도한 이유를 알고 있지만 코드가 가끔씩 작동하는 것처럼 보이지만 종종 그렇지 않은 경우가 있습니다. 이 호출이 null을 반환하는 이유는 무엇입니까?

내 crashlogs에서 2.3.x와 2.3.6이 발생하는 것처럼 보입니다.

enter image description here

답변

0

나는 과거에 비슷한 문제에 달려있다. 계속 닫고 데이터베이스를 열면 나에게이 문제가 발생했습니다. SQLLiteOpenHelper을 사용하는 경우 정말 좋은 이유가없는 한 데이터베이스를 닫지 않아야합니다.

SQLiteOpenHelper 당신이 getReadableDatabase()와 검색 데이터베이스에 보유 말한다 CommonsWare 응답 here를 참조/getWritableDatabase() 및 지점은 가 당신이에서 일을 특히로서,의 SQLiteDatabase 객체를 열어 재사용을위한 여러 스레드.

1

나만의 작품에 스레딩이 있습니까? 어떤 코드가 mSQLDBreader을 다른 방법으로 재설정 중일 수 있습니다. 아마도이 스레드는 사용하기 전에 가끔씩 실행되고 mSQLDBreader의 값을 삭제합니다.

2.3.x를 실행하는 에뮬레이터에서 목격 한 적이 있습니까?

Google의 getReadableDatabase 코드를 살펴본 결과 null이 반환 될 수있는 방법이 표시되지 않습니다. 당신이 관심이 있다면 피투성이의 세부 사항은 아래 있습니다. 내가 본 것에 기반하여 코드의 멀티 스레딩 버그 나 테스트 한 장치 제조업체의 안드로이드 코드에 대한 사용자 정의로 인한 버그가 의심 스러울 것입니다 (그럴만한 경우 그럴 수도 있습니다).

세부 정보 getReadableDatabase를 통한 모든 경로는 경로를 작성한 후 리턴 오브젝트에서 메소드를 호출합니다. 따라서이 값은 null이 될 수 없습니다. 그렇지 않으면 NPE가 내부에서 제기됩니다.

다음은 getReadableDatabase에 대한 2.3.6 코드 스 니펫입니다. 실제 출처는 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의 close 메소드의 모두 동기화와 태그 것이 중요합니다, 그래서 하나의 방법은 쓰레기 수있는 방법은 없습니다 동시에 이러한 메서드를 호출 할 여러 스레드가있는 경우 다른 상태 .. 사용하기 전에

0

개방형 데이터베이스

if (mDatabase != null && mDatabase.isOpen()) { 
    return mDatabase; // The database is already open for business 
} else { 
    return mDatabase.open(); 
} 
관련 문제