헬퍼(Helper) 클래스 : 스키마를 업그레이드 할 때 사용하기 좋은 클래스.

스키마 : 테이블의 구조를 정의한 것

 

이미 테이블 안에 데이터가 존재한다면, 스키마를 수정할 때 데이터의 손실이 일어날 수 있다.

그러므로 스키마를 수정할 때는 ① 테이블이 처음 만들어지는 것인지,

                                                   ② 사용자가 이미 사용하고 있는 상태인지

                                                   구분한 뒤 처리해야한다.

 

public SQLiteOpenHelper (Context context, String name, SQLiteDatabase.CursorFactory factory, int version)
// 1번째 파라미터 : 액티비티 안에서 만들 경우 this로 지정 가능.
// 2번째 파라미터 : 데이터베이스의 이름
// 3번째 파라미터 : 데이터 조회 시 반환하는 커서를 만들어 낼 CursorFactory 객체
// 4번째 파라미터 : 버전 정보. 데이터베이스 업그레이드를 위해 사용.

위 클래스는 데이터베이스를 만들거나 열기 위해 필요한 작업들을 도와주는 역할을 한다.

데이터베이스의 생성, 업그레이드 시 콜백 메서드가 호출된다는 장점이 있다. 각각의 상태에 맞게 처리 가능함.

 

public abstract void onCreate (SQLiteDatabase db)
// 데이터베이스가 생성될 때 호출되는 메서드.
public abstract void onOpen (SQLiteDatabase db)
// 데이터베이스를 열 때 호출되는 메서드.
public abstract void onUpgrade (SQLiteDatabse db, int oldVersion, int newVersion)
// 현재의 데이터베이스 버전이 이미 사용하고 있는 버전과 다를 경우 자동으로 호출되는 메서드.

 

 

<헬퍼 클래스 사용하기>

이전 프로젝트 복붙해서 사용한다.

activity_main의 버튼 텍스트만 좀 바꿔준다.

 

이전 프로젝트에서는 editText에 입력받은 이름으로 데이터베이스와 테이블을 만들었는데 이번엔 버튼을 클릭하면 DatabaseHelper 클래스에 내장되어있는 이름으로 만들어지도록 설정됨. (딱히 이유가 있는 건 아니고.. 걍 DatabaseHelper 생성자 메서드에 파라미터로 이름이 들어가도록 설정하면 이전 프로젝트처럼 editText 입력받은 이름으로 생성됨.)

 

1️⃣DatabaseHelper 클래스 만들기

위에서 언급한 SQLiteOpenHelper를 상속받은 새 클래스를 만든다.

onCreate, onUpgrade 메서드를 재정의한다. (onOpen은 안해도 됨)

package com.example.chapter11_3;

public class DatabaseHelper extends SQLiteOpenHelper {
    public static String name = "employee.db";
    public static int version = 1;

    public DatabaseHelper(@Nullable Context context) {
        super(context, name, null, version);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        String sql = "create table if not exists emp(" + "_id integer PRIMARY KEY autoincrement, "
                + "name text, " + "age integer, " + "mobile text)";
        db.execSQL(sql);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        if(newVersion>1){
            db.execSQL("DROP TABLE IF EXISTS emp");
            // emp라는 테이블이 있을 경우 삭제하기. (새 버전이 생성되면서 기존 버전은 삭제. 아마?)
        }
    }
}

 

작성하고 나서 느끼는건데.. 걍 원래 MainActivity에 작성했던 거를 클래스로 따로 빼는 거나 마찬가지다.

대신 이제 onUpgrade가 추가된.

 

 

 

 

2️⃣MainActivity

package com.example.chapter11_3;

public class MainActivity extends AppCompatActivity {

    EditText editText_DB, editText_TB;
    TextView textView;
    SQLiteDatabase database;
    DatabaseHelper dbHelper;

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

        editText_DB = findViewById(R.id.editTextText);
        editText_TB = findViewById(R.id.editTextText2);
        textView = findViewById(R.id.textView);

        Button button_DB = findViewById(R.id.button);
        button_DB.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) { // 데이터베이스 생성
                textView.append("데이터베이스 & 테이블 생성 시작\n");
                String dbName = editText_DB.getText().toString();

                // 바뀐 코드
                dbHelper = new DatabaseHelper(getApplicationContext());
                database = dbHelper.getWritableDatabase();

                // database = openOrCreateDatabase(dbName, MODE_PRIVATE, null);
                textView.append("데이터베이스 & 테이블 생성 완료" + dbName + "\n");
            }
        });

        Button button_TB = findViewById(R.id.button2);
        button_TB.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // String tbName = editText_TB.getText().toString();

                // 레코드 추가
                textView.append("레코드 추가 시작\n");
                database.execSQL("insert into " + "emp" + "(name, age, mobile)"+
                        "values" + "('Sheldon', 26, 010-3141-5926)");
                textView.append("레코드 추가 완료\n");
            }
        });
    }
}

 

클래스를 따로 빼니까 확실히 MainActivity가 깔끔해져서 보기 좋다.

레코드 추가도 따로 뺄 수 있겠지?

 

 

 

 

3️⃣실행결과

잘 나옴.

 

 

 

 

 

4️⃣에러💣

앱이 실행이 안되고 아래와 같은 에러 메시지가 나타났다.

Caused by: org.gradle.workers.internal.DefaultWorkerExecutor$WorkExecutionException: A failure occurred 
while executing com.android.build.gradle.internal.res.ParseLibraryResourcesTask$ParseResourcesRunnable

 

문제가 뭔가 했는데 2가지 원인이었던 것 같다.

 

1. 복붙 후 프로젝트 이름 설정 안 바꿈

폴더명, settings, gradle, manifest에서 11_2 -> 11_3으로 바꿔줌.

 

2. 버튼의 텍스트에 & 삽입.

 

저번에도 XML 파일에는 &가 들어갈 수 없다고 했었다. (그래서 &#38;로 작성해야함. 아래 글 activity_main.xml 부분 참조)

 

10장 - 오픈 API 정보 가져와서 리사이클러뷰로 보여주기

1️⃣gradle, manifest 코드 추가 build.gradle : volley랑 gson 라이브러리를 추가한다.dependencies { implementation("com.android.volley:volley:1.2.1") implementation("com.google.code.gson:gson:2.8.6") AndroidManifest.xml : 인터넷 권한

sand-to-desert.tistory.com

 

이것들을 수정해줬더니 해결됨.