2013-04-11 4 views
13

앱 스토어에서 현재 앱을 사용할 수 있지만 완전히 이해할 수없는 오류 보고서 유형이 있습니다. 내 애플 내부 SQLite 데이터베이스를 사용하지만, 일부 장치 (확실히 대다수는) 다음과 같은 오류가 가끔 발생 :"android.database.sqlite.SQLiteException : 드문 경우의 오류"

android.database.sqlite.SQLiteException : 이러한 테이블을 : image_data (코드 1) : 컴파일하는 동안 : 카테고리 = '천문학'AND 스탬프> = 1,357,426,800과 합체 (title_nl, '') = ''

내가이 테이블이 존재하고 난 확신 image_data로부터 최소 (스탬프)을 선택 이 쿼리가 올바른지 확인하십시오. 나는이 오류가 앱의 위젯에서만 발생하고 AlarmManager에 의해 방송 된 BroadcastReceiver에서 발생한다는 것을 알고있다. (앱은 하루 앱의 그림처럼 새로운 항목을 다운로드하려고 시도한다.)

저는 데이터베이스에 액세스 할 때 Context와 관련이 있다고 생각합니다. AppContextHelper라는 클래스가 있는데,이 클래스는 Application을 확장하고 컨텍스트를 저장하는 정적 멤버를가집니다. 이 컨텍스트는 데이터베이스에 액세스 할 때 항상 사용됩니다.

내 질문 : 어떤 경우 위젯이나 앞서 언급 한 AlarmManager에 의해 방송 된 BroadcastReceiver에서 데이터베이스를 수집 할 때 그 컨텍스트가 유효하지 않을 수 있으며 그 경우 제공된 '컨텍스트'를 사용하여 '애플리케이션 '문맥? 그렇다면 컨텍스트가 잘못되었거나 더 나은 이유는 무엇입니까? 어떤 컨텍스트가 제공되는 것입니까?

미리 감사드립니다.

마찬가지로 위젯이나 AlarmManager 클래스의 일부 장치에서만 문제가 발생한 코드를 요청했습니다.

