# 결과물 미리보기
파이어베이스 스토리지에 이미지를 업로드시키고, 리얼타임 데이터베이스에서 다시 가져와서 리사이클러뷰에 뿌려준다. 이미지 업로드시 프로그레스바가 돌게 했으며, 다른 뷰(버튼)들이 터치되지 않도록 막는 기능까지 구현했다.
# 구현 요구 사항
- 이미지파일을 파이어베이스에 스토리지에 업로드하기
- 파이어베이스 스토리지에 있는 이미지파일 url 가져오기
- 콜백함수 이용하기
- 프레그레스바 추가 및 배경 터치 막기
# 이미지 파일 업로드하기
기존에 만들었던 코드를 조금 변형해야 한다. 먼저 갤러리부터 받아온 이미지 uri가 존재하는지 확인하고, 존재한다면 포토를 업로드해주도록 한다. 이미지 uri가 없다면 빈 이미지는 빼고 업로드 해야한다.
private fun initSubmitItemButton() {
submitButton.setOnClickListener {
val titleEditText = findViewById<EditText>(R.id.addTitleEditText).text.toString()
val priceEditText = findViewById<EditText>(R.id.addPrcieEditText).text.toString()
val uid = auth.uid.orEmpty()
if (titleEditText.isNotEmpty() && priceEditText.isNotEmpty()) {
// TODO
// 선택된 이미지 uri가 존재할 경우
// 이미지를 스토리지에 저장시킴
// 스토리지에 저장 시킨 후 다시 값을 받아와 모델에 uri값을 넣어 만들어 줘야함
showProgressBar()
if (imageURI != null) {
uploadPhoto(imageURI!!,
mSuccessHandler = { uri ->
uploadArticle(uid, titleEditText, priceEditText, uri)
hideProgressBar()
},
mErrorHandler = {
Toast.makeText(this, "게시글 업로드에 실패했습니다", Toast.LENGTH_SHORT).show()
}
)
} else {
// 이미지 uri가 존재하지 않는 경우
// 사진이 없는 게시글을 작성함
uploadArticle(uid, titleEditText, priceEditText, "")
hideProgressBar()
}
} else {
Toast.makeText(this, "제목과 가격을 입력해주세요", Toast.LENGTH_SHORT).show()
}
}
}
# 파이어베이스 스토리지에서 이미지 저장 및 가져오기 - 콜백함수를 이용하여
이미지 URI가 null이 아니라면, 현재 내 로컬이미지 파일을 파이어베이스에 업로드시키고, 업로드 파이어베이스(서버) 스토리지에서 해당 이미지의URL값을 가져온다. 그 URL을 이용해 모델 객체를 만들고, 글라이더는 해당 URL에서 이미지를 가져오게 될 것이다. 이 코드는 실행 순서가 중요하기 때문이 비동기(?)의 문제를 처리하기 위해서 콜백함수를 이용한다. uploadPhoto()함수는 성공핸들러와 에러핸들러를 콜백함수로써 넘겨준다.
private fun uploadPhoto(
imageURI: Uri,
mSuccessHandler: (String) -> Unit,
mErrorHandler: () -> Unit,
) {
val fileName = "${System.currentTimeMillis()}.png"
storage.reference.child("article/photo").child(fileName)
.putFile(imageURI)
.addOnCompleteListener {
if (it.isSuccessful) {
// 파일 업로드에 성공했기 때문에 파일을 다시 받아 오도록 해야함
storage.reference.child("article/photo").child(fileName).downloadUrl
.addOnSuccessListener { uri ->
mSuccessHandler(uri.toString())
}.addOnFailureListener {
mErrorHandler()
}
} else {
mErrorHandler()
}
}
}
## 파이어베이스 스토리지
파이어베이스 스토리지는 리얼타임데이터베이스와 사용방법이 매우 유사했다.
private val storage by lazy {
Firebase.storage
}
위와같이 전역객체를 만들어 주고 난후, 이 스토리지의 레퍼런스를 얻고 child를 통해서 경로를 잡아준다. 그리고 해당 경로의 지정한 파일명으로 putFile을 해주는데 여기서 imageURI는 현재 내 핸드폰상의 이미지의 URI가 된다. 그리고 해당 이벤트가 성공시, 다시 이미지파일의 URL을 받아온후, mSUccessHandler()콜백함수를 호출하여 인자로 넘겨줬던 함수가 호출 되면서, uploadArticle()이 최종적으로 실행되게 된다.
해당 과정을 공부하면서, 앞전에 겪엇던 프래그먼트가 바뀌면서 list가 클리어되는 것을 고쳐볼 수 있지 않을까 생각이 들었고, 이번 포스팅을 마치고 콜백함수로 해당 버그를 수정을 시도해볼 생각이다.
# 프레그레스바 - 로딩 바 추가하기
이미지가 서버에 저장되는 순간의 시간이 필요하기때문에 잠깐 멈추는데, 사용자는 이것을 인지 하지 못할 수 있기 때문에 프로그레스바를 추가하고, 프로그레스바가 돌때에는 뒷배경이 터치되지 않도록 해야 한다.
먼저 XML에 프로그레스바를 추가해준다.
// 프로그레스바 보이기
private fun showProgressBar() {
val pBar = findViewById<ProgressBar>(R.id.progressBar)
blockLayoutTouch()
pBar.isVisible = true
}
// 프로그레스바 숨기기
private fun hideProgressBar() {
val pBar = findViewById<ProgressBar>(R.id.progressBar)
clearBlockLayoutTouch()
pBar.isVisible = false
}
// 화면 터치 막기
private fun blockLayoutTouch() {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
}
// 화면 터치 풀기
private fun clearBlockLayoutTouch() {
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
}
# 마치며
어쩌면 비동기-동기처리의 필요성을 인지하고있는 지금 시점에서 콜백함수에 대해서 다시금 생각해보면서 해결책이 될 수 도 있다는 생각을 하게 됐다.
앱이 그래도 조금 있어보여서 개발하는 재미가 쏠쏠하다.