✏️  일기장 앱을 내장 메모리가 아닌 sd카드의 mydiary 폴더에 저장되도록 작업. 단, SD카드에 mydiary가 없으면 kotlin 코드에서 자동 생성되게 함

 

xml 코드
<?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"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <DatePicker
        android:id="@+id/datePicker"
        android:datePickerMode="spinner"
        android:calendarViewShown="false"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <EditText
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:padding="20dp"
        android:background="#E7D9F6"
        android:layout_weight="1"
        android:lines="8"/>

    <Button
        android:id="@+id/btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:enabled="false"
        android:text="BUTTON" />

</LinearLayout>

 

 

MainActivity 코드
class MainActivity : AppCompatActivity() {
    lateinit var datePicker: DatePicker
    lateinit var editText: EditText
    lateinit var btn: Button
    lateinit var fileName: String 

    /* 추가된 코드 */
    lateinit var savePath: String // 저장 경로
    var isFlag = false // 디렉토리 생성을 저장

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

        title = "간단 일기장"

        // 접근 권한 요청
        ActivityCompat.requestPermissions(this,
            arrayOf(android.Manifest.permission.WRITE_EXTERNAL_STORAGE),
            Context.MODE_PRIVATE)

        datePicker = findViewById(R.id.datePicker)
        editText = findViewById(R.id.editText)
        btn = findViewById(R.id.btn)

        val calendar = Calendar.getInstance()
        val calendarYear = calendar.get(Calendar.YEAR)
        val calendarMonth = calendar.get(Calendar.MONTH)
        val calendarDay = calendar.get(Calendar.DAY_OF_MONTH)
        
        // 외부 경로 지정
        savePath = Environment.getExternalStorageDirectory().absolutePath + "/MyDiary"

        fileName = "${calendarYear}_${calendarMonth + 1}_${calendarDay}.txt"
        val str = readDiary(fileName) // 날짜에 해당하는 일기 파일을 읽기
        editText.setText(str) // 에디트텍스트에 일기 내용을 출력
        btn.isEnabled = true // 버튼 활성화

        datePicker.init(
            calendarYear,
            calendarMonth,
            calendarDay,
            DatePicker.OnDateChangedListener() { datePicker: DatePicker, year: Int, month: Int, day: Int ->
                makeDir() // 새로운 디렉토리 생성 함수 ( 있으면 다시 생성 x )
                
                fileName = "${year}_${month + 1}_${day}.txt"
                val string = readDiary(fileName) // 날짜에 해당하는 파일을 읽기
                editText.setText(string) // 에디트텍스트에 일기 내용을 출력
                Toast.makeText(applicationContext, fileName, Toast.LENGTH_SHORT).show()
                btn.isEnabled = true // 버튼 활성화
            })


        btn.setOnClickListener {
            val outputStream = FileOutputStream("$savePath/$fileName") // 지정 경로 이름으로 저장
            val string = editText.text.toString() // 입력값 저장
            outputStream.write(string.toByteArray())
            outputStream.close()
            Toast.makeText(applicationContext, "${fileName} 이 저장됨", Toast.LENGTH_SHORT).show()
        }
    }


    private fun readDiary(fileName: String): String? {
        var diaryStr: String? = null
        val inputStream: FileInputStream

        try {
            inputStream = FileInputStream("${savePath}/${fileName}") // 지정 파일 불러오기
            val txt = ByteArray(inputStream.available())
            inputStream.read(txt)
            inputStream.close()
            diaryStr = txt.toString(Charsets.UTF_8).trim()
            btn.text = "수정하기"
        } catch (e: IOException) {
            editText.hint = "일기 없음"
            btn.text = "새로 저장"
        }
        return diaryStr;
    }

    private fun makeDir() {
        if (!isFlag) { // 외부에 디렉토리가 생성되어 있지 않으면 생성
            // 저장 경로 생성
            val myDir = File(savePath)
            myDir.mkdir()
            isFlag = true
        }
    }

}

 

 

 

 

 

 

[ 내용 참고 : IT 학원 강의 ]


1.  activity_main.xml

데이터 피커, 에디트텍스트, 버튼을 1개씩 생성

<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"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <DatePicker
        android:id="@+id/datePicker"
        android:datePickerMode="spinner"
        android:calendarViewShown="false"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <EditText
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:padding="10dp"
        android:background="#F0FFE6"
        android:layout_weight="1"
        android:lines="8"/>

    <Button
        android:id="@+id/btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:enabled="false"
        android:text="BUTTON" />

