profile image

L o a d i n g . . .

반응형



안드로이드 데이터베이스 SQLite 사용하기(메모저장)

Using Android Database SQLite


웹이든 앱이든 빠질 수 없는게 데이터베이스인데, 안드로이드에는 기본적으로 데이터베이스관련 클래스가 내장되어 있다.

데이터베이스를 생성하는 가장 간단한 방법은 context 클래스에 정의된 openOrCreateDatabase() 메소드를 사용한다

애플리케이션에서 기본적으로 사용하는 Activity 클래스가 Context를 상속한 것이므로

액티비티를 만들 때 그 안에서 이 메소드를 이용해 데이터베이스를 만들거나 열 수 있다.


The database, whether on the web or on the app, is the database, and Android has basically buili-in database-reated classes

The simplest way to create a database is to use the openOrCreateDatabase() method defined tn the context class.

The activity class that the application uses by default inherits Context

When you create an activity, you can use this method to create or open a database.


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<ListView
android:id="@+id/memo_list"
android:layout_width="match_parent"
android:layout_height="match_parent">

</ListView>

<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
app:useCompatPadding="true"
android:clickable="true"
app:fabSize="auto"
app:srcCompat="@drawable/add"
tools:layout_editor_absoluteX="328dp"
tools:layout_editor_absoluteY="455dp" />

</RelativeLayout>


메모하기 버튼이 있는 <activity_main>


activity-main with the Note button


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">

<EditText
android:id="@+id/title_edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="title"
android:maxLines="1"/>

<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/darker_gray">

<EditText
android:id="@+id/content_edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="contents"
android:background="@android:color/transparent"/>

</ScrollView>

</LinearLayout>

메모의 제목과 내용을 입력하는 <activity_memo>


Entering the title and content of the note activity_memo


import android.provider.BaseColumns;

// 테이블 정보를 담을 계약 클래스
// Contracy class to hold table information
public class MemoContract {

private MemoContract() {}

// BaseColumns 인터페이스는 _ID 및 _COUNT 열의 이름을 제공
// The BaseColumns interface provides the names of the
// _ID and _COUNT columns.
public static class MemoEntry implements BaseColumns {
public static final String TABLE_NAME = "memo";
public static final String COLUMN_NAME_TITLE = "title";
public static final String COLUMN_NAME_CONTENT = "content";
}
}

테이블의 정보를 담을 계약 클래스로 

테이블의 이름과 컬럼명을 저장해 두는 클래스이다.

BaseColumns를 상속받은 MemoEntry 클래스에 테이블명과 컬럼명을 담아둔다

이 BaseColumns를 상속받으면 _ID와 _COUNT를 사용할 수 있는데

_ID는 데이터 하나당 하나의 고유한 ID를 주는데 이를 이용하여 다양한 기능을 만들 수 있다.


To the contract class to hold information from the table

A class that stores the name and column name of a table

The MomoEntry class inherits BaseColumns contains the table name and column name

If you inherit this BaseColumns, you can use the _ID and _COUNT

An _ID gives one unique ID per data, which can be used to create a variety of functions.


public class MemoDbHelper extends SQLiteOpenHelper {

// 싱글턴 방식
// 하나의 인스턴스만 가져도 된다.
// singleton
// have one instance
private static MemoDbHelper sInstance;

public static final int DB_VERSION = 1;
public static final String DB_NAME = "Memo.db";
public static final String SQL_CREATE_ENTERS =
String.format(
"CREATE TABLE %s (%s INTEGER PRIMARY KEY AUTOINCREMENT, %s TEXT, %s TEXT)",
MemoContract.MemoEntry.TABLE_NAME,
MemoContract.MemoEntry._ID,
MemoContract.MemoEntry.COLUMN_NAME_TITLE,
MemoContract.MemoEntry.COLUMN_NAME_CONTENT);

public static final String SQL_DELETE_ENTERS =
"DROP TABLE IF EXISTS " + MemoContract.MemoEntry.TABLE_NAME;

public static MemoDbHelper getsInstance(Context context) {
if (sInstance == null) {
sInstance = new MemoDbHelper(context);
}
return sInstance;
}

private MemoDbHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}

// 최초의 DB 생성 부분
// First DB generation part
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(SQL_CREATE_ENTERS);
}

// DB가 변경될 경우 버전을 올려주고
// DB 변경점을 대응
// If the DB changes, can upload the version.
// respond to DB changes
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL(SQL_DELETE_ENTERS);
onCreate(db);
}
}

DB를 생성하는 클래스로 SQLiteOpenHelper를 상속받았다.

