Android Projects

[My Note] 비밀번호 기능 구현하기

IT Knowledge Share 2022. 4. 25. 19:22
반응형

마이노트에서 사용될 비밀번호 기능을 구현해봅니다.

비밀번호를 저장하고 수정하여, 노트를 나중에 노트를 열 수 있도록 구현할 예정입니다.

 

기존에 그린 UI 내에서 NumberPicker, Button 등의 뷰 콤포넌트(View Component)를 액티비티에 연결하여 실제 사용할 수 있도록 MainActivity에서 작업합니다.

 

아래와 같이 액티비티 내에서 연결할 NumberPicker를 선언해줍니다. lazy init을 통해서 각 NumberPicker들을 초기화해주도록 합니다. 초기화를 위해 apply를 함수를 사용했는데, 해당 함수는 this로 NumberPicker에 접근할 수 있습니다.

class MainActivity : AppCompatActivity() {

    private val numberPicker1 : NumberPicker by lazy {
        findViewById<NumberPicker>(R.id.numberPicker1)
            .apply {
                minValue = 0
                maxValue = 9
            }
    }
    
    ...이하 생략
}

 

by lazy로 초기화하는 이유는 메인 액티비티 생성 시 아직 뷰가 그려지지 않았기 때문입니다. onCreate 함수에서 뷰가 완성되고, onCreate 이후에 뷰에 대한 접근이 가능합니다.  결론적으로, numberPicker 1~ 3을 직접적으로 사용하진 않지만, lazy init의 apply 함수 초기값에 접근하기 위해, 뷰가 그려지는 onCreate 내에서 사용된 것입니다.

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.main_activity)
    
    numberPicker1
    numberPicker2
    numberPicker3
}

 

추가적으로, 메인 액티비티 클래스 내에서 버튼을 선언해주도록 합니다.

private val openButton: AppCompatButton by lazy {
    findViewById<AppCompatButton>(R.id.openButton)
}

private val changePasswordButton: AppCompatButton by lazy {
    findViewById<AppCompatButton>(R.id.changePassword)
}

onCreate 함수 내에서 버튼에 대한 동작을 정의합니다. 오픈 버튼을 클릭 시, 기존에 저장된 비밀번호 값을 가져와서 현재 값과 비교해야 합니다.

비밀번호는 저장하는 두 가지 방법은 다음과 같습니다.

1. Local DB에 저장

2. 파일에 직접 기록 (SharedPreference)

 

SharedPreference에 저장된 비밀번호를 가져올 수 있도록 코딩해줍니다. SharedPreference는 맵과 같이 키, 밸류 형식으로 저장되며, 인자로는 Name과 Mode가 있는데, Name은 말그대로 SharedPreference의 명칭입니다. Mode의 경우, 다른 앱과 비밀번호가 공유되지 않도록, MODE_PRIVATE으로 지정합니다.

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.main_activity)

    numberPicker1
    numberPicker2
    numberPicker3

    openButton.setOnClickListener {
        getSharedPreferences("password", MODE_PRIVATE)

    }
}

 이제는 SharedPreference에 저장된 값을 실제 입력한 값과 비교해야 합니다. 비밀번호를 검사할 수 있도록 코딩해줍니다. SharedPreference의 값은 passwordPreference 변수에 할당해줍니다. 그리고 passwordFromUser 값은 $기호를 사용하여 나란히 입력된 값을 가져올 수 있도록 합니다.

 

passwordPreference의 값을 가져올 때 getString 메소드를 사용했으며, 키와 밸류 값으로 저장되는 ShardPreference의 Key Name을 "password"로 지정합니다. "000"은 초기값입니다. equals 메소드를 통해 값을 비교합니다.

 

if 문을 사용하여, 패스워드 일치/불일치 조건을 만든 후, 패스워드가 일치할 경우, startActivity()를 통해 노트 작성 액티비티를 실행할 수 있도록 합니다.

 

패스워드가 일치하지 않는 경우, AlertDialog.Builder 패턴을 사용하여 알림 메시지를 띄우게 합니다.

AlertDialog.Builder 패턴에서 this는 액티비티 자신을 의미합니다.

 

해당 패턴에서 정의될 수 있는 파라미터 중에는 Positive 또는 NegativeButton을 정의하여, 성공/실패에 따른 버튼의 텍스트와 그에 따른 람다식을 만들어줄 수 있습니다. 특히 아래 사진과 같이, Positive 또는 NegativeButton의 람다식은 onClickListener의 onClick 안에 두 개의 인자를 받고 있기 때문에, 명시적으로 정의해줘야 합니다.

setPositiveButton("확인") {dialog, which -> }

위에서 보듯이, dialog, which 인자를 명시적으로 정의했으며, ->로 동작을 정의합니다.

정의할 동작이 없는 경우, setPositiveButton("확인") { _, _ -> } 처럼 작성하여 동작 생략을 표시해줍니다.

openButton.setOnClickListener {
    val passwordPreference = getSharedPreferences("password", MODE_PRIVATE)
    val passwordFromUser = "${numberPicker1.value}${numberPicker2.value}${numberPicker3.value}"

    //SharedPreference 및 PasswordFromUser의 값이 같은 경우
    if (passwordPreference.getString("password", "000").equals(passwordFromUser)) {
        // 패스워드 일치

        //노트 페이지 열기
        startActivity()
    } else {
        // 패스워드 불일치
        AlertDialog.Builder(this)
            .setTitle("실패")
            .setMessage("비밀번호가 잘못되었습니다.")
            .setPositiveButton("확인") { _, _ -> }
            .create()
            .show()

    }
}

