본문 바로가기

안드로이드

[안드로이드] SQLite 데이터베이스 이용하기

   

   

<목표>  [안드로이드] SQLite 데이터베이스 이용하기

 

   

 오늘은 안드로이드 개발에 있어서 없어서는 안될 데이터베이스의 사용법에 대해 알아보겠습니다.안드로이드는 모바일 환경에 알맞은 SQLite 데이터베이스를 채택하고 있습니다. 기본의 다른 데이터베이스와의 큰 차이는 없습니다.다른 점이라면, 일반적은 데이터베이스는 테이블 생성시 각 속성에 대한 타입을 지정합니다. 하지만 SQLite는 타입을 지정하는 것이 없습니다. 즉, int, string, text 등의 타입을 지정할 수가 없다는 말이죠. 그러나 메모리와 속도면에서 소규모의 데이터베이스를 운영하는 데 있어서는 이점이 있습니다.

 데이터베이스의 사용법은 기존의 데이터베이스를 한번이라도 다뤄보신적 있으신 분은 별 어려움 없이 사용하실 수 있을 것입니다. 처음 접하는 사람들 역시, 기존에 있는 샘플코드를 이용하여 조금만 수정해서 사용하시면, 별 어려움 없이 프로그램에 적용시키실 수 있을 겁니다.

 샘플 코드는 인터넷에 널리 퍼져 있는 코드를 정리한 것입니다. 간단한 노트 기능으로 타이틀과 바디를 가지는 테이블이 있고, 이를 이용하여 데이터를 추가, 삭제, 업데이트 등을 수행할 수 있습니다.

   

   

  STEP 1 자바 소스 코드 

 

 자바 코드는 크게 두가지로 나뉘어집니다. 데이터베이스를 컨트롤 하는 객체와 이 객체를 사용하여 데이터베이스를 접근하는 엑티비티입니다.

 아래의 예제는 데이터베이스를 컨트롤 하는객체(NotesDbAdapter) 입니다. 이 클래스 내부에 DatabaseHelper객체가 있어 데이터베이스를 관리합니다. 이는 안드로이드에서 제공하는 SQLiteOpenHelper를 상속받아 간단히 만들 수 있습니다. DatabaseHelper 객체에는 크게 세 가지 함수가 존재합니다. 생성자, onCreate, onUpdate 가 있습니다. 말 그대로 onCreate는 데이터베이스를 생성하면서, 데이터베이스 이름과 버전을 설정할 수 있습니다. 이 부분에 쿼리문을 이용하여 데이터베이스의 테이블을 생성합니다. onUpdate는 말 그대로 업데이트가 필요할 시 수행이 됩니다. 현재의 데이터베이스 버전과 업데이트 하려는 데이터베이스의 버전을 비교하여, 낮은 버전일 경우 새롭게 테이블을 구성한다던가, 다른 조작 등을 취할 수 있습니다.

   

  [DBAdapter] 데이터베이스 관리 클래스

 

package com.pulsewings.exceltodatabase;

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 NotesDbAdapter {

	public static final String KEY_TITLE = "title";
	public static final String KEY_BODY = "body";
	public static final String KEY_ROWID = "_id";
	private static final String TAG = "NotesDbAdapter";

	private DatabaseHelper mDbHelper;
	private SQLiteDatabase mDb;

	/**
	 *
	 * Database creation sql statement
	 */

	private static final String DATABASE_CREATE = "create table notes (_id integer primary key autoincrement, "
			+ "title text not null, body text not null);";

	private static final String DATABASE_NAME = "data";
	private static final String DATABASE_TABLE = "notes";
	private static final int DATABASE_VERSION = 2;
	private final Context mCtx;

	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_CREATE);
		}

		@Override
		public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
			Log.w(TAG, "Upgrading database from version " + oldVersion + " to " + newVersion
					+ ", which will destroy all old data");
			db.execSQL("DROP TABLE IF EXISTS notes");
			onCreate(db);
		}
	}

	public NotesDbAdapter(Context ctx) {
		this.mCtx = ctx;
	}

	public NotesDbAdapter open() throws SQLException {
		mDbHelper = new DatabaseHelper(mCtx);
		mDb = mDbHelper.getWritableDatabase();
		return this;
	}

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

	public long createNote(String title, String body) {
		ContentValues initialValues = new ContentValues();
		initialValues.put(KEY_TITLE, title);
		initialValues.put(KEY_BODY, body);
		return mDb.insert(DATABASE_TABLE, null, initialValues);
	}

	public boolean deleteNote(long rowId) {
		Log.i("Delete called", "value__" + rowId);
		return mDb.delete(DATABASE_TABLE, KEY_ROWID + "=" + rowId, null) > 0;
	}

	public Cursor fetchAllNotes() {
		return mDb.query(DATABASE_TABLE, new String[] { KEY_ROWID, KEY_TITLE, KEY_BODY }, null, null, null, null, null);
	}

	public Cursor fetchNote(long rowId) throws SQLException {

		Cursor mCursor = mDb.query(true, DATABASE_TABLE, new String[] { KEY_ROWID, KEY_TITLE, KEY_BODY }, KEY_ROWID
				+ "=" + rowId, null, null, null, null, null);
		if (mCursor != null) {
			mCursor.moveToFirst();
		}
		return mCursor;
	}

	public boolean updateNote(long rowId, String title, String body) {
		ContentValues args = new ContentValues();
		args.put(KEY_TITLE, title);
		args.put(KEY_BODY, body);
		return mDb.update(DATABASE_TABLE, args, KEY_ROWID + "=" + rowId, null) > 0;
	}

}

   

 그 밖에는 함수명에서도 볼 수 있듯이 데이터를 추가, 삭제, 업데이트하는 기능입니다. 기존의 데이터베이스와 다른 점은 쿼리문을 이용하지 않고 데이터를 조정이 가능한 것입니다. ContentValues 라는 타입을 이용하여 기존에 있는 테이블의 속성명과 조작하려는 인스턴스를 넣어 한꺼번에 데이터베이스로 요청할 수 있습니다. Insert, update 같이 데이터베이스 객체 내에 있는 함수를 이용하여 쿼리문 없이 데이터베이스 조작이 가능합니다. 이러한 함수는 내부에서 직접 쿼리문을 만들어 데이터베이스로 쿼리문을 날립니다.

 자신이 사용하고 싶은 테이블을 구성하신 뒤에, 이 코드를 자신에 맞는 테이블로 바꾸시면 큰 어려움 없이 데이터베이스를 이용하실 수 있으실 겁니다.

 

  [Bouns] Cursor 사용

 

