从未在数据库上显式调用Close

时间:2014-01-15 03:45:09

标签: java android sqlite

这个问题已被多次询问,我认为我的情况有点不同。

早些时候 我在类级别声明了我的db对象:

DBAdapter dbHelper; 
在onCreate中

dbHelper = new DBAdapter(this);

我在破坏中关闭了数据库:

@Override
    public void onDestroy(){
        super.onDestroy();
        if (dbHelper != null) 
        {
            dbHelper.close();
        }

    }

但是每次我写入数据库时​​都会出错。关闭后从未明确调用DB它也有一些关于数据库锁的例外。

问题

我有一个异步任务,在此我逐个更新每个记录的三个表。 (操作确实很大)但现在我将DB init的代码转移到我的异步任务。在执行前我初始化数据库,然后我在onPostExecute中关闭数据库。但问题仍然存在,这个问题的解决方案是什么?下面是我的异步任务的代码:

private class MagicCall extends AsyncTask<Void, String, String> {

        int years; 
        long secon; 
        long min; 
        int hours;
        int mon; 
        int days;
        int weeks;
        String CONTACT_ID,CONTACT_NAME,CONTACT_IMAGE_URI; 

        ProgressDialog Asycdialog = new ProgressDialog(LoaderClass.this);

        @Override
        protected void onPreExecute() {
            dbHelper = new DBAdapter(getApplicationContext());
            dbHelper.open();
            //Init the LoaderDialog 
            Asycdialog.setMessage("Working");
            Asycdialog.getWindow().setGravity(Gravity.CENTER_VERTICAL);
            Asycdialog.getWindow().setGravity(Gravity.CENTER_HORIZONTAL);
            Asycdialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
            Asycdialog.setCancelable(false);
            //Dialog Show
            Asycdialog.show();
            super.onPreExecute();
        }

        protected void onPostExecute(String result) {
            // hide the dialog
            dbHelper.close();
            Asycdialog.dismiss();
            startActivity(new Intent(LoaderClass.this, MainActivity.class));
            finish();
            super.onPostExecute(result);
        }