</LinearLayout>

 

android:lines="8"

 

    ✓  에디트텍스트를 8행으로 설정

 

android:enabled="false"


    ✓  초기에 버튼을 disable 되게 하고, java 코드에서 enable 되게 함

 


 

2.  Kotlin 코드 작성 및 수정

  • activity_main의 3개 위젯에 대응할 위젯 변수 3개를 선언
  • 파일 이름을 저장할 문자열 변수 1개를 선언. 파일 이름을 '연_월_일.txt'로 지정
  • 위젯 변수에 activity_main.xml의 위젯을 대입
  • 데이트피커를 설정
  • Calendar 클래스를 이용하여 현재 날짜의 년, 월, 일을 구한 후 데이트피커를 초기화 ➡️ 데이트피커의 날짜가 변경되면 변경된 날짜에 해당하는 일기 파일(연_월_일.txt)의 내용을 에디트텍스트로 보여줌
  • 현재 날짜의 파일(연_월_일.txt)을 읽어 일기의 내용을 반환하는 readDiary() 메서드 완성
class MainActivity : AppCompatActivity() {
    lateinit var datePicker: DatePicker
    lateinit var editText: EditText
    lateinit var btn: Button
    lateinit var fileName: String // 파일 이름 저장

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

        title = "간단 일기장"

        datePicker = findViewById(R.id.datePicker)
        editText = findViewById(R.id.editText)
        btn = findViewById(R.id.btn)

        val calendar = Calendar.getInstance()
        val calendarYear = calendar.get(Calendar.YEAR)
        val calendarMonth = calendar.get(Calendar.MONTH)
        val calendarDay = calendar.get(Calendar.DAY_OF_MONTH)

        fileName = "${calendarYear}_${calendarMonth + 1}_${calendarDay}.txt"
        val str = readDiary(fileName) // 날짜에 해당하는 일기 파일을 읽기
        editText.setText(str) // 에디트텍스트에 일기 내용을 출력
        btn.isEnabled = true // 버튼 활성화


        datePicker.init(
            calendarYear,
            calendarMonth,
            calendarDay,
            DatePicker.OnDateChangedListener() { datePicker: DatePicker, year: Int, month: Int, day: Int ->
                fileName = "${year}_${month + 1}_${day}.txt"
                val string = readDiary(fileName) // 날짜에 해당하는 파일을 읽기
                editText.setText(string) // 에디트텍스트에 일기 내용을 출력
                Toast.makeText(applicationContext, fileName, Toast.LENGTH_SHORT).show()
                btn.isEnabled = true // 버튼 활성화
            })

        btn.setOnClickListener {
            val outputStream = openFileOutput(fileName, Context.MODE_PRIVATE)
            val string = editText.text.toString()
            outputStream.write(string.toByteArray())
            outputStream.close()
            Toast.makeText(applicationContext, "${fileName} 이 저장됨", Toast.LENGTH_SHORT).show()
        }
    }

    private fun readDiary(fileName: String): String? {
        var diaryStr: String? = null
        val inputStream: FileInputStream

        try {
            inputStream = openFileInput(fileName)
            val txt = ByteArray(inputStream.available())
            inputStream.read(txt)
            inputStream.close()
            diaryStr = txt.toString(Charsets.UTF_8).trim()
            btn.text = "수정하기"
        } catch (e: IOException) {
            editText.hint = "일기 없음"
            btn.text = "새로 저장"
        }
        return diaryStr;
    }

}

 

inputStream = openFileInput(fileName)


    ✓ 일기 파일을 열어 입력 파일 스트림에 저장. 파일이 없으면 예외가 발생해서 catch 구문이 실행

 


 

3.   프로젝트 실행 및 결과 확인

선택된 날짜에 쓴 일기가 있다면 일기 내용이 보이고 버튼이 <수정하기>로 바뀜
선택된 날짜에 일기가 없다면 에디트텍스트에 '일기 없음' 힌트가 보이고 버튼이 <새로 저장>으로 바뀜

 

 

 


4. 파일 확인

AVD가 켜진 상태에서 Divice File Explorer 실행
View  ▶️  Tool Windows  ▶️  Divice File Explorer

 

 

 

 

 

[ 내용 참고 : IT 학원 강의 ]

+ Recent posts