안드로이드 앱 개발을 하다보면 해당 기기에 있는 파일을 불러오고 싶을 때가 있다 예를 들면 사진이나 동영상 등 말이다 이번 글에서 이러한 기능을 구현하는 방법을 짧고 간단히 알아보겠다
우선 해당 기능을 구현하는 방법은 크게 이전에 사용하던 방법과 최근 방식 이렇게 두 가지로 나눌 수 있다 일단은 이전 방식부터 차근 차근 알아보자
구현 방법
아래 코드들은 두 방법에서 공통으로 사용 될 코드이다
activity_main.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?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:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/open_file_button"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:textSize="18sp"
android:text="파일 열기"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</androidx.constraintlayout.widget.ConstraintLayout>
간단히 로직을 보여줄 버튼 하나로 구성하였으니 실제로 사용할 때는 상황에 맞게 구성하길 바란다
getFileNameFromUri
1
2
3
4
5
6
7
8
9
10
11
12
13
private fun getFileNameFromUri(context: Context, uri: Uri): String? {
var fileName: String? = null
val cursor = context.contentResolver.query(uri, null, null, null, null)
cursor?.use {
val nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
if (nameIndex != -1 && cursor.moveToFirst()) {
fileName = cursor.getString(nameIndex)
}
}
return fileName
}
Uri를 통해 파일 이름을 가져오는 함수이다 파일을 잘 불러왔나 확인 용으로 사용한 함수이다
viewBinding
중요한 건 아니지만 해당 코드에서 findViewById 대신 viewBinding을 이용했다
startActivityForResult를 통한 구현
먼저 소개할 방법은 startActivityForResult를 이용한 방법으로 해당 방법은 deprecated된 방법이라 추천하진 않지만 필요한 사람도 있을 거 같아 소개한다
1. REQUESTCODE 선언
1
2
3
companion object {
const val REQUESTCODE = 200
}
우선 startActivityForResult를 통해 파일을 가져오기 위해서는 필수는 아니지만 companion object로 REQUESTCODE를 선언하는게 좋다
2. startActivityForResult 호출
그 다음으로는 버튼을 클릭 했을 때 파일을 가져오게 만들 것이니 setOnClickListener 안에
1
2
3
4
5
binding.openFileButton.setOnClickListener {
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "*/*"
startActivityForResult(intent, REQUESTCODE)
}
이런 식으로 Intent(Intent.ACTION_GET_CONTENT) 객체에 type을 설정한 뒤 아까 위에 설정한 REQUESTCODE와 함께 tartActivityForResult에 넣어주면 된다
3. onActivityResult 재정의
그 뒤 onActivityResult를 override 해주는 것이 필요한데 이 부분은 쉽게 말하자면 파일을 선택한 이후 행동할 로직을 작성하는 부분이다
1
2
3
4
5
6
7
8
9
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUESTCODE && resultCode == Activity.RESULT_OK) {
data?.data?.let { uri ->
val fileName = getFileNameFromUri(this, uri)
Toast.makeText(this, fileName, Toast.LENGTH_SHORT).show()
}
}
}
우선 조건문으로 onActivityResult에 requestCode와 우리가 startActivityForResult를 통해 넘겨준 REQUESTCODE 값이 일치하는지 resultCode가 RESULT_OK인지 검증하고
만약 둘다 만족한다면 성공적으로 파일을 선택한 값이 들어온 경우이다 우린 이제 여기에 로직을 작성해주면 되는데 난 예시로 보여줘야 하니 getFileNameFromUri를 통해 파일 이름을 가져와서
Toast 메시지로 출력해보겠다
그러면 이렇게 잘 출력되는 걸 볼 수 있다
registerForActivityResult를 통한 구현
다음으로 소개할 방법은 registerForActivityResult를 이용한 방법으로 더 간단하게 가능하며 해당 방법은 현재 기준으로 권장되는 방법이다
1. registerForActivityResult 선언
우선 registerForActivityResult를 통해 파일을 가져오기 위해서는 registerForActivityResult를 선언해야 한다 여기서 인자로 넣을 수 있는 ActivityResultContracts 클래스의 하위 타입은 다양하지만 startActivityForResult와 비슷하게 하기 위해 GetContent로 하겠다
참고로 GetContent는 사용자가 파일을 선택할 수 있게 할 때 쓰는 타입이다
1
2
3
4
5
6
7
private val openFileLauncher =
registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
if (uri != null) {
val fileName = getFileNameFromUri(this, uri)
Toast.makeText(this@MainActivity, fileName, Toast.LENGTH_SHORT).show()
}
}
다음으로 startActivityForResult에서 했던 것처럼 마찬가지로 조건문을 통해 Uri 값을 Null 체크한 뒤 getFileNameFromUri을 통해 파일 이름을 가져와서 Toast 메세지로 출력하게 한다
2. registerForActivityResult 실행
마찬가지로 버튼을 클릭 했을 때 파일을 가져오게 만들 것이니 setOnClickListener 안에
1
2
3
binding.openFileButton.setOnClickListener {
openFileLauncher.launch("*/*")
}
이런 식으로 openFileLauncher를 launch 해주면 되는데
그러면 마찬가지로 이렇게 잘 출력되는 걸 볼 수 있다
마치며
마치며 계속해서 등장하던 “/“ 같은 문자들은 MIME 타입이라고 부르며 자세한 설명은 여기를 참고하고 간단히는 어떤 파일 형식을 가져올지 지정하는 거라고 보면 된다 참고로 우리가 코드에서 사용한 “/“는 모든 형식에 파일을 뜻한다