        @Override
        protected String doInBackground(Void... args) {


            // 
            // Dear maintainer:
            // 
            // Once you are done trying to 'optimise' this routine,
            // and have realized what a terrible mistake that was,
            // please increment the following counter as a warning
            // to the next guy:
            // 
            // total_hours_wasted_here = 0;
            //
            int lines = 0;
            try{
                BufferedReader reader;
                if(FLAG ==1){
                    reader = new BufferedReader(new FileReader("/sdcard/BirthdayReminders/fileone.txt"));
                }else{
                    reader = new BufferedReader(new FileReader("/sdcard/BirthdayReminders/output.txt"));
                }
                while (reader.readLine() != null) lines++;
                reader.close();
            }catch(Exception e){

            }



            dbHelper.NotificationDrop(); 
            int i=0;
            File toRead = null;
            try{
                if(FLAG ==1){
                    toRead=new File("/sdcard/BirthdayReminders/fileone.txt");
                }else{
                    toRead=new File("/sdcard/BirthdayReminders/output.txt");
                }
                FileInputStream fis=new FileInputStream(toRead);

                Scanner sc=new Scanner(fis);

                //read data from file line by line:
                String currentLine;
                while(sc.hasNextLine()){


                    currentLine=sc.nextLine();
                    //now tokenize the currentLine:
                    StringTokenizer st=new StringTokenizer(currentLine,"=",false);
                    //put tokens ot currentLine in map
                    //  mapInFile.put(st.nextToken(),st.nextToken());

                    String dateStr = st.nextToken();
                    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
                    Date date = format.parse(dateStr);
                    java.sql.Date dx = new java.sql.Date(date.getTime());
                    Date key = dx;
                    String dateToInsert = String.valueOf(dx); 
                    // *********
                    String listStr = st.nextToken();

                    String cut = listStr.substring(1, listStr.length() - 1);

                    String[] array = cut.split(",");
                    CONTACT_ID = (array[0].trim());

                    CONTACT_NAME = toTitleCase(array[1].trim());

                    if(array[2].contains(".jp"))
                        array[2] = array[2].replace(".jp", ".jpg").trim();
                    CONTACT_IMAGE_URI = (array[2].trim());


                    if (isCancelled()) {
                        break;
                    }
                    //  int k = Sx.size();


                    String progress = ("" + Character.toUpperCase(CONTACT_NAME.charAt(0)) + CONTACT_NAME.substring(1) + "\n"+i + " of " + lines + " Contacts"); // Progress displayed here. 



                    years = getDiffYear(key);               // For years elapsed
                    secon = seconds(key);                   // for seconds elapsed
                    min = seconds(key) / 60;                // For minutes elapsed
                    hours = (int) (seconds(key) / 60) / 60; // For hours elapsed
                    mon = months(String.valueOf(key));                      // for months elapsed

                    days = daysElapsed(key);                // Days elapsed
                    weeks = daysElapsed(key) / 7;           // For weeks

                    //===============================================================================================================
                    if (dateToInsert.contains("0001-") == true){ //Special Case, we added 0001 to Birthdays Which Have NO Year field. 
                        //===========================================================================================================

                        dbHelper.insert(dateToInsert, CONTACT_NAME, "","", CONTACT_IMAGE_URI, "", "", "", CONTACT_ID, "", ""); // All other fields will be empty, because we don't have a Year. 
                        int PRIMARY_ID = dbHelper.getPrimaryId();
                        String FOREIGN_KEY = dbHelper.getHighestID(PRIMARY_ID); 


                        //=====================================================================================================
                        //In this case we are only interested in fetching the year alert for next birthday of this contact -->
                        //=====================================================================================================

                        intCal.yearsToNotify(years, dateToInsert); 
                        int yearsSpecial = intCal.getYearsRegular();
                        Date dateYearsReg = intCal.getYearsRegDate();

                        dbHelper.insertNotifications(5, convertDate(dateYearsReg), 0, yearsSpecial,FOREIGN_KEY,PRIMARY_ID); 

                    }
                    //=========================================================================
                    //Case when all the Date fields exist and we set up notifications  --->
                    //=========================================================================
                    else if(dateToInsert != "null" && dateToInsert.contains("0001-") != true){

                        dbHelper.insert(dateToInsert, CONTACT_NAME, String.valueOf(days), String.valueOf(hours), CONTACT_IMAGE_URI, String.valueOf(min),String.valueOf(mon), String.valueOf(secon), CONTACT_ID, String.valueOf(weeks), String.valueOf(years));

                        int PRIMARY_ID = dbHelper.getPrimaryId(); // Fetch the PrimaryId (_id) of the above inserted row, its the Foreign key for Notification and SpecialNotifications Table. 
                        String FOREIGN_KEY = dbHelper.getHighestID(PRIMARY_ID); // Same as above, but fetches the Name field of the last inserted row. 



                        //=========================================================================
                        //**Database Insertions Notifications Table/ SpecialNotifications Table**
                        //=========================================================================



                        //=======================================================================================//
                        //Regular intervals DB Insertions: 
                        //======================================================================================//
                        //Notification Types:
                        //1 for months
                        //2 for weeks
                        //3 for days
                        //4 for minutes
                        //5 for years
                        //6 for seconds
                        //7 for hours
                        //======================================================================================//

                        //==============================
                        //For Months 
                        //==============================
                        intCal.monthsNotify(mon, dateToInsert);
                        int monSpecial =  intCal.getMonthRegular(); 
                        Date dateMonReg = intCal.getMonRegDate(); 


                        dbHelper.insertNotifications(1, convertDate(dateMonReg), 0, monSpecial,FOREIGN_KEY,PRIMARY_ID);


                        //===============================
                        //For Weeks 
                        //===============================
                        intCal.weeksToNotify(weeks,dateToInsert); 
                        int weekSpecial = intCal.getWeekRegular();
                        Date dateWeekReg =intCal.getWeekRegDate(); 

                        dbHelper.insertNotifications(2, convertDate(dateWeekReg), 0, weekSpecial,FOREIGN_KEY,PRIMARY_ID);


                        //===============================
                        //For Days
                        //===============================
                        intCal.daysToNotify(days, dateToInsert); 
                        int daysSpecial= intCal.getDaysRegular();  
                        Date dateDaysReg = intCal.getDaysRegDate(); 

                        dbHelper.insertNotifications(3, convertDate(dateDaysReg), 0, daysSpecial,FOREIGN_KEY,PRIMARY_ID);


                        //===============================
                        //For minutes
                        //===============================
                        intCal.minutesToNotify(min,dateToInsert);
                        long minutesSpecial= intCal.getMinutesRegular();
                        Date dateMinsReg = intCal.getMinutesRegDate(); 

                        dbHelper.insertNotifications(4, convertDate(dateMinsReg), 0,(int) minutesSpecial,FOREIGN_KEY,PRIMARY_ID);


                        //==============================
                        //For Years
                        //==============================
                        intCal.yearsToNotify(years, dateToInsert); 
                        int yearsSpecial = intCal.getYearsRegular();
                        Date dateYearsReg = intCal.getYearsRegDate();

                        dbHelper.insertNotifications(5, convertDate(dateYearsReg), 0, yearsSpecial,FOREIGN_KEY,PRIMARY_ID);


                        //=============================
                        //For Seconds
                        //=============================
                        intCal.secondsToNotify(secon, dateToInsert);
                        long secondsSpecial= intCal.getSecondsRegular(); 
                        Date dateSecondsReg = intCal.getSecondsRegDate(); 

                        dbHelper.insertNotifications(6, convertDate(dateSecondsReg), 0, secondsSpecial,FOREIGN_KEY,PRIMARY_ID);


                        //=============================
                        //For Hours
                        //=============================
                        intCal.hoursToNotify(hours, dateToInsert); 
                        int hoursSpecial= intCal.getHoursRegular();
                        Date dateHoursReg= intCal.getHoursRegDate(); 

                        dbHelper.insertNotifications(7, convertDate(dateHoursReg), 0, hoursSpecial,FOREIGN_KEY,PRIMARY_ID);



                        //============================================================================================//
                        //Special Intervals
                        //=============================================================================================================//
                        //Notification Types:
                        //1 for months
                        //2 for weeks
                        //3 for days
                        //4 for minutes
                        //5 for years
                        //6 for seconds
                        //7 for hours
                        //For Years
                        intCal.specialIntervalYears(years, dateToInsert); 
                        int yearsOnceSpecial =intCal.getYearsSpecial();
                        Date dateYearsSpecial = intCal.getYearsSpDate(); 
                        dbHelper.insertSpecialNotifications(5, convertDate(dateYearsSpecial), yearsOnceSpecial,FOREIGN_KEY,PRIMARY_ID);


                        //For Months
                        intCal.specialIntervalMonths(mon,dateToInsert); 
                        int monthsOnceSpecial= intCal.getMonthsSpecial();
                        Date dateMonthsSpecial = intCal.getMonthsSpDate();
                        dbHelper.insertSpecialNotifications(1, convertDate(dateMonthsSpecial), monthsOnceSpecial,FOREIGN_KEY,PRIMARY_ID);


                        //For Weeks
                        intCal.specialIntervalsWeeks(weeks,dateToInsert); 
                        int weeksOnceSpecial= intCal.getWeeksSpecial(); 
                        Date dateWeeksSpecial = intCal.getWeeksSpDate(); 
                        dbHelper.insertSpecialNotifications(2, convertDate(dateWeeksSpecial), weeksOnceSpecial,FOREIGN_KEY,PRIMARY_ID);

                        //For Days
                        intCal.specialIntervalsDays(days, dateToInsert); 
                        int daysOnceSpecial= intCal.getDaysSpecial(); 
                        Date dateDaysSpecial = intCal.getDaysSpDate(); 
                        dbHelper.insertSpecialNotifications(3, convertDate(dateDaysSpecial), daysOnceSpecial,FOREIGN_KEY,PRIMARY_ID);

                        //For Hours
                        intCal.specialIntervalsHours(hours,dateToInsert); 
                        int hoursOnceSpecial= intCal.getHoursSpecial();  
                        Date dateHoursSpecial = intCal.getHoursSpDate(); 
                        dbHelper.insertSpecialNotifications(7, convertDate(dateHoursSpecial), hoursOnceSpecial,FOREIGN_KEY,PRIMARY_ID);

                        //For Minutes
                        intCal.specialIntervalMinutes(min,dateToInsert); 
                        long minutesOnceSpecial= intCal.getMinutesSpecial(); 
                        Date dateMinutesSpecial= intCal.getMinutesSpDate(); 
                        dbHelper.insertSpecialNotifications(4, convertDate(dateMinutesSpecial), (int)minutesOnceSpecial,FOREIGN_KEY,PRIMARY_ID);

                        //For Seconds
                        intCal.specialIntervalsSeconds(secon,dateToInsert); 
                        long secondsOnceSpecial= intCal.getSecondsSpecial(); 
                        Date dateSecondsSpecial= intCal.getSecondsSpDate(); 
                        dbHelper.insertSpecialNotifications(6, convertDate(dateSecondsSpecial), secondsOnceSpecial,FOREIGN_KEY,PRIMARY_ID); 

                    }
                    publishProgress(progress);
                    Asycdialog.setMax(lines);
                    Asycdialog.incrementProgressBy(1);
                    i++;
                }

            }catch (Exception e){

            } 
            try{
                writeToSD(); 
            }catch (Exception e){
                System.out.println(""+e);
            }


            return "";

        }

