이번 예제에서는 SQLite를 사용한 아주 간단한 회원가입 / 로그인 기능을 구현해볼 예정입니다.
스틱코드를 작성해서 좀 더 빠르게 기능을 만들어 보았습니다.
stickode.com/detail.html?no=1867 - xml, activity 코드
stickode.com/detail.html?no=1868 - sqlite 관련 코드
관련한 모든 코드내역은 해당 링크에서 확인하실수 있습니다.
해당 포스팅을 즐겨찾기, 혹은 내 스틱코드로 복사하여 포스팅 후 안드로이드 스튜디오를 재시작(모든 프로젝트 종료후)
이후에 포스팅을 따라서 구현해주시기 바랍니다.
Activity코드, xml 코드는 파일명으로
나머지 코드는 sqlite 를 치고 자동완성하실수 있습니다.
그래들 View-Binding 설정
View-Binding 설정을 해줘야합니다.
android{
viewBinding {
enabled = true
}
}
로그인 / 회원가입 만들기 구성목록 정리
MainActivity(로그인 하는 액티비티) , RegisterActivity(회원가입 하는 액티비티),
SecondActivity(로그인 성공시 넘어가는 빈 액티비티)
LocalDB(SQLite DB 클래스) LocalDatas(SQLite DB 테이블 구조 정의된 클래스)
구성목록 만들기
우선 위 메뉴로 들어가서 Activity와 xml 파일을 자동 생성해줍니다.
기본적으로 주어진 MainActivity 외에 회원가입을 진행할 RegisterActivity,
로그인시 넘겨줄 화면인 SecondActivity를 생성해줍니다.
다음은 SQLite를 제어할 클래스,object 파일을 생성합니다.
LocalDB Class와 LocalDatas Object 를 생성하면 됩니다.
이러면 우선 기본적인 파일 생성이 끝났습니다.
로그인 / 회원가입 관련 XML 만들기
최소한의 View로 구현된 XML 파일입니다.
View-Binding을 이용했기 때문에 id 값이 변수로 적용되는점을 참고하시면 좋습니다.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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">
<EditText
android:id="@+id/edit_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="312dp"
android:ems="10"
android:hint="아이디"
android:inputType="textPersonName"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.502"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/edit_pw"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:ems="10"
android:hint="비밀번호"
android:inputType="textPassword"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.502"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/edit_id" />
<Button
android:id="@+id/btn_login"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="100dp"
android:layout_marginLeft="100dp"
android:layout_marginTop="24dp"
android:text="로그인"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/edit_pw" />
<Button
android:id="@+id/btn_register"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginEnd="100dp"
android:layout_marginRight="100dp"
android:text="가입하기"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/edit_pw" />
</androidx.constraintlayout.widget.ConstraintLayout>
activity_register.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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=".RegisterActivity">
<EditText
android:id="@+id/edit_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="312dp"
android:ems="10"
android:hint="아이디"
android:inputType="textPersonName"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.502"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/edit_pw"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:ems="10"
android:hint="비밀번호"
android:inputType="textPassword"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.502"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/edit_id" />
<EditText
android:id="@+id/edit_pw_re"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:ems="10"
android:hint="비밀번호 확인"
android:inputType="textPassword"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.502"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/edit_pw" />
<Button
android:id="@+id/btn_register"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:layout_marginEnd="160dp"
android:layout_marginRight="160dp"
android:text="회원가입"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/edit_pw_re" />
</androidx.constraintlayout.widget.ConstraintLayout>
stickode.com/detail.html?no=1867
링크의 즐겨찾기후 스틱코드를 사용하면 다음과 같이 XML 파일을 빠르게 생성할수 있습니다.
기본 xml 파일을 지우고 코드를 복사 붙여넣기 하거나 스틱코드를 이용하시면 됩니다.
activity_main.xml, activity_register.xml 작성이 끝났습니다.
SQLite 모듈화 사용 코드 작성
우선 사용될 테이블부터 정의해보겠습니다. 저는 최소한의 기능만을 가지고 있기를 원하기 때문에
id, password 값만을 저장하는 테이블을 작성하겠습니다. 그외에는 _ID 라는 primary key autoincrement 인덱스 값을
컬럼으로 가집니다.
우선 LocalDatas object 파일에 가서 패키지 부분을 제외한 나머지 코드를 지우고 스틱코드를 입력합니다.
오류가 뜨는 부분은 위에서부터 alt+enter로 지워줍니다.
object LocalDatas { // 로컬 데이터 베이스의 자료형태 정의된 object
object userData : BaseColumns { // users 라는 DB 테이블의 데이터 컬럼 내용 정리
const val TABLE_NAME = "users"
const val COLUMN_NAME_ID = "id" // 임의의 컬럼명 작성
const val COLUMN_NAME_PASSWORD = "password" // 임의의 컬럼명 작성
}
object Groups :BaseColumns{ // 만약 그룹에 관련한 DB 형식을 지정하고 싶다면 동일한 방식으로 추가합니다.
}
}
해당 코드에서 테이블명과 컬럼명을 미리 정의해둡니다. 사용하고자하는 테이블 형태에 맞게 추가하시면 됩니다.
LocalDB.kt 파일내용을 모두 지우고 sqlite 를 입력후 스틱코드를 입력합니다.
마찬가지로 오류가 뜨는 부분은 위에서부터 alt+enter로 지워줍니다.
최초실행(혹은 sqlite버전업)시 아까 정의해둔 컬럼값들을 가지고 DB 테이블을 생성합니다.
fun createDatabase(db: SQLiteDatabase) {
// 테이블이 존재하지 않는경우 생성
var sql: String = "CREATE TABLE if not exists ${LocalDatas.userData.TABLE_NAME} (" +
"${BaseColumns._ID} integer primary key autoincrement," +
"${LocalDatas.userData.COLUMN_NAME_ID} varchar(15)," +
"${LocalDatas.userData.COLUMN_NAME_PASSWORD} varchar(20)"+
");"
db.execSQL(sql)
}
LocalDatas에 맞게 작성해 주면 됩니다. BaseColumns._ID값은 위에서 말한 PK 인덱스값입니다.
다음은 DB내에 로그인, 회원가입 함수, 같은 ID의 유저가 존재하는지 여부를 확인하는 함수 를 추가해보겠습니다.
우선 id, password 두개의 값을 받아서 SQLite 테이블에 insert하는 함수를 작성해 보겠습니다.
fun registerUser(id:String, password:String){
}
자동완성된 상태에서 컬럼명을 LocalDatas의 값으로, insert할 값을 id, password로 변경해줍니다.
fun registerUser(id: String, password:String){
val db =this.writableDatabase
val values = ContentValues().apply {// insert될 데이터값
put(LocalDatas.userData.COLUMN_NAME_ID, id)
put(LocalDatas.userData.COLUMN_NAME_PASSWORD, password)
}
val newRowId = db?.insert(LocalDatas.userData.TABLE_NAME, null, values)
// 인서트후 인서트된 primary key column의 값(_id) 반환.
}
이제 아이디를 확인하는 함수를 만들어 보겠습니다. 아이디값을 받아서 값이 존재여부에 따라 true/false를 반환합니다.
마찬가지로 확인할 값에 맞게 코드를 변경해줍니다.
fun checkIdExist(id: String): Boolean {
val db = this.readableDatabase
// 리턴받고자 하는 컬럼 값의 array
val projection = arrayOf(BaseColumns._ID)
//,LocalDatas.userData.COLUMN_NAME_ID, LocalDatas.userData.COLUMN_NAME_PASSWORD)
// WHERE "id" = id AND "password"=password 구문 적용하는 부분
val selection = "${LocalDatas.userData.COLUMN_NAME_ID} = ?"
val selectionArgs = arrayOf(id)
// 정렬조건 지정
// val sortOrder = "${FeedEntry.COLUMN_NAME_SUBTITLE} DESC"
val cursor = db.query(
LocalDatas.userData.TABLE_NAME, // 테이블
projection, // 리턴 받고자 하는 컬럼
selection, // where 조건
selectionArgs, // where 조건에 해당하는 값의 배열
null, // 그룹 조건
null, // having 조건
null // orderby 조건 지정
)
if(cursor.count>0){// 반환된 cursor 값이 존재
return true;
}else{//반환된 cursor 값이 없음
return false;
}
}
마지막으로 로그인 확인 함수입니다. id, password를 받아서 db값과 비교후 유저의 존재여부를 true/false로 반환합니다.
마찬가지로 확인할 값에 맞게 코드를 변경해줍니다.
fun logIn(id: String, password:String): Boolean {
val db = this.readableDatabase
// 리턴받고자 하는 컬럼 값의 array
val projection = arrayOf(BaseColumns._ID)
//,LocalDatas.userData.COLUMN_NAME_ID, LocalDatas.userData.COLUMN_NAME_PASSWORD)
// WHERE "id" = id AND "password"=password 구문 적용하는 부분
val selection = "${LocalDatas.userData.COLUMN_NAME_ID} = ? AND ${LocalDatas.userData.COLUMN_NAME_PASSWORD} = ?"
val selectionArgs = arrayOf(id,password)
// 정렬조건 지정
// val sortOrder = "${FeedEntry.COLUMN_NAME_SUBTITLE} DESC"
val cursor = db.query(
LocalDatas.userData.TABLE_NAME, // 테이블
projection, // 리턴 받고자 하는 컬럼
selection, // where 조건
selectionArgs, // where 조건에 해당하는 값의 배열
null, // 그룹 조건
null, // having 조건
null // orderby 조건 지정
)
if(cursor.count>0){// 반환된 cursor의 0번째 값이 null이면
return true;
}else{
return false;
}
}
이상으로 회원가입에 사용할 SQLite 모듈의 기능 작성이 끝났습니다.
액티비티 코드 작성
패키지 부분을 제외한 나머지 코드를 지우고
다음과 같이 스틱코드를 입력하면 됩니다. 오류가 뜨는 부분은 제일 위쪽부터 마우스를 올리고 alt+enter를 누르면 전부 사라집니다. RegisterActivity도 마찬가지로 작성해주시면 됩니다.
각 액티비티(회원가입,로그인)는 아까 정의해둔 LocalDB 클래스를 초기화하여 이용하게 됩니다.
//MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
binding = ActivityMainBinding.inflate(layoutInflater) // 뷰바인딩
val view = binding.root
setContentView(view)
localDB= LocalDB(this, DATABASE_NAME,null, DATABASE_VERSION) // SQLite 모듈 생성
binding.btnLogin.setOnClickListener { view-> // 로그인 버튼 클릭 리스너
val id = binding.editId.text.toString()
val passwd = binding.editPw.text.toString()
val exist = localDB.logIn(id,passwd) // 로그인 실행
if(exist){//로그인 성공
val intent =Intent(this,SecondActivity::class.java)
startActivity(intent)
}else{//실패
Toast.makeText(this@MainActivity, "아이디나 비밀번호가 틀렸습니다.", Toast.LENGTH_SHORT).show()
}
}
binding.btnRegister.setOnClickListener { view-> //회원가입화면으로 이동
val intent =Intent(this,RegisterActivity::class.java)
startActivity(intent)
}
}
각 코드에 대한 설명은 주석을 참고해주세요.
액티비티의 작성까지 끝났다면 기본적인 회원가입을 시험해봅니다. 문제없이 동작하는것을 확인하실수 있습니다.
'안드로이드 코틀린' 카테고리의 다른 글
[Kotlin][Android] retrofit2 이용한 HTTP 통신 (0) | 2021.03.15 |
---|---|
[Kotlin][Android] 당겨서 새로고침 기능 만들기 (0) | 2021.03.10 |
[Kotlin][Android] 안드로이드 스피너 2탄 스피너 커스텀하기 (0) | 2021.02.21 |
[Kotlin][Android]안드로이드 스피너 만들기 (0) | 2021.02.13 |
[Kotlin][Android] 안드로이드 회원가입/로그인 (2) | 2021.02.01 |