안드로이드 SQLite? 데이터 저장 - 전화번호부 앱

YAMAMAMO·2021년 11월 13일
0

서론

-이전 포스팅에서 리사이클러뷰를 이용한 전화번호부 앱을 만들었습니다. 이름과 전화번호를 입력할 수 있고 입력된 데이터들은 리사이클러뷰에 나타는 것을 볼 수 있었습니다. 하지만 앱을 끄고난 후 앱을 켜면 입력되었던 데이터들이 다 사라졌습니다. 네 저장기능이 없는 반 쪽 짜리 전화번호부 앱이었습니다. 그러면 이번 포스팅에서는 입력한 데이터를 저장하는 방법을 알아 보겠습니다.

데이터 저장

-데이터를 저장하는 방법에는 서버에 있는 데이터베이스에 데이터를 저장하거나, 핸드폰 자체에 데이터를 저장하는 방법이 있습니다. 이번에는 핸드폰에 저장하는 방식으로 앱을 구현 해보겠습니다.

-로컬에 데이터를 저장하는 방법에는 SharedPreferece, SQLite 를 사용할 수 있습니다. 이 포스팅에서는 SQLite 를 사용하겠습니다.

SQLite?

-SQLite는 작고, 빠르며, 독립적 이며, 신뢰성이 높으며, 완전한 기능을 갖춘 SQL 데이터베이스 엔진을 구현하는 C언어 라이브러리입니다. SQLite는 세계에서 가장 많이 사용된느 데이터베이스 엔진입니다. SQLite는 모든 휴대폰과 대부분의 컴퓨터에 내장되어 있으며 사람들이 매일 사용하는 수 많은 다른 응용 프로그램에 번들로 제공 됩니다.

https://www.sqlite.org/index.html

-데이터베이스에 데이터를 저장하는 작업은 연락처 정보와 같이 반복적이거나 구조화된 데이터에 이상적입니다.

테이블 생성

-테이블은 간단히 말해서 표입니다. 엑셀표와 같다고 생각하시면 됩니다.
예시

  • 위와 같은 방식으로 데이터를 저장 합니다.
  • 전화번호부는 테이블 이름을 뜻합니다.
  • 컬럼(열)은 번호, 이름, 전화번호 입니다.

DBHelper 클래스 생성

public class DBHelper extends SQLiteOpenHelper {
    public static final int DATABASE_VERSION = 1;  // 데이터베이스 스키마를 변경하는 경우 데이터베이스 버전을 증가시켜야 합니다.
    public static final String DATABASE_NAME = "MobileNumber.db"; // 데이터베이스 이름 

    public DBHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(FeedEntry.SQL_CREATE_ENTRIES); //테이블 생성
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int i, int i1) {
        db.execSQL(FeedEntry.SQL_DELETE_ENTRIES); 
        onCreate(db);
    }

    public static class FeedEntry implements BaseColumns {
        public static final String TABLE_NAME = "phoneBook"; //테이블 명
        public static final String COLUMN_NAME_NAME = "name"; //컬럼 명
        public static final String COLUMN_NAME_NUMBER = "number"; //컬럼 명

        //테이블 생성 쿼리
        private static final String SQL_CREATE_ENTRIES =
                "CREATE TABLE " + FeedEntry.TABLE_NAME + " (" +
                        FeedEntry._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
                        FeedEntry.COLUMN_NAME_NAME + " TEXT," +
                        FeedEntry.COLUMN_NAME_NUMBER + " TEXT)";
        //DROP TABLE 테이블을 삭제 쿼리
        //IF EXISTS 절을 사용하면 삭제하려는 데이터베이스나 테이블이 존재하지 않아서 발생하는 에러를 미리 방지.
        private static final String SQL_DELETE_ENTRIES =
                "DROP TABLE IF EXISTS " + FeedEntry.TABLE_NAME;
    }
}

MainAcitivity

public class MainActivity extends AppCompatActivity {
    private String TAG = "MainActivity";
    private Context mContext;
    private ArrayList<Data> mArrayList;
    private Adapter mAdapter;
    private RecyclerView mRecyclerView;
    private EditText edit_name, edit_number;
    private Button btn_save;
    private DBHelper mDbHelper;
    private SQLiteDatabase db;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate (savedInstanceState);
        setContentView (R.layout.activity_main);
        mContext = MainActivity.this;
        edit_name = findViewById (R.id.edit_name);
        edit_number = findViewById (R.id.edit_number);
        btn_save = findViewById (R.id.btn_save);
        mRecyclerView = findViewById (R.id.recycler)

