마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

SQLite에 데이터 저장시 nullPointException 오류가 납니다.

0 추천

GPS로부터 받은 정보를 SQLite에 저장하는 코드입니다.

데이터베이스는 LocDatabase.java라는 파일로 따로 작성하였고, AppConstants 의 DATABASE_NAME은 location.db입니다.

그런데 다음과 같은 오류가 나면서 데이터베이스에 저장이 되지 않습니다.

E/LocDatabase: Exception in execute
    java.lang.NullPointerException: Attempt to invoke virtual method 'void android.database.sqlite.SQLiteDatabase.execSQL(java.lang.String)' on a null object reference
        at org.techtown.drawer.LocDatabase.execSQL(LocDatabase.java:68)
        at org.techtown.drawer.Fragment1.saveLoc(Fragment1.java:212)
        at org.techtown.drawer.Fragment1.access$000(Fragment1.java:31)
        at org.techtown.drawer.Fragment1$GPSListener.onLocationChanged(Fragment1.java:186)
        at android.location.LocationManager$ListenerTransport._handleMessage(LocationManager.java:388)
        at android.location.LocationManager$ListenerTransport.access$000(LocationManager.java:300)
        at android.location.LocationManager$ListenerTransport$1.handleMessage(LocationManager.java:316)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7050)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:965)

오류가 나는 saveLoc 메소드는 다음과 같습니다.

private void saveLoc(Location location){
        String sql = "insert into " + LocDatabase.TABLE_LOCATION + "(LATITUDE, LONGITUDE, ACCURACY, ALTITUDE, SPEED) values (" +
                     "'" + location.getLatitude() + "', " +
                     "'" + location.getLongitude() + "', " +
                     "'" + location.getAccuracy() + "', " +
                     "'" + location.getAltitude() + "', " +
                     "'" + location.getSpeed() + "', ";

        Log.d(TAG, "sql : " + sql);
        LocDatabase database = LocDatabase.getInstance(context);
        database.execSQL(sql);
    }

그리고, LocDatabase는 아래의 코드입니다.

public class LocDatabase {
    private static final String TAG = "LocDatabase";

    private static LocDatabase locDatabase;
    public static String TABLE_LOCATION = "LOCATION";
    public static int DATABASE_VERSION = 1;

    private DatabaseHelper dbHelper;
    private SQLiteDatabase db;
    private Context context;

    private LocDatabase(Context context){
        this.context = context;
    }

    public static LocDatabase getInstance(Context context){
        if (locDatabase == null){
            locDatabase = new LocDatabase(context);
        }

        return locDatabase;
    }

    public boolean open(){
        println("opening database [" + AppConstants.DATABASE_NAME + "].");

        dbHelper = new DatabaseHelper(context);
        db = dbHelper.getWritableDatabase();

        return true;
    }

    public void close() {
        println("closing database [" + AppConstants.DATABASE_NAME + "].");
        db.close();

        locDatabase = null;
    }

    public Cursor rawQuery(String SQL) {
        println("\nexecuteQuery called.\n");

        Cursor cursor = null;

        try {
            cursor = db.rawQuery(SQL, null);
            println("cursor count : " + cursor.getCount());
        } catch(Exception ex){
            Log.e(TAG, "Exception in executeQuery", ex);
        }

        return cursor;
    }

    public boolean execSQL(String SQL){
        println("\nexecute called.\n");

        try {
            Log.d(TAG, "SQL : " + SQL);
            db.execSQL(SQL);
        } catch (Exception ex) {
            Log.e(TAG, "Exception in execute", ex);
            return false;
        }

        return true;
    }

    private class DatabaseHelper extends SQLiteOpenHelper {

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

        public void onCreate(SQLiteDatabase db){
            println("creating database [" + AppConstants.DATABASE_NAME + "].");

            println("creating table [" + TABLE_LOCATION + "].");

            String DROP_SQL = "drop table if exists " + TABLE_LOCATION;

            try {
                db.execSQL(DROP_SQL);
            } catch(Exception ex) {
                Log.e(TAG, "Exception in DROP_SQL", ex);
            }

            String CREATE_SQL = "create table " + TABLE_LOCATION + "("
                              + " _id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "
                              + " LATITUDE REAL DEFAULT 0.0, "
                              + " LONGITUDE REAL DEFAULT 0.0, "
                              + " ACCURACY REAL DEFAULT 0.0, "
                              + " ALTITUDE REAL DEFAULT 0.0, "
                              + " SPEED REAL DEFAULT 0.0, "
                              + " CREATE_DATE TIMESTAMP DEFAULT CURRENT_TIMESTAMP "
                              + ")";

            try {
                db.execSQL(CREATE_SQL);
            } catch(Exception ex) {
                Log.e(TAG, "Exception in CREATE_SQL", ex);
            }

            String CREATE_INDEX_SQL = "create index " + TABLE_LOCATION + "_IDX ON " + TABLE_LOCATION + "("
                                      + "CREATE_DATE" + ")";

            try {
                db.execSQL(CREATE_INDEX_SQL);
            } catch (Exception ex) {
                Log.e(TAG, "Exception in CREATE_INDEX_SQL", ex);
            }
        }

        public void onOpen(SQLiteDatabase db){
            println("opened database [" + AppConstants.DATABASE_NAME + "].");
        }

        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
            println("Upgrading database from version " + oldVersion + " to" + newVersion + ".");
        }
    }

    private void println(String msg){
        Log.d(TAG, msg);
    }
}

책을 참고하여 쓴 코드라서 오류가 안날거라고 생각했는데 어디가 문제일까요...?

Sprite_ZERO (470 포인트) 님이 2022년 2월 24일 질문

1개의 답변

0 추천
 
채택된 답변

아직 SQLiteHelper 를 사용하고 계시네요. 가능하면 RoomDB를 사용하시면 코드가 훨씬 깔금하고 변경하기도 쉬워질텐데. 특히 지금과 같이 겪는 문제는 잘 생기지 않도록 코드 구조를 가져갈 수 있습니다. 이것 별개의 토픽이라 놔두고요....

로그로 볼 때, 에러가 나는 라인이 아래로 보입니다.

public boolean execSQL(String SQL){
        ...
            db.execSQL(SQL); // ===> 요기!
        ..
    }
 

에러의 원인은 db 변수가 널인 상에서 execSQL을 호출했기 때문에 NullPointerException이 난 상황입니다. db변수가 널인 이유는 db변수를 초기화 하는 곳이 open() 메소드인데, 이걸 호출하는 곳을 찾을 수가 없네요. 따라서 아래와 같이 초기화를 해주셔야 할 것으로 보입니다.

public class LocDatabase {
    ...
 
    private LocDatabase(Context context){
        this.context = context;
        open();
    }
 
   ...  
}

 

보통은 open시에 에러가 나지는 않겠지만, 만약의 경우를 대비해 에러 처리를 해주시는 걸 권장합니다.

spark (228,010 포인트) 님이 2022년 2월 24일 답변
Sprite_ZERO님이 2022년 2월 24일 채택됨
해결했습니다. 감사합니다
...