DB가 생성될 OnCreate와 디비의 내용이 변결 될 경우의 onUpgrade 메소드 두개를 오버라이딩 한다.

db.execSQL메소드를 사용하여 디비를 사용할 수 있으며

쿼리문을 넣어서 사용해도 되지만, 나중에 유지및 보수를 위해서 

변수로 정의해 놓는 것이 좋다.

쿼리문을 알고 있다면 그렇게 큰 어려움이 없는 부분이다.


It inherited SQLiteOpenHelper as the class thar creates the DB

Override the two onUpgrade methods if the content of the onCreate and onUpgrade to be created

You can use the db.execSQL method to use

Query may be inserted, but later for maintenance

You'd better define it as a variable.

If you know the query, you don't have that much difficulty


public class MemoActivity extends AppCompatActivity {
private EditText mTitleEditText;
private EditText mContentEditText;
private long mMemoId = -1;

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

mTitleEditText = findViewById(R.id.title_edit);
mContentEditText = findViewById(R.id.content_edit);

Intent intent = getIntent();
if (intent != null) {
mMemoId = intent.getLongExtra("id", -1);
String title = intent.getStringExtra("title");
String content = intent.getStringExtra("content");

mTitleEditText.setText(title);
mContentEditText.setText(content);
}
}

// 뒤로가기를 눌렀을 때
// back button press
@Override
public void onBackPressed() {
String title = mTitleEditText.getText().toString();
String contents = mContentEditText.getText().toString();

// SQLite에 저장하는 방법은
// ContentValues의 객체를 만들어서 저장 가능
// to dave to SQLite
// contentValues.put(key, value)
ContentValues contentValues = new ContentValues();
contentValues.put(MemoContract.MemoEntry.COLUMN_NAME_TITLE, title);
contentValues.put(MemoContract.MemoEntry.COLUMN_NAME_CONTENT, contents);

// DB에 전달
// 지금은 DB에 저장하기 때문에 getWritableDatabase
SQLiteDatabase db = MemoDbHelper.getsInstance(this).getWritableDatabase();

if (mMemoId == -1) {
long newRowID = db.insert(MemoContract.MemoEntry.TABLE_NAME,
null,
contentValues);

if (newRowID == -1) {
//Toast.makeText(this, "저장에 문제가 생겼습니다", Toast.LENGTH_SHORT).show();
Toast.makeText(this, "save error", Toast.LENGTH_SHORT).show();
} else {
//Toast.makeText(this, "저장이 되었습니다.", Toast.LENGTH_SHORT).show();
Toast.makeText(this, "save success", Toast.LENGTH_SHORT).show();
// 내용 전달
// content delivery
setResult(RESULT_OK);
}
} else {
// 내용이 수정이 되었다면
// if content has been modified.
int count = db.update(MemoContract.MemoEntry.TABLE_NAME, contentValues,
MemoContract.MemoEntry._ID + "=" + mMemoId, null);

if (count == 0) {
//Toast.makeText(this, "수정에 문제가 발생하였습니다", Toast.LENGTH_SHORT).show();
Toast.makeText(this, "modification error", Toast.LENGTH_SHORT).show();
} else {
//Toast.makeText(this, "수정이 되었습니다", Toast.LENGTH_SHORT).show();
Toast.makeText(this, "modification success", Toast.LENGTH_SHORT).show();
setResult(RESULT_OK);
}
}

super.onBackPressed();
}
}

메모의 제목과 내용을 입력 한 후에 뒤로가기 버튼을 누르면 메모가 저장이 된다.

SQLite에 저장을 할 때에는 ContentValues를 사용하며 (key, value)형식으로 저장한다.

db에 내용을 저장하기 위해서는 insert를 사용해야 하며 쿼리문을 알고있다면 이 메소드를 사용하는 것은 어렵지 않다.

db에 insert를 하기 위해서는 db를 write로 만들어야 하는데 이때, getWriteDatabase()로 해서 생성하도록 한다.

insert의 경우 타입이 long으로써 성공이 했다면 inset를 한 갯수가 반환 될 것이다. 

그러므로 -1의 경우 insert가 실패한 것이다.

내용이 수정될 경우 update를 사용하면 되며 where이라는 조건절에 _ID를 넣어서 사용하면 된다.

update는 타입이int이며 0이라면 수정에 실패가 한것이고, 1이 넘어오면 수정이 된것이다.

이 때 1은 게시물 하나를 수정을 해서 1이 반환된것이다.


After entering the title and contents of the note, press the Back button to save the note

Use ContentValues to save in SQLite (key,value) format

To store content in db, you must use insert, and if you know the query statement, it is not difficult to use this method.

In order to insert the db, the db must be written to create the db using GetWriteDatabase().