        //DBHelper 객체를 선언해줍니다.
        mDbHelper = new DBHelper (mContext);
        //쓰기모드에서 데이터 저장소를 불러옵니다.
        db = mDbHelper.getWritableDatabase ();
				
	//리사이클러뷰 객체 생성 어댑터 연결 약간의 리팩토링 
	initRecyclerView ();

        //버튼 클릭이벤트
        //이름과 전화번호를 입력한 후 버튼을 클릭하면 어레이리스트에 데이터를 담고 리사이클러뷰에 띄운다.
        btn_save.setOnClickListener (new View.OnClickListener () {
            @Override
            public void onClick(View view) {
                if (edit_name.getText ().length () == 0 && edit_number.getText ().length () == 0) {
                    Toast.makeText (mContext, "이름과 전화번호를 입력해주세요", Toast.LENGTH_SHORT).show ();
                } else {
                    String name = edit_name.getText ().toString ();
                    String number = edit_number.getText ().toString ();
                    edit_name.setText ("");
                    edit_number.setText ("");
                    Data data = new Data (name, number);

                    mArrayList.add (data);
                    mAdapter.notifyItemInserted (mArrayList.size () - 1);

                    //데이터를 테이블에 삽입합니다.
                    insertNumber (name, number);

                }
            }
        });

        //리사이클러뷰 클릭 이벤트
        mAdapter.setOnItemClickListener (new Adapter.OnItemClickListener () {

            //아이템 클릭시 토스트메시지0
            @Override
            public void onItemClick(View v, int position) {
                String name = mArrayList.get (position).getName ();
                String number = mArrayList.get (position).getNumber ();
                Toast.makeText (mContext, "이름 : " + name + "\n전화번호 : " + number, Toast.LENGTH_SHORT).show ();
            }

            //수정
            @Override
            public void onEditClick(View v, int position) {
                String name = mArrayList.get (position).getName ();
                String number = mArrayList.get (position).getNumber ();

                editItem (name, number, position);
            }

            //삭제
            @Override
            public void onDeleteClick(View v, int positon) {
                mArrayList.remove (positon);
                mAdapter.notifyItemRemoved (positon);
            }

        });

    }

    //데이터 삽입
    private void insertNumber(String name, String number){
        //쿼리를 직접 작성해서 입력하거나 values를 만들어서 하는 방법이 있다
        //후자를 이용하겠다. 
        ContentValues values = new ContentValues();
        values.put(DBHelper.FeedEntry.COLUMN_NAME_NAME, name);
        values.put(DBHelper.FeedEntry.COLUMN_NAME_NUMBER, number);
        db.insert(DBHelper.FeedEntry.TABLE_NAME, null, values);
        
	//데이터베이스를 공부할 때 직접 쿼리를 짜보는 것도 도움이 됩니다.
//        String sql = "INSERT INTO "+DBHelper.FeedEntry.TABLE_NAME+" values("+name+", "+number+");";
//        db.execSQL(sql);

    }

    //리사이클러뷰
    private void initRecyclerView(){
        //레이아웃메니저는 리사이클러뷰의 항목 배치를 어떻게 할지 정하고, 스크롤 동작도 정의한다.
        //수평/수직 리스트 LinearLayoutManager
        //그리드 리스트 GridLayoutManager
        LinearLayoutManager layoutManager = new LinearLayoutManager (mContext, LinearLayoutManager.VERTICAL, false);
        mRecyclerView.setLayoutManager (layoutManager);

        mArrayList = new ArrayList<> ();
        mAdapter = new Adapter (mContext, mArrayList);
        mRecyclerView.setAdapter (mAdapter);

    }

    //AlertDialog 를 사용해서 데이터를 수정한다.
    private void editItem(String name, String number, int position) {
        AlertDialog.Builder builder = new AlertDialog.Builder (this);
        View view = LayoutInflater.from (this).inflate (R.layout.dialog, null, false);
        builder.setView (view);

        final AlertDialog dialog = builder.create ();

        final Button btn_edit = view.findViewById (R.id.btn_edit);
        final Button btn_cancel = view.findViewById (R.id.btn_cancel);
        final EditText edit_name = view.findViewById (R.id.edit_editName);
        final EditText edit_number = view.findViewById (R.id.edit_editNumber);

        edit_name.setText (name);
        edit_number.setText (number);

        // 수정 버튼 클릭
        //어레이리스트 값을 변경한다.
        btn_edit.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view)
            {
                String editName = edit_name.getText ().toString ();
                String editNumber = edit_number.getText ().toString ();
                mArrayList.get (position).setName (editName);
                mArrayList.get (position).setNumber (editNumber);
                mAdapter.notifyItemChanged (position);
                dialog.dismiss();
            }
        });

        // 취소 버튼 클릭
        btn_cancel.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view)
            {
                dialog.dismiss();
            }
        });

        dialog.show ();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy ();
        mDbHelper.close();
    }

}