인자내용
moveToFirst 커서가 쿼리(질의) 결과 레코드들 중에서 가장 처음에 위치한 레코드를 가리키도록 합니다.
moveToNext 다음 레코드로 커서를 이동합니다.
moveToPrevious 이전 레코드로 커서를 이동합니다.
getCount 질의 결과값(레코드)의 갯수를 반환합니다.
getColumnIndexOrThrow 특정 필드의 인덱스값을 반환하며, 필드가 존재하지 않을경우 예외를 발생시킵니다.
getColumnName 특정 인덱스값에 해당하는 필드 이름을 반환합니다.
getColumnNames 필드 이름들을 String 배열 형태로 반환합니다.
moveToPosition 커서를 특정 레코드로 이동시킵니다.
getPosition 커서가 현재 가리키고 있는 위치를 반환합니다.

 

 데이터베이스의 특성상 하나의 테이블의 레코드를 읽어 오기 위해서는 커서라는 것이 필요합니다. 조건에 맞는 레코드를 한꺼번에 모두 들고 올 수가 없기 때문에 커서를 이용해서 조작을 합니다. 말 그대로 커서는 현재 레코드를 가리키고 있는 곳을 말합니다. 하나씩 이 커서를 이동하면서 레코드 하나하나씩을 접근해서 가져옵니다. 이 커서 객체를 이용하여 get을 하게 되면 컬럼 번호에 맞게 데이터를 가져올 수 있습니다.

 

  [Activity] 데이터베이스 이용 엑티비티

 

package com.pulsewings.exceltodatabase;

import android.app.Activity;
import android.database.Cursor;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class DatabaseTestActivity extends Activity {

	private NotesDbAdapter dbAdapter;
	private static final String TAG = "NotesDbAdapter";

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		Log.d(TAG, "DatabaseTest :: onCreate()");
		dbAdapter = new NotesDbAdapter(this);
		dbAdapter.open();

		Button bt = (Button) findViewById(R.id.inputButton);
		bt.setOnClickListener(new View.OnClickListener() {

			public void onClick(View v) {
				dbAdapter.createNote("title", "body");
				TextView tv = (TextView) findViewById(R.id.textView1);
				tv.setText("데이터베이스에넣었습니다.");
				TextView tv1 = (TextView) findViewById(R.id.textView2);
				tv1.setText("Title과 Body를데이터베이스에저장하였습니다.");
				Log.d(TAG, "First Button Click");
			}
		});

		Button bt1 = (Button) findViewById(R.id.outputButton);
		bt1.setOnClickListener(new View.OnClickListener() {

			public void onClick(View v) {
				Cursor result = dbAdapter.fetchAllNotes();
				result.moveToFirst();
				while (!result.isAfterLast()) {
					String title = result.getString(1);
					String body = result.getString(2);
					TextView tv = (TextView) findViewById(R.id.textView1);
					tv.setText(title);
					TextView tv1 = (TextView) findViewById(R.id.textView2);
					tv1.setText(body);
					result.moveToNext();
				}

				Log.d(TAG, "Second Button Click");
				result.close();
			}

		});

	}

}

   

 위의 코드는 실제 엑티비티에서 데이터베이스를 이용하는 것을 나타내는 소스코드입니다. 위에서 살펴본 NotesDbAdapter 객체를 생성하여, open()을 한 뒤 사용하면 됩니다. 사용하는 법은 너무나도 직관적이라 생략하겠습니다. While문을 이용하여 커서를 이용하여 테이블에 있는 모든 레코드를 가져와서 화면에 뿌려주는 것을 수행하는 코드입니다.

   

  STEP 2 Xml 코드

   

 Xml코드에는 간단히 테스트할 수 있는 TextView객체 두 개만 생성하고 있습니다.

   

  STEP 3 AndroidManifest.xml 코드

 

 데이터베이스를 이용하기 위해서 AndroidManifest.xml 코드 수정은 필요하지 않습니다.

   

 

 

<마무리>  SQLite 데이터베이스 사용하기

 

 데이터베이스를 사용하기 위해서는 안드로이드에서 제공하는 SQLiteOpenHelper를 이용하여 간단히 데이터베이스를 조작할 수 있습니다. 이 것을 상속받아 객체를 만들고 이 객체를 자신의 데이터베이스에 맞게 조작하도록 클래스(NotesDbAdapter)를 만들고, 엑티비티에서는 이 클래스를 생성하여 데이터베이스를 직접 사용할 수 있게 합니다. 간단한 샘플 코드를 이용하여 자신의 데이터베이스 테이블에 맞게 수정하여 사용하면 간단히 데이터를 저장할 수 있는 환경이 됩니다.

   

 

 


Posted by 
맥박맥박의 개발 일지

 

  • 2013년 7월 25일 업데이트하였습니다.