从未在数据库上显式调用Sqlite close() - 我试过但失败了

时间:2012-02-17 02:40:19

标签: android

好的,所以我创建了这个从游戏的AlarmManager启动的服务类。目的是以一定的时间间隔启动此服务,并检查游戏的远程玩家是否已经玩过。它唤醒,打开一个数据库并查询游戏列表,然后检查服务器的每个游戏的状态,如果一个游戏进入状态栏有一些好东西。这一切都很好,花花公子,但这个小小的服务不断抛出一个例外   “从未在数据库上显式调用Sqlite close()” 但我想我在下面的代码中关闭了查询和数据库。 我错过了什么?我已经阅读了几十个stackoverflow线程,所有人都说我应该关闭数据库,我在onDestroy()和unBind()中关闭它,但我仍然得到这个异常。

服务

public class WakeCheck extends Service {

    private triDbAdapter mDbHelper;

@Override
public void onCreate() {
// TODO Auto-generated method stub
}



@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}



@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
mDbHelper.close();
}



@Override
public void onStart(Intent intent, int startId) {
    super.onStart(intent, startId);
    //Toast.makeText(this, "MyAlarmService.onStart()", Toast.LENGTH_LONG).show();
    Cursor c;
    triDbAdapter mDbHelper = new triDbAdapter(this.getApplicationContext());
    mDbHelper.open();
    ServerCommunication sComm = new ServerCommunication(this.getApplicationContext());
    c = mDbHelper.fetchAllGames();

    if (c.getCount() > 0){
        c.moveToFirst();
        do {
            int game_id = c.getInt(c.getColumnIndex(mDbHelper.KEY_ID));
            try {
                if ( sComm.checkplay(game_id, 0) ) {
                    //notify user - communicate that there has been a new play

                    String ns = this.NOTIFICATION_SERVICE;
                    NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns);
                    int icon = R.drawable.status_icon;
                    CharSequence tickerText = "TriOminoes!";
                    long when = System.currentTimeMillis();

                    Notification notification = new Notification(icon, tickerText, when);
                    Context context = getApplicationContext();
                    CharSequence contentTitle = "TriOminoes";
                    String name = c.getString(c.getColumnIndex(mDbHelper.KEY_OPPNM));
                    int tscore = c.getInt(c.getColumnIndex(mDbHelper.KEY_TSCORE));
                    CharSequence contentText = name + " played for " + tscore +
                                    " points. It's Your Turn!";
                    Intent notificationIntent = new Intent(this, SelectGames.class);
                    if (Settings.AlarmVibrate) {
                        notification.flags |= Notification.DEFAULT_VIBRATE;
                    }
                    if (Settings.AlarmSound) {
                        notification.flags |= Notification.DEFAULT_SOUND;
                    }
                    notification.flags |= Notification.FLAG_AUTO_CANCEL;


                    PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent,
                            PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);


                    notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);


                    mNotificationManager.notify(1, notification);
                }
            } catch (JSONException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                c.close();
                mDbHelper.close();
                Log.d("WAKE", "Something went wrong in Communications");

            }
        } while (c.moveToNext());
    }
    c.close();
    mDbHelper.close();
}


@Override
public boolean onUnbind(Intent intent) {
// TODO Auto-generated method stub
    mDbHelper.close();
return super.onUnbind(intent);


}



}

triDbAdapter

package com.ulsanonline.triominoes;


import java.text.SimpleDateFormat;
import java.util.Calendar;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

public class triDbAdapter {



    /**
     * Database creation sql statement
     */
    private static final String DATABASE_CREATE1 =    
    "CREATE TABLE player (" +
              "_id              INTEGER ," +
              "username         TEXT not null," +
              "alarmtime        INTEGER not null," +
              "alarmvibrate     INTEGER not null," +
              "alarmsound       INTEGER not null," +
              "showboard        INTEGER not null," +
              "showtouch        INTEGER not null," +
              "showcenters      INTEGER not null );" ;

    private static final String DATABASE_CREATE2 = 
    "CREATE TABLE games (" +
              "_id              INTEGER, " +
              "myScore          INTEGER, " +
              "username         TEXT,    " +
              "myId             INTEGER, " +
              "opponentId       INTEGER, " +
              "opponentName     TEXT,    " +
              "opponentScore    INTEGER, " +
              "last_tile        INTEGER, " +
              "last_tile_name   TEXT,    " +
              "row              INTEGER, " +
              "col              INTEGER, " +    // grid location & rotation, face tells
              "rotate           INTEGER, " +    // all scoring information
              "face_dn          INTEGER, " +    // 1=face down, 1=face pointing up
              "who              INTEGER, " +    // who played it, user id
              "tscore           INTEGER, " +    // just score per that turn
              "remain           INTEGER, " +    // tiles remain(1) or not (0)
              "complete         INTEGER, " +    // game over(1) or keep playing(0)
              "last_played      INTEGER); " ;

