Android Studio SQLite DB에 대해 다뤄보자.
안드로이드에서 데이터를 저장하는 방법은 다음과 같은 것들이 있다.
SharedPreference |
key - value 으로 저장하여 모든 Intent에서 활용 가능 주로 서버 로그인후 idx, userID 등의 정보를 저장하여 활용한다. 앱이 삭제되면 저장된 정보는 삭제된다.
|
Internal Storage
|
안드로이드는 리눅스 운영체제를 수정하여 만들었으며, /data/data/어플리케이션패키지명/files 디렉토리에 저장한다. 앱이 삭제되면 어플리케이션패키지명이 삭제되므로 이 공간에 저장된 파일들도
삭제된다.
|
External Storage
|
외부저장공간은 탈착이 가능한 SD카드다. 안드로이드 장치는 외부 저장 공간을 지원하므로
외부 저장공간에 파일을 저장할 수 있다. 누구나 읽을 수 있고 사용자에의해 변경될 수 있다.
|
SQLite 데이터베이스
|
구조화된 데이터를 DB에 저장한다. SQLite는 초경량 데이터베이스로 데이터를 디스크 파일에 저장한다. 데이터 정의 명령어는 테이블을 생성/변경/삭제한다. 데이터 조작 명령어는 데이터를 조회/추가/삭제/수정한다.
|
Cursor 사용
Cursor 인터페이스는 데이터베이스 쿼리에 의해서 반환된 result 셋에 임시적으로 데이터를 읽고 쓰기 위해서 액세스할 수 있는 기능을 제공하는 인터페이스다.
인자 |
내용 설명
|
moveToFirst |
커서가 쿼리(질의) 결과 레코드들 중에서 가장 처음에 위치한 레코드를 가리키도록 한다. |
moveToLast | 마지막 행으로 이동
|
moveToNext |
다음 레코드로 커서를 이동 |
moveToPrevious |
이전 레코드로 커서를 이동
|
moveToPosition(int position)
| 파라미터로 주어진 절대 행 위치로 이동한다. 성공적이면 true 반환
|
getCount | 질의 결과값(레코드)의 갯수를 반환, 조건이 없으면 총개수 반환
|
getColumnCount | 총 칼럼 개수를 반환
|
getColumnIndex | 해당 이름의 칼럼의 0 베이스 칼럼 인덱스 값을 반환해준다. 해당 이름의 칼럼이 존재하지 않으면 -1을 반환한다.
|
getColumnIndexOrThrow | 해당 이름을 가지고 있는 칼럼의 0 베이스 인덱스 번호를 반환한다. 해당 이름의 칼럼이 존재하지 않으면 IllegalArgumentException 을 발생시킨다. |
getColumnName | 특정 인덱스값에 해당하는 필드 이름을 반환 |
getColumnNames | 칼럼의 이름들을 String(문자열) 배열 형태로 반환 |
moveToPosition | 커서를 특정 레코드로 이동시킨다 |
getPosition |
커서가 현재 가리키고 있는 위치를 반환 |
getDouble | 해당 인덱스의 칼럼 값을 double 형으로 반환한다.
|
close() | 열려있는 커서를 닫는다.
|
SQLite 데이터베이스의 특성상 하나의 테이블의 레코드를 읽어 오기 위해서는 커서(cursor)라는 것이 필요하다.
조건에 맞는 레코드를 한꺼번에
모두 가져올 수 없기 때문에 커서(cursor)를 이용해서 조작을 한다.
커서(cursor)는 현재 레코드를 가리킨다.
하나씩 이 커서(cursor)를 이동하면서 레코드 하나하나씩을 접근해서 가져온다. 이 커서 객체를 이용하여 get을 하게 되면 컬럼 번호에
맞게 데이터를 가져올 수 있다.
커서는 정방향이나 역방향으로 움직일 수 있다.
SQLite 는 구글 안드로이드 운영체제에 기본 탑재된 데이터베이스로 비교적 가벼운 데이터베이스다.
SQL 기본 문법은 http://www.w3schools.com/sql/default.asp 에서 익히면 된다. SQLite 는 완전히 독립적이고 서버 기능을 제공하지 않으며, 트랜잭션을 지원하며 쿼리를 수행할 수 있는 표준 SQL 언어를 사용한다.
SQLite 만의 문법사항을 알아야만 편하다. 간단하게 SQLite 의 문법 사항을 알아보자. ㅇ Data Type : Null, Integer(정수), Real(실수), Text(문자열), Blob - Integer : 부호있는 정수, 실제 값에 따라 1byte ~ 8bytes까지 가변적으로 저장됨 - Boolean values are stored as integers 0 (false) and 1 (true). - Date and Time 데이터 타입은 없다. datetime은 입력되는 값에 따라 Text, Real, Integer 타입으로 저장됨
ㅇ JOIN : Left Outer Join, INNER Join 지원 ㅇ Rename Table, Add Column 지원 (Drop Column, Alter Column, Add Constraint 미지원) - 한번에 여러 Column 추가 안된다. - Join Update 를 지원하지 않는다.
ㅇ Grant and Revoke : 별도로 권한 부여 기능이 없고, OS 파일 시스템 권한을 사용
SQLite 에 대한 자세한 설명은 http://overoid.tistory.com/19 에 잘 설명되어 있다.
영문 원본을 읽어보려면 http://www.sqlite.org/datatype3.html 를 보면 된다. |
http://www.androidhive.info/2011/11/android-sqlite-database-tutorial/ 에 좋은 예제가 있다.
초기 데이터가 많은 경우 DB 파일을 assets 에 저장해두고 copy 해서 SQLite 저장하는 것은 해보지 않았다.
서버 데이터를 가져오는 케이스에 대한 로직을 그려본다면 ...
서버에 있는 자료를 읽어서 SQLite DB에 저장하고, SQLite DB에 저장된 데이터를 읽어서 ArrayList에 저장하고 ListView 또는 RecyclerView 를 통해 보여주거나, 폰에 주소록을 저장할 수도 있다.
안드로이드에서 데이터베이스를 사용하려면
- SQLiteOpenHelper 를 사용하는 방법
- openOnCreateDatabase() 메소드로 데이터베이스 객체를 직접 생성하는 방법
둘 중 하나를 선택해야 한다.
안드로이드에 내장되어 있는 SQLite을 사용하기 위해서는 SQLiteOpenHelper 클래스를 이용해야 한다.
SQLiteOpenHelper 클래스는 데이터베이스를 생성하고 버전을 관리 할 수 있도록 도와주는 클래스이다.
SQLiteOpenHelper 클래스를 이용하면 SQL 기본 사용법을 알면 쉽게 처리할 수가 있다.
SQLiteOpenHelper 를 사용하는 방법으로 코드를 구현해 보자.
=== SQLiteDBHandler ===
|
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;
import java.util.ArrayList; import java.util.List;
public class SQLiteDBHandler extends SQLiteOpenHelper { public static final String TAG = "DBHelper";
private static final int DATABASE_VERSION = 1; private static final String DATABASE_NAME = "mCRM.db"; public static final String TABLE_NAME = "PBbook";
public static final String Column_Uid = "uid"; public static final String Column_Name = "name"; public static final String Column_mobileNO ="mobileNO"; public static final String Column_officeNO ="officeNO"; public static final String Column_profile_image = "profile_image";
public SQLiteDBHandler(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); }
@Override public void onCreate(SQLiteDatabase db) { String Member_Create = "create table "+ TABLE_NAME + " (" + "idx INTEGER PRIMARY KEY AUTOINCREMENT,"+ "uid INTEGER not null," + "name TEXT not null," + "mobileNO TEXT not null," + "officeNO TEXT," + "profile_image TEXT);"; db.execSQL(Member_Create); Log.v(TAG,"DB Created"); }
@Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { Log.w("LOG_TAG", "Upgrading database from version " + oldVersion + " to " + newVersion + ", which will destroy all old data"); // KILL PREVIOUS TABLES IF UPGRADED db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME); onCreate(db); //새로 생성하기 Log.v(TAG,"DB Updated"); }
public void InsertData(String uid,String name, String mobileNO, String officeNO,String profile_image) { SQLiteDatabase db = getWritableDatabase(); // 쓰기 가능한 데이터베이스를 가져와 입력
// 이름 + 휴대폰번호 기준으로 중복 체크 String query = "select idx from " + TABLE_NAME + " where " + Column_Name + "= '"+ name +"' and " + Column_mobileNO + "= '" + mobileNO + "'"; Cursor cursor = db.rawQuery(query, null); cursor.moveToFirst(); // Cursor를 제일 첫행으로 이동 if( cursor.getCount() == 0) { // 중복이 없으면 저장하라. ContentValues cv = new ContentValues(); // 객체 생성 cv.put(Column_Uid, uid); cv.put(Column_Name, name); cv.put(Column_mobileNO, mobileNO); cv.put(Column_officeNO, officeNO); cv.put(Column_profile_image, profile_image); db.beginTransaction(); // 대량건수 데이터 입력 처리를 고려 try{ long rowId = db.insert(TABLE_NAME, null, cv); if(rowId < 0){ throw new SQLException("Fail to Insert"); } db.setTransactionSuccessful(); } catch(Exception e){ Log.i(TAG,e.toString()); } finally { db.endTransaction(); Log.v(TAG,"DB Inserted " + name + " uid =" + uid); } } cursor.close(); db.close(); }
/* Get the first row Column_ID from the table */ public int getFirstId() { int idToUpdate = 0; String query = "select idx from " + TABLE_NAME + " LIMIT 1";
SQLiteDatabase db = this.getReadableDatabase(); Cursor res = db.rawQuery(query, null);
if (null != res && res.getCount() > 0) { res.moveToFirst(); // Cursor를 제일 첫행으로 이동 idToUpdate = res.getInt(0); } return idToUpdate; }
/* Update the table row with Column_ID - id */ public boolean updateDB(Integer idx, String name, String mobileNO, String officeNO) { Log.i(TAG, "Updating Column_ID : " + idx); ContentValues cv = new ContentValues(); cv.put(Column_Name, name); cv.put(Column_mobileNO, mobileNO); cv.put(Column_officeNO, officeNO);
SQLiteDatabase db = this.getWritableDatabase(); db.update(TABLE_NAME, cv, "idx = ? ", new String[]{Integer.toString(idx)}); return true; }
/* Delete the row with Column_ID - id from the employees table */ public Integer deleteRow(Integer idx) { SQLiteDatabase db = this.getWritableDatabase(); return db.delete(TABLE_NAME, "idx = ? ", new String[]{Integer.toString(idx)}); }
public int getTableRowCount() { String countQuery = "SELECT * FROM " + TABLE_NAME; SQLiteDatabase db = this.getReadableDatabase(); Cursor cursor = db.rawQuery(countQuery, null); Log.i(TAG, "Total Row : " + cursor.getCount()); cursor.close(); return cursor.getCount(); }
// Getting All Contacts public List<Address_Item> getAllPBook() { List<Address_Item> pbookData = new ArrayList<Address_Item>(); // Select All Query String selectQuery = "SELECT * FROM " + TABLE_NAME;
SQLiteDatabase db = this.getWritableDatabase(); Cursor cursor = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list if (cursor.moveToFirst() && cursor.getCount() > 0) { do { Address_Item contact = new Address_Item(); contact.setUid(cursor.getString(1)); contact.setName(cursor.getString(2)); contact.setMobileNO(cursor.getString(3)); contact.setOfficeNO(cursor.getString(4)); contact.setProfile_image(cursor.getString(5)); // Adding contact to list pbookData.add(contact); // DB에서 받아온 값을 ArrayList에 Add } while (cursor.moveToNext()); } cursor.close(); return pbookData; // return contact list } }
|
=== Address_Item.java ===
|
public class Address_Item { // PersonData 정보를 담고 있는 객체 생성 private String profile_image; // 이미지 경로를 String으로 받기 위해서 private String uid; private String name; private String mobileNO; private String officeNO; boolean checkBoxState;
public Address_Item() { }
public Address_Item(String profile_image, String uid, String name, String mobileNO, String officeNO, boolean checkBoxState) { this.profile_image = profile_image; this.uid = uid; this.name = name; this.mobileNO = mobileNO; this.officeNO = officeNO; this.checkBoxState = checkBoxState; }
public String getProfile_image() { return profile_image; }
public void setProfile_image(String profile_image) { this.profile_image = profile_image; }
public String getUid() { return uid; }
public void setUid(String uid) { this.uid = uid; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getMobileNO() { return mobileNO; }
public void setMobileNO(String mobileNO) { this.mobileNO = mobileNO; }
public String getOfficeNO() { return officeNO; }
public void setOfficeNO(String officeNO) { this.officeNO = officeNO; }
public boolean isCheckBoxState() { return checkBoxState; }
public void setCheckBoxState(boolean checkBoxState) { this.checkBoxState = checkBoxState; } } |
MainActivity.java 파일에서 구현할 코드는 다음과 같다.
import android.app.Activity; import android.app.ProgressDialog; import android.content.ContentResolver; import android.content.Context; import android.content.SharedPreferences; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Button; import android.widget.TextView; import android.widget.Toast;
import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject;
import java.util.List;
public class MainActivity extends AppCompatActivity {
SQLiteDBHandler sqLiteDBHandler; public SharedPreferences settings; ProgressDialog mProgressDialog;
TextView textView; Context context;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_sqlite2contact);
textView = (TextView) findViewById(R.id.sqlite_txt);
sqLiteDBHandler = new SQLiteDBHandler(MainActivity.this); // 서버에서 데이터를 가져와서 DB에 insert settings = getSharedPreferences("settings", Activity.MODE_PRIVATE); Uri.Builder builder = new Uri.Builder() .appendQueryParameter("idx", settings.getString("idx","")); String postParams = builder.build().getEncodedQuery(); new getOrgChartData().execute(Value.IPADDRESS + "/get_json.php",postParams);
// 저장버튼을 클릭하면 SQLite DB에 저장된 데이터를 폰의 주소록에 저장하는 기능 Button btn_contactSave = (Button) findViewById(R.id.btn_sqlite_save); btn_contactSave.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { List<Address_Item> contacts = sqLiteDBHandler.getAllPBook(); int num = 0; for(Address_Item item : contacts){ num++; int rawContactId = 0; Contacts phonebook = new Contacts(); // 전화번호부 객체 생성 ContentResolver cr = getContentResolver(); String strContactName = item.getName(); String strMobileNO = item.getMobileNO(); String strofficeNO = item.getOfficeNO(); String strEmail = ""; String strPhoto = ""; if (item.getProfile_image().length() > 0) { strPhoto = Value.IPADDRESS + "/photos/" + item.getProfile_image(); } rawContactId = phonebook.ContactsIDExistCheck(cr, strContactName); if (rawContactId > 0) { // 기존 전화번호가 존재하면 삭제하고 새로 입력 phonebook.ContactsIDdelete(cr, context, rawContactId); } phonebook.ContactsIDinsert(cr, context, strContactName, strMobileNO, strofficeNO, strEmail, strPhoto); } Toast.makeText(getApplicationContext(), "총" + num + "개 연락처가 저장되었습니다.", Toast.LENGTH_LONG).show(); } });
}
class getOrgChartData extends AsyncTask<String, Void, String> { @Override protected void onPreExecute() { super.onPreExecute(); // Create a progressdialog mProgressDialog = new ProgressDialog(MainActivity.this); mProgressDialog.setTitle("Personal Profile JSON Parse"); mProgressDialog.setMessage("Loading..."); mProgressDialog.setIndeterminate(false); mProgressDialog.show(); // Show progressdialog }
@Override protected String doInBackground(String... params) { try { return PHPComm.getJson(params[0],params[1]); } catch (Exception e) { return new String("Exception: " + e.getMessage()); } }
protected void onPostExecute(String result){ searchJSON=result; showJSONObjectList(); mProgressDialog.dismiss(); } }
// 서버 정보를 파싱하기 위한 변수 선언 String searchJSON; private static final String TAG_RESULTS="result"; private static final String TAG_UID = "uid"; // 서버 테이블의 실제 필드명 private static final String TAG_NAME = "userNM"; private static final String TAG_MobileNO ="mobileNO"; private static final String TAG_OfficeNO ="telNO"; private static final String TAG_Image = "photo"; // 이미지 필드 JSONArray peoples = null;
protected void showJSONObjectList() { try { JSONObject jsonObj = new JSONObject(searchJSON); peoples = jsonObj.getJSONArray(TAG_RESULTS);
for(int i=0;i<peoples.length();i++){ JSONObject c = peoples.getJSONObject(i); final String uid = c.getString(TAG_UID); final String name = c.getString(TAG_NAME); final String mobileNO = c.getString(TAG_MobileNO); final String officeNO = c.getString(TAG_OfficeNO); final String Profile_Image = c.getString(TAG_Image);
// 서버에서 가져온 데이터 저장 sqLiteDBHandler.InsertData(uid,name, mobileNO, officeNO,Profile_Image); }
} catch (JSONException e) { e.printStackTrace(); }
textView.setText(String.valueOf(sqLiteDBHandler.getTableRowCount())); }
}
|
도움되셨다면 00 클릭~ 해주시길 ^^
참고하면 도움이 될 게시글
https://sites.google.com/site/ydhanslab/andeuloideu/oebusqlitedbneohgi