[프로젝트] 자문자답 앱 - 데이터베이스 연동

유의선·2023년 11월 2일
0

데이터베이스를 만들고 리스트 화면, 문제 만들기 화면, 문제 풀기 화면에서 데이터를 조회하고 저장하는 기능을 구현하였다.


데이터베이스 만들기

데이터베이스와 테이블을 만들고, 데이터베이스를 이용할 수 있는 메소드를 정의한 클래스 QuestionDatabase.java를 만들었다.

package org.techtown.qself;

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

import androidx.annotation.Nullable;

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

    // 싱글톤 인스턴스
    private static QuestionDatabase database;

    // 테이블 이름
    public static String TABLE_QUESTION = "QUESTION";

    // 데이터베이스 이름
    public static String DATABSE_NAME = "question.db";

    // 데이터베이스 버전
    public static int DATABASE_VERSION = 1;

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

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

    // 싱글톤 인스턴스
    public static QuestionDatabase getInstance(Context context){
        if(database == null)
            database = new QuestionDatabase(context);

        return database;
    }

    // 데이터베이스 열기
    public boolean open(){
        println("Database Open.");

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

        return true;
    }

    // 데이터베이스 닫기
    public void close(){
        println("Database Close.");

        db.close();
        database = null;
    }

    // 쿼리문 실행
    public Cursor rawQuery(String SQL){
        Cursor cursor = null;
        try{
            cursor = db.rawQuery(SQL, null);
            println("Execute Query.");
        }catch (Exception ex){
            Log.e(TAG, "Exception in executeQuery", ex);
        }

        return cursor;
    }

    // SQL문 실행
    public boolean execSQL(String SQL){
        try{
            Log.d(TAG,"SQL : " + SQL);
            db.execSQL(SQL);
            println("Execute SQL");
        }catch (Exception ex){
            Log.e(TAG,"Exception in executeQuery", ex);
            return false;
        }

        return true;
    }


    // 데이터베이스 헬퍼 클래스
    private class DatabaseHelper extends SQLiteOpenHelper{

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

        @Override
        public void onCreate(SQLiteDatabase db) {

            // 이미 존재하는 테이블 DROP
            String DROP_SQL = "drop table [" + TABLE_QUESTION + "]";
            try{
                db.execSQL(DROP_SQL);
                println("Drop Table.");
            }catch (Exception ex){
                Log.e(TAG, "Exception in DROP_SQL", ex);
            }

            // 테이블 생성
            String CREAT_SQL = "create table " + TABLE_QUESTION + "("
                    +" _id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "
                    +" TITLE TEXT DEFAULT '', "
                    +" QUESTION TEXT DEFAULT '', "
                    +" ANSWER TEXT DEFAULT '' "
                    +")";
            try{
                db.execSQL(CREAT_SQL);
                println("Create Table.");
            }catch (Exception ex){
                Log.e(TAG,"Exception in CREATE_SQL", ex);
            }

        }

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

        @Override
        public void onOpen(SQLiteDatabase db) {
            println("opened Database : " + DATABSE_NAME + ".");
        }
    }

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

싱글톤 인스턴스로 클래스를 정의하였다.

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

    // 싱글톤 인스턴스
    private static QuestionDatabase database;

    // 테이블 이름
    public static String TABLE_QUESTION = "QUESTION";

    // 데이터베이스 이름
    public static String DATABSE_NAME = "question.db";

    // 데이터베이스 버전
    public static int DATABASE_VERSION = 1;

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

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

    // 싱글톤 인스턴스
    public static QuestionDatabase getInstance(Context context){
        if(database == null)
            database = new QuestionDatabase(context);

        return database;
    }

데이터베이스 헬퍼 클래스를 사용하여 데이터베이스와 테이블을 만들었다.

데이터베이스의 이름은 "question.db",
테이블의 이름은 "QUESTION"으로 하였고,
테이블의 속성은 _id, TITLE, QUESTION, ANSWER로 정의하였다.

    // 데이터베이스 헬퍼 클래스
    private class DatabaseHelper extends SQLiteOpenHelper{

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

        @Override
        public void onCreate(SQLiteDatabase db) {

            // 이미 존재하는 테이블 DROP
            String DROP_SQL = "drop table [" + TABLE_QUESTION + "]";
            try{
                db.execSQL(DROP_SQL);
                println("Drop Table.");
            }catch (Exception ex){
                Log.e(TAG, "Exception in DROP_SQL", ex);
            }

            // 테이블 생성
            String CREAT_SQL = "create table " + TABLE_QUESTION + "("
                    +" _id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "
                    +" TITLE TEXT DEFAULT '', "
                    +" QUESTION TEXT DEFAULT '', "
                    +" ANSWER TEXT DEFAULT '' "
                    +")";
            try{
                db.execSQL(CREAT_SQL);
                println("Create Table.");
            }catch (Exception ex){
                Log.e(TAG,"Exception in CREATE_SQL", ex);
            }

        }

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

        @Override
        public void onOpen(SQLiteDatabase db) {
            println("opened Database : " + DATABSE_NAME + ".");
        }
    }