앱을 실행해서 데이터를 입력하면 SQLite에 저장할 수 있습니다. 하지만 데이터가 잘 입력 되었는지 알 수 없습니다. 이번에는 저장된 데이터를 불러와 보겠습니다.

데이터 불러오기

public class MainActivity extends AppCompatActivity {
   
  ......

    //데이터 삽입
    private void insertNumber(String name, String number) {
        //쿼리를 직접 작성해서 입력하거나 values를 만들어서 하는 방법이 있다
        //후자를 이용하겠다.
        ContentValues values = new ContentValues ();
        values.put (DBHelper.FeedEntry.COLUMN_NAME_NAME, name);
        values.put (DBHelper.FeedEntry.COLUMN_NAME_NUMBER, number);
        db.insert (DBHelper.FeedEntry.TABLE_NAME, null, values);
	
    	//데이터베이스를 공부할 때 직접 쿼리를 짜보는 것도 도움이 됩니다.
//        String sql = "INSERT INTO "+DBHelper.FeedEntry.TABLE_NAME+" values("+name+", "+number+");";
//        db.execSQL(sql);

    }

    //데이터 불러오기
    //Cursor를 사용해서 데이터를 불러옵니다.
    //while문을 사용해서 불러온 데이터를 mArrayList에 삽입합니다.
    private void loadData() {
        @SuppressLint("Recycle") Cursor c = db.rawQuery ("SELECT * FROM " + DBHelper.FeedEntry.TABLE_NAME, null);
        while (c.moveToNext ()) {
            String name = c.getString (c.getColumnIndex (DBHelper.FeedEntry.COLUMN_NAME_NAME));
            String number = c.getString (c.getColumnIndex (DBHelper.FeedEntry.COLUMN_NAME_NUMBER));
            Data data = new Data (name, number);

            mArrayList.add (data);
        }

        mAdapter.notifyDataSetChanged ();
    }

    //리사이클러뷰
    private void initRecyclerView() {
        //레이아웃메니저는 리사이클러뷰의 항목 배치를 어떻게 할지 정하고, 스크롤 동작도 정의한다.
        //수평/수직 리스트 LinearLayoutManager
        //그리드 리스트 GridLayoutManager
        LinearLayoutManager layoutManager = new LinearLayoutManager (mContext, LinearLayoutManager.VERTICAL, false);
        mRecyclerView.setLayoutManager (layoutManager);

        mArrayList = new ArrayList<> ();
        mAdapter = new Adapter (mContext, mArrayList);
        mRecyclerView.setAdapter (mAdapter);

        //저장된 데이터를 불러옵니다.
        loadData ();

    }

  .......

}

-loadData 메서드를 만들어서 리사이클러뷰 객체 생성될 때 데이터를 로드 해줍니다.

-데이터가 저장되고 앱을 재실행하면 데이터를 불러옵니다.

마무리

-SQLite에 데이터를 저장 하는 것을 해보았습니다. 안드로이드 개발문서를 참고해서 개발을 했습니다.

(https://developer.android.com/training/data-storage/sqlite)

-이해가 안 가는 부분이 있으면 안드로이드 개발문서를 보거나 댓글 부탁드립니다.

-다음 포스팅은 저장된 데이터를 수정하거나 삭제하는 방법을 알아보겠습니다.

-코드는 조금씩 리팩토링 해가면서 작성됩니다. 모든 코드는 이 시리즈를 처음부터 보면 알 수 있습니다. 추후 앱이 완성되면 깃헙에 올릴 예정입니다.

profile
안드로이드 개발자

0개의 댓글