    private static final String DATABASE_CREATE3 = 
    "CREATE TABLE tilesPlayed (" +
             "_id               INTEGER REFERENCES games(_id) on UPDATE CASCADE," +
             "row               INTEGER, " +
             "col               INTEGER, " +    // grid location & rotation, face tells
             "rotate            INTEGER, " +    // all scoring information
             "face_dn           INTEGER, " +    // 1=face down, 0=face pointing up
             "tile              INTEGER); " ;

    private static final String DATABASE_CREATE4 = 
    "CREATE TABLE myTiles  (" +
             "_id               INTEGER PRIMARY KEY AUTOINCREMENT, " +
             "game_id           INTEGER REFERENCES games(_id) on UPDATE CASCADE," +
             "tile              INTEGER); " ;

    private static final String DATABASE_NAME = "triominoes.db";
    private static final String PLAYER_TABLE  = "player";
    private static final String GAMES_TABLE   = "games";
    private static final String TILES_TABLE   = "tilesPlayed";
    private static final String MYTILES_TABLE = "myTiles";
    private static final int DATABASE_VERSION = 1;  

    public static final String KEY_NAME   = "username";
    public static final String KEY_ID     = "_id";
    public static final String KEY_GAME   = "game_id";
    public static final String KEY_USERID = "myId";
    public static final String KEY_TILE   = "tile";
    public static final String KEY_LASTT  = "last_tile"; 
    public static final String KEY_LASTN  = "last_tile_name";
    public static final String KEY_SCORE  = "myScore";
    public static final String KEY_OPP    = "opponentId";
    public static final String KEY_OPPSC  = "opponentScore";
    public static final String KEY_OPPNM  = "opponentName";
    public static final String KEY_DATE   = "last_played";
    public static final String KEY_ROW    = "row";
    public static final String KEY_COL    = "col";
    public static final String KEY_ROT    = "rotate";
    public static final String KEY_FACEDN = "face_dn";
    public static final String KEY_TSCORE = "tscore";
    public static final String KEY_WHO    = "who";
    public static final String KEY_REMAIN = "remain";
    public static final String KEY_COMPLETE = "complete";
    public static final String KEY_ATIME  = "alarmtime";
    public static final String KEY_AVIBE  = "alarmvibrate";
    public static final String KEY_ASOUND = "alarmsound";
    public static final String KEY_SHOWBOARD = "showboard";
    public static final String KEY_SHOWTOUCH = "showtouch";
    public static final String KEY_SHOWCENTERS = "showcenters";




    private static final String TAG = "dbAdapter";
    private DatabaseHelper mDbHelper;
    private SQLiteDatabase mDb;
    private final Context mCtx;
    private static final String DATE_FORMAT_NOW = "yyyy-MM-dd hh:mm";


    private static class DatabaseHelper extends SQLiteOpenHelper {

        DatabaseHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }



        @Override
        public void onCreate(SQLiteDatabase db) {

            db.execSQL(DATABASE_CREATE1);
            db.execSQL(DATABASE_CREATE2);
            db.execSQL(DATABASE_CREATE3);
            db.execSQL(DATABASE_CREATE4);


        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
                    + newVersion + ". ALL data will be destroyed");
            db.execSQL("DROP TABLE IF EXISTS user");
            db.execSQL("DROP TABLE IF EXISTS games");
            db.execSQL("DROP TABLE IF EXISTS tilesPlayed");
            onCreate(db); 

        }

    }    

    /**
     * Constructor - takes the context to allow the database to be
     * opened/created
     * 
     * @param ctx the Context within which to work
     */
    public  triDbAdapter(Context ctx) {
        this.mCtx = ctx;
    }

    /**
     * Open the student database. If it cannot be opened, try to create a new
     * instance of the database. If it cannot be created, throw an exception to
     * signal the failure
     * 
     * @return this (self reference, allowing this to be chained in an
     *         initialization call)
     * @throws SQLException if the database could be neither opened or created
     */
    public triDbAdapter open() throws SQLException {
        mDbHelper = new DatabaseHelper(mCtx);
        mDb = mDbHelper.getWritableDatabase();
        return this;
    }

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

    /**
     * createUserProfile inserts the local username and server-generated userid, _ID , into the database.
     * @param username the name of the local user
     * @param _id - index in player table
     * @return 
     */    
    public long createUserProfile(String username, int _id) {
        ContentValues initialValues = new ContentValues();
        initialValues.put(KEY_NAME, username);
        initialValues.put(KEY_ID, _id);
        initialValues.put(KEY_ATIME,Settings.AlarmInterval);
        initialValues.put(KEY_AVIBE,Settings.AlarmVibrate?1:0);
        initialValues.put(KEY_ASOUND,Settings.AlarmSound?1:0);
        initialValues.put(KEY_SHOWBOARD,Settings.ShowBoard?1:0);
        initialValues.put(KEY_SHOWTOUCH, Settings.ShowTouch?1:0);
        initialValues.put(KEY_SHOWCENTERS,Settings.ShowCenters?1:0);       
        return mDb.insertOrThrow(PLAYER_TABLE, null, initialValues);
    }

    /* initially upon startup, get what's in the dB */
    public void getSettings()  {
        Log.w(TAG, "getting settings");
        String sql = "SELECT * FROM player";
        Cursor c = mDb.rawQuery(sql, null);
        c.moveToLast();
        Settings.AlarmInterval = c.getInt(c.getColumnIndex(KEY_ATIME));
        Settings.AlarmVibrate = (c.getInt(c.getColumnIndex(KEY_AVIBE)) == 1);
        Settings.AlarmSound = (c.getInt(c.getColumnIndex(KEY_ASOUND)) == 1);
        Settings.ShowBoard = (c.getInt(c.getColumnIndex(KEY_SHOWBOARD)) == 1);
        Settings.ShowTouch = (c.getInt(c.getColumnIndex(KEY_SHOWTOUCH)) == 1);
        Settings.ShowCenters = (c.getInt(c.getColumnIndex(KEY_SHOWCENTERS)) == 1);
        c.close();
    }



   /**
    * updateLastPlayed - updates the game with the last tile played
    * @param game_id
    * @param user_id - local user's id
     * @param who - index to which player made the move
     * @param score - score to update
     * @param tile - tile number
     * @param name - name of the tile, used for rebuilding faces
     * @param row - row in the grid the tile was placed
     * @param col - col in the grid the tile was placed
     * @param rot - current rotation of the tile when placed
     * @param facedn - orientation of the tile as placed
     * @param tScore - score for just this turn
     * @param remain - 0 = no remaining tiles, 1 = there are tiles left.
     * @param complete - 0 = not complete, keep playing; 1=game over
     * @return 
    */
    public void UpdateLastPlayed(int game_id, int user_id, int who, int score, int tile, String name,
                                 int row, int col, int rot, Boolean facedn, int tScore, int remain, int complete) {
        ContentValues args = new ContentValues();
        ContentValues InitialValues = new ContentValues();
        int newscore;

        args.put(KEY_ID, game_id);
        args.put(KEY_WHO, who);
        args.put(KEY_LASTT, tile);
        args.put(KEY_LASTN, name);
        args.put(KEY_ROW, row);
        args.put(KEY_COL, col);
        args.put(KEY_ROT, rot);
        int face = (facedn)? 1 :0;
        args.put(KEY_FACEDN, face);
        args.put(KEY_TSCORE, tScore);

        Calendar cal = Calendar.getInstance();
        args.put(KEY_DATE, cal.getTimeInMillis());

        if (user_id == who) {   // last player was me
            if (score == -5) { 
                newscore = score + getScore(game_id, user_id); // adjust myscore
                args.put(KEY_SCORE, newscore);
                args.put(KEY_LASTT, -1);

            }
            else 
                args.put(KEY_SCORE, score);
        }
        else {                 // last player was opponent
            if (score == -5) { 
                newscore = score + getScore(game_id, who); // adjust opponent's
                args.put(KEY_OPPSC, newscore);
                args.put(KEY_LASTT, -1);

            }
            else
                args.put(KEY_OPPSC, score);

        }


        mDb.update(GAMES_TABLE, args, KEY_ID + "=" + game_id, null);    // this table goes to 
                                                                        // and comes from the main server

        InitialValues.put(KEY_ID, game_id);
        InitialValues.put(KEY_ROW, row);
        InitialValues.put(KEY_COL, col);
        InitialValues.put(KEY_ROT, rot);
        InitialValues.put(KEY_TILE, tile);
        InitialValues.put(KEY_FACEDN, face);
        mDb.insert(TILES_TABLE, null, InitialValues);                   // this table is local only 

    }

    public Cursor fetchLastPlayed(int game_id){
Cursor c;
        return mDb.query(GAMES_TABLE, new String[] {KEY_ID, KEY_SCORE,
        KEY_OPP, KEY_OPPSC, KEY_OPPNM, KEY_DATE, KEY_LASTT, KEY_LASTN, KEY_TSCORE, KEY_WHO}, 
        KEY_ID + "=" + game_id, null, null, null, KEY_DATE);

    }

}

1 个答案:

答案 0 :(得分:0)

在一个类似的问题中,建议在调用onDestroy的超级函数之前执行close操作。

所以你应该试试这个:SQLite database never close in my Android app