마지막으로 데이터베이스를 열고 닫는 메소드, 쿼리와 SQL문을 실행하는 메소드를 정의하였다.

    // 데이터베이스 열기
    public boolean open(){
        println("Database Open.");

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

        return true;
    }

    // 데이터베이스 닫기
    public void close(){
        println("Database Close.");

        db.close();
        database = null;
    }

    // 쿼리문 실행
    public Cursor rawQuery(String SQL){
        Cursor cursor = null;
        try{
            cursor = db.rawQuery(SQL, null);
            println("Execute Query.");
        }catch (Exception ex){
            Log.e(TAG, "Exception in executeQuery", ex);
        }

        return cursor;
    }

    // SQL문 실행
    public boolean execSQL(String SQL){
        try{
            Log.d(TAG,"SQL : " + SQL);
            db.execSQL(SQL);
            println("Execute SQL");
        }catch (Exception ex){
            Log.e(TAG,"Exception in executeQuery", ex);
            return false;
        }

        return true;
    }

MainActivity.java

MainActivity.java에 실행 시 데이터베이스를 열고, 종료 시 데이터베이스를 닫는 코드를 추가하였다.

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

    public static final int REQUEST_CODE_MAKE = 101;

    // 데이터베이스 인스턴스
    public static QuestionDatabase mDatabase = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 데이터베이스 열기
        openDatabase();

		.
        .
        .
        
    // 종료 시 데이터베이스 닫기.
    @Override
    protected void onDestroy() {
        super.onDestroy();

        if(mDatabase != null){
            mDatabase.close();
            mDatabase = null;
        }
    }

    // 데이터베이스를 여는 함수
    public void openDatabase() {
        if(mDatabase != null){
            mDatabase.close();
            mDatabase = null;
        }

        mDatabase = QuestionDatabase.getInstance(this);
        boolean isOpen = mDatabase.open();
        if(isOpen){
            Log.d(TAG, "Question database is open.");
        }else{
            Log.d(TAG, "Question database is not open.");
        }
    }
}

ListActivity.java, SolveActivity.java

문제의 목록을 보여주는 ListActivity.java와 SolveActivity.java에 데이터베이스에서 데이터를 가져오고, 리사이클러 뷰에 가져온 데이터를 추가하도록 만들었다.

public class ListActivity extends AppCompatActivity {

    RecyclerView recyclerView;
    QuestionAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_list);

        recyclerView = findViewById(R.id.RecyclerView);

        LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
        recyclerView.setLayoutManager(layoutManager);
        adapter = new QuestionAdapter();

        // 리사이클러뷰에 문제 추가
        loadQuestionListData();


        .
        .
		.
        
        
    // 리사이클러뷰에 문제 추가 메소드
    public void loadQuestionListData() {
        int recordCount = 0;

        String sql = "select _id, TITLE, QUESTION, ANSWER FROM " + QuestionDatabase.TABLE_QUESTION + " order by _id ASC";

        QuestionDatabase database =QuestionDatabase.getInstance(this);
        if(database != null){
            Cursor cursor = database.rawQuery(sql);

            recordCount = cursor.getCount();

            for(int i = 0; i < recordCount; i++){
                cursor.moveToNext();

                int _id = cursor.getInt(0);
                String Title = cursor.getString(1);
                String Question = cursor.getString(2);
                String Answer = cursor.getString(3);

                adapter.addItem(new Question(_id, Title, Question, Answer));
            }

            cursor.close();
            adapter.notifyDataSetChanged();
        }

    }
}
public class SolveActivity extends AppCompatActivity {
    public static final int REQUEST_CODE_SOLVE = 102;

    RecyclerView recyclerView;
    QuestionAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_solve);

        recyclerView = findViewById(R.id.RecyclerView);

        LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
        recyclerView.setLayoutManager(layoutManager);
        adapter = new QuestionAdapter();

        // 리사이클러뷰에 문제 추가
        loadQuestionListData();
        

        .
        .
        .
        

    public void loadQuestionListData() {
        int recordCount = 0;

        String sql = "select _id, TITLE, QUESTION, ANSWER FROM " + QuestionDatabase.TABLE_QUESTION + " order by _id ASC";

        QuestionDatabase database =QuestionDatabase.getInstance(this);
        if(database != null){
            Cursor cursor = database.rawQuery(sql);

            recordCount = cursor.getCount();

            for(int i = 0; i < recordCount; i++){
                cursor.moveToNext();

                int _id = cursor.getInt(0);
                String Title = cursor.getString(1);
                String Question = cursor.getString(2);
                String Answer = cursor.getString(3);

                adapter.addItem(new Question(_id, Title, Question, Answer));
            }

            cursor.close();
            adapter.notifyDataSetChanged();
        }

    }
}

MakeQuestion.java

MakeQuestion.java에 입력된 데이터로 문제를 만들어 데이터베이스에 저장하는 코드를 추가하였다.

public class MakeActivity extends AppCompatActivity {

    EditText editTextTitle;
    EditText editTextQuestion;
    EditText editTextAnswer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_make);

        editTextTitle = findViewById(R.id.editTextTitle);
        editTextQuestion = findViewById(R.id.editTextQuestion);
        editTextAnswer = findViewById(R.id.editTextAnswer);

        Button buttonMakeQuestion = findViewById(R.id.buttonMakeQuestion);

        buttonMakeQuestion.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                // 데이터베이스에 문제 추가
                addQuestion();
                
                .
                .
                .
                

    // 데이터베이스에 문제 추가 메소드
    private void addQuestion() {
        String title = editTextTitle.getText().toString();
        String question = editTextQuestion.getText().toString();
        String answer = editTextAnswer.getText().toString();

        String sql = "insert into " + QuestionDatabase.TABLE_QUESTION +
                "(TITLE, QUESTION, ANSWER) values(" +
                "'" + title + "', " +
                "'" + question + "', " +
                "'" + answer + "')";

        QuestionDatabase database = QuestionDatabase.getInstance(this);
        database.execSQL(sql);
    }
}




0개의 댓글