이후에는 비밀번호 변경에 대한 동작을 정의합니다. 비밀번호를 변경 시 다른 작업을 할 수 없도록 예외 처리하는 부분을 잊지마시기 바랍니다! 

changePasswordButton.setOnClickListener {
    
}

비밀번호 변경에 대한 예외처리를 위해, 전역변수로 changePasswordMode를 선언합니다.

 private var changePasswordMode = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main_activity)

        numberPicker1
        numberPicker2
        numberPicker3
        
        ... 이하 생략
        
}

오픈 버튼에 changePasswordMode가 true일 경우를 선언해줍니다. 전역변수의 기본 값은 false인데, true일 경우, 변경 중에 있다는 토스트 메시지를 띄운 후, setOnClickListener 람다 함수를 리턴하도록 합니다. @setOnClickListener 이렇게 명시를 해줘야만, onCreate 함수를 리턴하는 것인지, setOnClickListener 람다 함수를 리턴하는 것인지 인식할 수 있습니다. 그리고, changePasswordButton.setBackgroundColor(Color.GREEN)를 통해, 변경 성공 시 버튼색을 녹색으로 바꾸도록 합니다.

openButton.setOnClickListener {

    if (changePasswordMode) {
        Toast.makeText(this, "비밀번호 변경 중에 있습니다.", Toast.LENGTH_SHORT).show()
        return@setOnClickListener
    }
}

이제 changePasswordButton 동작을 완성해줍니다. 비밀번호 변경 시, changePasswordMode 상태라면 번호를 저장하고, 아니라면 비밀번호 변경모드를 활성화시켜줍니다. else 문에서 패스워드 값이 같은 경우, changePasswordMode를 true로 바꾸고, 토스트 메시지를 띄워주었습니다.

 changePasswordButton.setOnClickListener {
    if (changePasswordMode){
        //번호 변경 후 저장 기능

    } else {
        //비밀번호 변경 모드 활성. 비밀번호 일치/불일치 체크
        val passwordPreference = getSharedPreferences("password", MODE_PRIVATE)
        val passwordFromUser = "${numberPicker1.value}${numberPicker2.value}${numberPicker3.value}"

        //SharedPreference 및 PasswordFromUser의 값이 같은 경우
        if (passwordPreference.getString("password", "000").equals(passwordFromUser)) {
        
            changePasswordMode = true
            Toast.makeText(this, "변경할 패스워드를 입력해주시기 바랍니다.", Toast.LENGTH_SHORT).show()
            changePasswordButton.setBackgroundColor(Color.GREEN)
            
        } else {
            // 패스워드 불일치
            AlertDialog.Builder(this)
                .setTitle("실패")
                .setMessage("비밀번호가 잘못되었습니다.")
                .setPositiveButton("확인") { _, _ -> }
                .create()
                .show()

        }
    }
}
반응형

비밀번호 변경 버튼 클릭 시, 번호를 변경하고 저장하는 if 문을 완성해줍니다. 아래와 같이, 과거에는 editor를 정의하여, 동작을 완성해줄 수 있었습니다. editor 정의 후 필요한 메소드를 사용해준 예시입니다.

changePasswordButton.setOnClickListener {
    if (changePasswordMode){
        //번호 변경 후 저장 기능
        
        val passwordPreference = getSharedPreferences("password", MODE_PRIVATE)
        val editor = passwordPreference.edit()
        
        editor.putString()
        editor.commit()
        
        .. 등등
        
    }
}

이제는 코틀린 KTX (코틀린 익스텐션) 기능을 이용하여, 아래 사진과 같이 미리 정의된 editor 함수를 쉽게 불러와서 사용할 수 있습니다.

KTX로 이미 정의된 editor 람다 함수를 통해 동작을 완성하도록 합니다.

아래 사진과 같이, SharedPreferences.Editor로 this로 들어와 있어 쉽게 작업이 가능합니다.

아래와 같이 비밀번호 변경 버튼의 changePasswordMode 부분을 완성해줍니다. putString을 통해, 키와 값을 넣어주는데, "password"라는 명칭의 키에 매칭되는 값으로는 현재 값(passowordFromUser)을 넣어주면 됩니다.

 

특히, 저장을 위해서는 commit() 또는 apply() 메소드를 사용하게 됩니다.

commit()은 현재까지의 작업이 다 저장되기 전까지 UI를 멈추고 기다리지만, apply()는 바로 다음 작업을 실행할 수 있도록 비동기적인 저장을 하게 됩니다. 코틀린 KTX에서 이미 정의된 editor는 commit : Boolean = false로 되어 있기에, 해당 논리값을 true 바꿔주면 됩니다. 그게 아니라면 그냥 passwordPreference.edit {  } 안에 commit() 메소드를 선언하면 됩니다.

 

그리고 변경 모드는 false로 바꾼 후, 색상은 검정색이 될 수 있도록 코딩합니다.

changePasswordButton.setOnClickListener {
    if (changePasswordMode){
       //번호 변경 후 저장 기능
       val passwordPreference = getSharedPreferences("password", MODE_PRIVATE)
         passwordPreference.edit(true){
           val passwordFromUser = "${numberPicker1.value}${numberPicker2.value}${numberPicker3.value}"
           putString("password", passwordFromUser)
           
           changePasswordMode = false
           changePasswordButton.setBackgroundColor(Color.BLACK)
        }

    }
}
반응형