앱에서 이미지를 가져와 게시글을 업로드할 때 registerForActivityResult()와 Firebase Storage를 사용하였다.
네비게이션 메뉴바에서 카메라 메뉴탭을 누르면 갤러리로 이동하는 과정에서 registerForActivityResult() 메서드를 사용했다.
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
...
우선 앱이 자신의 핸드폰 갤러리에 접근하는 것을 허용하는지 사용자에게 묻기 위해 AndroidManifest.xml 파일에 READ_EXTERNAL_STORAGE
권한을 추가한다.
class MainActivity : AppCompatActivity() {
...
//갤러리 앱으로 이동하는 launcher 등록
private var launcher = registerForActivityResult(ActivityResultContracts.GetContent()) {
it-> changeFragment(GalleryFragment(it))
}
override fun onCreate(savedInstanceState: Bundle?) {
...
initNavigationBar() //네이게이션 바의 각 메뉴 탭을 눌렀을 때 화면이 전환되도록 하는 함수.
//앱에서 앨범에 접근을 허용할지 선택하는 메시지, 한 번 허용하면 앱이 설치돼 있는 동안 다시 뜨지 않음.
ActivityCompat.requestPermissions(this@MainActivity,
arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE), 1)
}
fun initNavigationBar() {
binding.myNavigation.run {
setOnNavigationItemSelectedListener {
when (it.itemId) {
...
R.id.photoItem -> {
//앱이 갤러리에 접근햐는 것을 허용했을 경우
if (ContextCompat.checkSelfPermission(this@MainActivity.applicationContext, android.Manifest.permission.READ_EXTERNAL_STORAGE)== PackageManager.PERMISSION_GRANTED) {
launcher.launch("image/*") //갤러리로 이동하는 런처 실행.
} else { //앱이 갤러리에 접근햐는 것을 허용하지 않았을 경우
Toast.makeText(this@MainActivity,
"갤러리 접근 권한이 거부돼 있습니다. 설정에서 접근을 허용해 주세요.",
Toast.LENGTH_SHORT).show()
}
}
...
true
}
selectedItemId = R.id.homeItem
}
}
}
registerForActivityResult() 메서드를 호출해 갤러리 앱으로 이동하는 launcher를 등록한다.
Contract는 ActivityResultContracts
에 이미 정의돼 있는 GetContent()
를 사용하면 갤러리로 이동할 수 있다. 갤러리 앱에서 다시 돌아올 때 전달받는 데이터(it)는 사용자가 선택한 이미지의 uri
이다. 이 uri와 함께 GalleryFragment로 이동한다.
ActivityCompat.requestPermissions()
메서드를 호출해 처음 MainActivity 화면에 들어온 사용자에게 앨범에 접근해도 될지 권한을 요청하는 READ_EXTERNAL_STORAGE
메세지를 보낸다.
메뉴바에서 카메라탭을 클릭했을 때 갤러리 앱으로 이동하는 launcher를 실행한다.
ContextCompat.checkSelfPermission()
으로 사용자가 권한을 허용했는지 확인한 후 권한을 허용했다면 launcher를 실행한다.
dependencies {
...
implementation 'com.google.firebase:firebase-storage-ktx'
}
Firebase Storage를 사용하기 위해 build.gradle(Module) 파일에 라이브러리를 추가한다.
class GalleryFragment(uri: Uri): Fragment() {
private lateinit var mBinding: FragmentGalleryBinding
private var uri: Uri? = uri
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
mBinding = FragmentGalleryBinding.inflate(inflater, container, false)
mBinding.postPhotoIV.setImageURI(uri) //갤러리에서 선택한 이미지를 해당 이미지뷰에서 보여줌.
//게시글 업로드 버튼을 누르면 Firebase Storage에 이미지를 업로드 하는 함수 실행.
mBinding.postButton.setOnClickListener {
uploadImageTOFirebase(uri!!)
}
return mBinding.root
}
//Firebase Storage에 이미지를 업로드 하는 함수.
fun uploadImageTOFirebase(uri: Uri) {
var storage: FirebaseStorage? = FirebaseStorage.getInstance() //FirebaseStorage 인스턴스 생성
//파일 이름 생성.
var fileName = "IMAGE_${SimpleDateFormat("yyyymmdd_HHmmss").format(Date())}_.png"
//파일 업로드, 다운로드, 삭제, 메타데이터 가져오기 또는 업데이트를 하기 위해 참조를 생성.
//참조는 클라우드 파일을 가리키는 포인터라고 할 수 있음.
var imagesRef = storage!!.reference.child("images/").child(fileName) //기본 참조 위치/images/${fileName}
//이미지 파일 업로드
imagesRef.putFile(uri!!).addOnSuccessListener {
Toast.makeText(activity, getString(R.string.upload_success), Toast.LENGTH_SHORT).show()
}.addOnFailureListener {
println(it)
Toast.makeText(activity, getString(R.string.upload_fail), Toast.LENGTH_SHORT).show()
}
}
}
mBinding.postPhotoIV.setImageURI(uri)
: 이미지 뷰에 사용자가 선택한 이미지를 넣어준다. mBinding.postButton.setOnClickListener { uploadImageTOFirebase(uri!!) }
: 게시글 업로드 버튼을 누르면 Firebase Storage에 이미지를 업로드한다. IMAGE_날짜_시간_.png
형식으로 지정한다. imagesRef
로 스토리지에 이미지를 저장할 경로를 지정한다. putFile()
메서드를 호출해 이미지를 imagesRef 경로에 저장한다. [출처] Charlezz-액티비티 결과 처리하기 (Good bye… startActivityForResult, onActivityResult)
[출처] 랴파파의 콜렉션-안드로이드 코틀린:Firebase Storage 이미지 저장
[출처] 파이어베이스 스토리지 공식 문서