In case of insert, if type is successful as long, one number of inserts will be returned.

Therefore, in the case of -1, the insert has failed

If the content is modified, you can use update and _ID in the conditional clause

Update is typeint, 0 is the failure to modify and 1 is the correction

At this point, 1 wat returned by modifying one post.


public class MainActivity extends AppCompatActivity {

public static final int REQUEST_CODE_INSERT = 1000;
private MemoAdapter mAdapter;

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

FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 화면이 넘어감.. 이렇게 한줄로 표현이 가능.
// change view, this can be expressed in an single line
startActivityForResult(new Intent(MainActivity.this, MemoActivity.class), REQUEST_CODE_INSERT);
}
});

ListView listView = findViewById(R.id.memo_list);


Cursor cursor = getMemoCursor();
mAdapter = new MemoAdapter(this, cursor);
listView.setAdapter(mAdapter);

// 리스트의 아이템을 클릭했을 때 내용이 보이게 익명 클래스
// anonymous class to show content when you click an item is the list
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent intent = new Intent(MainActivity.this, MemoActivity.class);

Cursor cursor = (Cursor) mAdapter.getItem(position);

String title = cursor.getString(cursor.getColumnIndexOrThrow(MemoContract.MemoEntry.COLUMN_NAME_TITLE));
String content = cursor.getString(cursor.getColumnIndexOrThrow(MemoContract.MemoEntry.COLUMN_NAME_CONTENT));

intent.putExtra("id", id);
intent.putExtra("title", title);
intent.putExtra("content", content);

startActivityForResult(intent, REQUEST_CODE_INSERT);
}
});

// 리스트 아이템을 오래 누르고 있을때
// -> 삭제기능
// when long pressing the list item
// -> delete function
listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {

final long deleteId = id;

AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
//builder.setTitle("메모 삭제");
builder.setTitle("memo delete");
//builder.setMessage("메모를 삭제하시겠습니다?");
builder.setMessage("are you going to delete the note?");
builder.setPositiveButton("삭제(delete)", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// DB 불러오기
// calling up DB
SQLiteDatabase db = MemoDbHelper.getsInstance(MainActivity.this).getWritableDatabase();
int deletedCount = db.delete(MemoContract.MemoEntry.TABLE_NAME,
MemoContract.MemoEntry._ID + "=" + deleteId, null);

if (deletedCount == 0 ) {
//Toast.makeText(MainActivity.this, "삭제에 문제가 발생하였습니다", Toast.LENGTH_SHORT).show();
Toast.makeText(MainActivity.this, "delete error", Toast.LENGTH_SHORT).show();
} else {
mAdapter.swapCursor(getMemoCursor());
//Toast.makeText(MainActivity.this, "삭제가 되었습니다.", Toast.LENGTH_SHORT).show();
Toast.makeText(MainActivity.this, "delete success", Toast.LENGTH_SHORT).show();
}

}
});
//builder.setNegativeButton("취소", null);
builder.setNegativeButton("cancel", null);
builder.show();

return true;
}
});

}

// 디비에서 조회하는 메소드
// method that is inquiry by db
private Cursor getMemoCursor() {
MemoDbHelper dbHelper = MemoDbHelper.getsInstance(this);
return dbHelper.getReadableDatabase()
.query(MemoContract.MemoEntry.TABLE_NAME,
null, null, null, null, null, null);
}

// startActivityForResult 이걸로 넘겨서 받는 메소드
// startActivityForResult to receive data
// 메모 작성 후 보여질때 최신내용으로 다시 보여짐
// redisplay for the latest internal use when viewed after creating a note
// -> swapCursor()
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_INSERT && resultCode == RESULT_OK) {
mAdapter.swapCursor(getMemoCursor());
}
}

// 리스트뷰에 내용을 뿌리기 위한 Adapter
// Adapter to spray content in listView
private static class MemoAdapter extends CursorAdapter {

public MemoAdapter(Context context, Cursor c) {
super(context, c);
}

@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
// 안드로이드에서 미리 제공해주는 레이아웃을 뿌린다.
// show a layout that is provided in advance by android
return LayoutInflater.from(context).inflate(android.R.layout.simple_list_item_1, parent, false);
}

// 데이터를 실제로 뿌려주는 메소드
/// a method that actually spills data
@Override
public void bindView(View view, Context context, Cursor cursor) {
TextView titleText = view.findViewById(android.R.id.text1);
titleText.setText(cursor.getString(cursor.getColumnIndexOrThrow(MemoContract.MemoEntry.COLUMN_NAME_TITLE)));
}

}
}


반응형
복사했습니다!