Intent myIntent = new Intent(AppContextHelper.getContext(), ApodDownloader.class); 
    mPendingIntent = PendingIntent.getBroadcast(AppContextHelper.getContext(), 0, myIntent, 0); 

    AlarmManager alarmManager = (AlarmManager)AppContextHelper.getContext().getSystemService(Context.ALARM_SERVICE); 
    Calendar calendar = Calendar.getInstance(); 
    calendar.setTimeInMillis(System.currentTimeMillis()); 

    alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis() + 10000, AlarmManager.INTERVAL_HOUR, mPendingIntent); 
  • AppContextHelper.java

    : 나는

    1. 알람을 초기화 코드 (즉, 적어도 라인 코드입니다)에 알람 관리기 클래스의 오류로 이어지는 코드를 게시 할 예정입니다

      public class AppContextHelper extends Application { 
      
          private static Context mContext; 
      
          @Override 
          public void onCreate() { 
           super.onCreate(); 
           mContext = this; 
          } 
      
          public static Context getContext(){ 
           return mContext; 
          } 
      } 
      
    2. (일부) ApodDownloader.java (여기에는 예외 발생 라인이 포함됨)

      @Override 
      public void onReceive(Context arg0, Intent arg1) { 
          (new AsyncTaskThreadPool<Integer, Void, Boolean>() { 
      
           @Override 
           protected Boolean doInBackground(Integer... params) { 
            Helpers.logMessage("Checking new entries."); 
      
      
            SQLiteDatabase db = FrescoDatabase.acquireReadableDatabase(AppContextHelper.getContext()); 
            try { 
             >>> THIS LINE THROWS THE EXCEPTION <<< 
             maxStamp = Helpers.executeScalarLong(db, "SELECT Min(stamp) FROM image_data WHERE category = 'Astronomy' AND stamp >= 1357426800 and coalesce(title_nl, '') = ''"); 
      
             [...] 
            } finally { 
             FrescoDatabase.releaseReadableDatabase(); 
            } 
      
            [...] more code 
      
           } 
           [...] onPostExecute 
          }).executeOnExecutor(AsyncTaskThreadPool.THREAD_POOL_EXECUTOR, 0); 
      
    3. FrescoDatabase.java 데이터베이스는 시작시 응용 프로그램에서 자동으로 생성되며이 코드는 작동하지만 예외를 발생시키는 장치에서도 작동합니다. AppManager가 위젯과 AlarmManager의 BroadcastReceiver를 제외하고 완벽하게 실행되기 때문에 데이터베이스가 문제가있는 장치에 있다는 것을 충분히 강조 할 수는 없습니다. db가 올바르게 초기화되지 않았다는 것을 알려주지 마십시오.

    4. (도의 일부) 도우미.자바

      public class Helpers { 
           [...] 
           public static long executeScalarLong(SQLiteDatabase db, String query) { 
            return executeScalarLong(db, query, new String[] { }); 
           } 
           public static long executeScalarLong(SQLiteDatabase db, String query, String... parameters) { 
            (line 85, see stack trace down below) Cursor cursor = db.rawQuery(query, parameters); 
            try { 
             cursor.moveToNext(); 
             long val = cursor.getLong(0); 
             return val; 
            } 
            catch (Exception e) { 
             ; 
            } 
            finally { 
             cursor.close(); 
            } 
            return -1; 
           } 
          } 
      

    예외 로그 (요청 된 바와 같이)

      java.lang.RuntimeException: An error occured while executing doInBackground() 
           at nl.tagpulse.utils.AsyncTaskThreadPool$3.done(AsyncTaskThreadPool.java:329) 
           at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273) 
           at java.util.concurrent.FutureTask.setException(FutureTask.java:124) 
           at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307) 
           at java.util.concurrent.FutureTask.run(FutureTask.java:137) 
           at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076) 
           at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569) 
           at java.lang.Thread.run(Thread.java:856) 
           Caused by: android.database.sqlite.SQLiteException: no such table: image_data (code 1): , while compiling: SELECT Min(stamp) FROM image_data WHERE category = 'Astronomy' AND stamp >= 1357426800 and coalesce(title_nl, '') = '' 
           at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method) 
           at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:1012) 
           at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:623) 
           at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588) 
           at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:58) 
           at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:37) 
           at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:44) 
           at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1314) 
           at android.database.sqlite.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1253) 
           at nl.tagpulse.fresco.other.Helpers.executeScalarLong(Helpers.java:85) 
           at nl.tagpulse.fresco.other.Helpers.executeScalarLong(Helpers.java:82) 
           at nl.tagpulse.fresco.business.FrescoDatabase.retrieveNewEntries(FrescoDatabase.java:64) 
           at nl.tagpulse.fresco.business.ApodDownloader$1.doInBackground(ApodDownloader.java:192) 
           at nl.tagpulse.fresco.business.ApodDownloader$1.doInBackground(ApodDownloader.java:1) 
           at nl.tagpulse.utils.AsyncTaskThreadPool$2.call(AsyncTaskThreadPool.java:317) 
           at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) 
           ... 4 more 
    

    는 I는 Helpers.java 블록에서 라인 (85) 마커를 추가했다.

    희망이 도움이됩니다.

  • +1

    자바 코드를 게시하면 아무 것도 할 수 없습니다. – Sajmon

    +0

    코드를 추가하여 명확히하려고했습니다. 희망이 도움이됩니다. – Toverbal

    +0

    도 오류 로그를 게시하십시오. – kdehairy

    답변

    4

    여기에 무슨 일이 일어나고있는 작업은 다음과 같습니다

    ApodDownloader는 브로드 캐스트 리시버이고 그것의 onReceive()에서 당신이 허용되지 않습니다 어떤 종류의 AsyncTask를 시작합니다. 문서 상태 :

    브로드 캐스트 리시버 오브젝트가 onReceive 호출 기간 (문맥, 의도)에 대해서만 유효합니다. 이 함수에서 코드가 반환되면 시스템은 객체가 완료된 것으로 간주하고 더 이상 을 활성화하지 않습니다.

    이것은 당신이 onReceive에서 무엇을 할 수 있는지에 중요한 영향 (문맥, 의도) 구현이있다 : 당신이 비동기 작업을 처리하기 위해 함수에서 반환해야하므로, 비동기 작업을 필요로 사용할 수없는 것을, 그러나 에서 BroadcastReceiver는 더 이상 활성 상태가 아니므로 이 완료되기 전에 시스템은 프로세스를 종료 할 수 있습니다. 프로세스가 응용 프로그램 컨텍스트를 살해

    http://developer.android.com/reference/android/content/BroadcastReceiver.html#ReceiverLifecycle

    는 더 이상 사용할 수 없습니다. AppContextHelper.getContext()에 계속 액세스 할 수는 있지만 이전에로드 된 클래스는 프로세스를 제거 할 때 종료되므로 새로로드 된 클래스가됩니다. 즉, 돌려 주어지는 컨텍스트는 null가됩니다. 이것은 드물게 Android가 실제로 내 경험에없는 프로세스를 죽이는 경우에만 발생합니다.

    AppContextHelper가 제공하는 컨텍스트가 아직 초기화되지 않은 경우 InitializeFrescoDatabaseTask.getDatabaseFileName (context) 호출은 빈 문자열을 반환하고 자연스럽게 잘못된 데이터베이스를 엽니 다. FrescoDatabase 클래스의 onCreate()에서 아무 일도하지 않기 때문에 데이터베이스가 올바르게 초기화되지 않아 테이블을 찾지 못합니다. 그러나 테이블을 만들더라도 잘못된 데이터베이스가되고 충돌은 사라지더라도 데이터가 표시되지 않습니다.

    이 문제를 방지하려면 onReceive()가 실행중인 것과 동일한 스레드에서 모든 작업을 수행해야합니다. 너무 오래 걸리면 무거운 작업을 수행하는 데 시간이 오래 걸립니다.

    코드를 분석 할 때 알아 차 렸던 또 하나의 점은 알람을 만들 때 응용 프로그램 컨텍스트를 사용하여 새로운 의도 (AppContextHelper.getContext(), ApodDownloader.class);)를 작성한다는 것입니다. 이 작업을 수행 할 때 FLAG_ACTIVITY_NEW_TASK를 설정해야하거나 "android.util.AndroidRuntimeException : Activity 컨텍스트 외부에서 startActivity()를 호출하려면 FLAG_ACTIVITY_NEW_TASK 플래그가 필요합니다. 정말로 원하는 것입니까?" 앱을 크래시 할 수도,하지 않을 수도 있습니다.

    +0

    나는 이것이 Toverbal과 마주 치는 문제에 대한 해답이 될 수 있다는 것에 동의합니다. 내 문제를 해결하지는 않지만 확인을위한 새로운 아이디어를 나에게주었습니다. – Raanan

    +0

    @ Raanan : 프로젝트에 대한 정보를 제공하지 않으면 도움을 줄 수 없습니다. 어쩌면 당신 자신의 질문을 열 수 있을까요? –

    +0

    예, 동의합니다. 그러나 제 자신의 질문을하기 전에 먼저 몇 가지 테스트를 더 실시 할 것입니다. 당신의 대답이 Toverbal에 의해 받아 들여지면 현상금을 당신에게 줄 것입니다. – Raanan

    관련 문제