        protected void onProgressUpdate(String... values) {

            super.onProgressUpdate(values);
            Asycdialog.setMessage("" + values[0]);
        }


    }

这是日志:

01-15 09:22:36.215: E/SQLiteDatabase(728): close() was never explicitly called on database '/data/data/com.exa.birthdayrem/databases/Bdr' 
01-15 09:22:36.215: E/SQLiteDatabase(728): android.database.sqlite.DatabaseObjectNotClosedException: Application did not close the cursor or database object that was opened here
01-15 09:22:36.215: E/SQLiteDatabase(728):  at android.database.sqlite.SQLiteDatabase.<init>(SQLiteDatabase.java:1943)
01-15 09:22:36.215: E/SQLiteDatabase(728):  at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:1007)
01-15 09:22:36.215: E/SQLiteDatabase(728):  at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:986)
01-15 09:22:36.215: E/SQLiteDatabase(728):  at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:1051)
01-15 09:22:36.215: E/SQLiteDatabase(728):  at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:770)
01-15 09:22:36.215: E/SQLiteDatabase(728):  at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:221)
01-15 09:22:36.215: E/SQLiteDatabase(728):  at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:157)
01-15 09:22:36.215: E/SQLiteDatabase(728):  at com.exa.birthdayrem.DBAdapter.<init>(DBAdapter.java:110)
01-15 09:22:36.215: E/SQLiteDatabase(728):  at com.exa.birthdayrem.LoaderClass$MagicCall.onPreExecute(LoaderClass.java:378)
01-15 09:22:36.215: E/SQLiteDatabase(728):  at android.os.AsyncTask.executeOnExecutor(AsyncTask.java:561)
01-15 09:22:36.215: E/SQLiteDatabase(728):  at android.os.AsyncTask.execute(AsyncTask.java:511)
01-15 09:22:36.215: E/SQLiteDatabase(728):  at com.exa.birthdayrem.LoaderClass.onLoadFinished(LoaderClass.java:225)
01-15 09:22:36.215: E/SQLiteDatabase(728):  at com.exa.birthdayrem.LoaderClass.onLoadFinished(LoaderClass.java:1)
01-15 09:22:36.215: E/SQLiteDatabase(728):  at android.app.LoaderManagerImpl$LoaderInfo.callOnLoadFinished(LoaderManager.java:433)
01-15 09:22:36.215: E/SQLiteDatabase(728):  at android.app.LoaderManagerImpl$LoaderInfo.onLoadComplete(LoaderManager.java:405)
01-15 09:22:36.215: E/SQLiteDatabase(728):  at android.content.Loader.deliverResult(Loader.java:110)
01-15 09:22:36.215: E/SQLiteDatabase(728):  at android.content.CursorLoader.deliverResult(CursorLoader.java:88)
01-15 09:22:36.215: E/SQLiteDatabase(728):  at android.content.CursorLoader.deliverResult(CursorLoader.java:42)
01-15 09:22:36.215: E/SQLiteDatabase(728):  at android.content.AsyncTaskLoader.dispatchOnLoadComplete(AsyncTaskLoader.java:236)
01-15 09:22:36.215: E/SQLiteDatabase(728):  at android.content.AsyncTaskLoader$LoadTask.onPostExecute(AsyncTaskLoader.java:76)
01-15 09:22:36.215: E/SQLiteDatabase(728):  at android.os.AsyncTask.finish(AsyncTask.java:602)
01-15 09:22:36.215: E/SQLiteDatabase(728):  at android.os.AsyncTask.access$600(AsyncTask.java:156)
01-15 09:22:36.215: E/SQLiteDatabase(728):  at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:615)
01-15 09:22:36.215: E/SQLiteDatabase(728):  at android.os.Handler.dispatchMessage(Handler.java:99)
01-15 09:22:36.215: E/SQLiteDatabase(728):  at android.os.Looper.loop(Looper.java:137)
01-15 09:22:36.215: E/SQLiteDatabase(728):  at android.app.ActivityThread.main(ActivityThread.java:4340)
01-15 09:22:36.215: E/SQLiteDatabase(728):  at java.lang.reflect.Method.invokeNative(Native Method)
01-15 09:22:36.215: E/SQLiteDatabase(728):  at java.lang.reflect.Method.invoke(Method.java:511)
01-15 09:22:36.215: E/SQLiteDatabase(728):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
01-15 09:22:36.215: E/SQLiteDatabase(728):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
01-15 09:22:36.215: E/SQLiteDatabase(728):  at dalvik.system.NativeStart.main(Native Method)
01-15 09:22:36.215: E/System(728): Uncaught exception thrown by finalizer
01-15 09:22:36.235: E/System(728): java.lang.IllegalStateException: Don't have database lock!
01-15 09:22:36.235: E/System(728):  at android.database.sqlite.SQLiteDatabase.verifyLockOwner(SQLiteDatabase.java:2090)
01-15 09:22:36.235: E/System(728):  at android.database.sqlite.SQLiteDatabase$1.entryRemoved(SQLiteDatabase.java:2182)
01-15 09:22:36.235: E/System(728):  at android.database.sqlite.SQLiteDatabase$1.entryRemoved(SQLiteDatabase.java:2178)
01-15 09:22:36.235: E/System(728):  at android.util.LruCache.trimToSize(LruCache.java:197)
01-15 09:22:36.235: E/System(728):  at android.util.LruCache.evictAll(LruCache.java:285)
01-15 09:22:36.235: E/System(728):  at android.database.sqlite.SQLiteDatabase.deallocCachedSqlStatements(SQLiteDatabase.java:2143)
01-15 09:22:36.235: E/System(728):  at android.database.sqlite.SQLiteDatabase.closeClosable(SQLiteDatabase.java:1126)
01-15 09:22:36.235: E/System(728):  at android.database.sqlite.SQLiteDatabase.finalize(SQLiteDatabase.java:1914)
01-15 09:22:36.235: E/System(728):  at java.lang.Daemons$FinalizerDaemon.doFinalize(Daemons.java:182)
01-15 09:22:36.235: E/System(728):  at java.lang.Daemons$FinalizerDaemon.run(Daemons.java:168)
01-15 09:22:36.235: E/System(728):  at java.lang.Thread.run(Thread.java:856)

DBAdapter中的open方法:

public DBAdapter open() throws SQLException {
    DBHelper = new DatabaseHelper(mCtx);
    mDb = DBHelper.getWritableDatabase();
    return this;

}

2 个答案:

答案 0 :(得分:1)

我通常会在每个方法的finally块中关闭数据库。喜欢以下

try {
    //open db
    // perform tasks
} catch (Exception e) {
    // handle exceptions
} finally {
    // close db
}

答案 1 :(得分:1)

最简单的方法是将数据库保存在全局上下文中,无论是作为静态还是作为Application类(由getApplicationContext()访问),这样在应用程序运行时它将始终处于打开状态。

您还应该确保使用数据库的所有帮助方法都已正确同步。

您实际上不需要关闭数据库,请看其中一位工程师的帖子:

https://groups.google.com/forum/#!msg/android-developers/nopkaw4UZ9U/cPfPL3uW7nQJ

“鉴于设计,在整个过程的整个过程中保持任何打开并且从不关闭它只是不是泄漏。它将在清理过程时被清理。”< / p>