저번에 "파이어베이스 이미지URL을 통해 이미지 불러오기" 글을 쓴적이 있다
https://coding-juuwon2.tistory.com/212
파이어베이스 이미지URL을 통해 이미지 불러오기
내가 구현하고싶었던 부분은 내가 게시글을 작성하고 업로드 버튼을 누르면, 게시글을 작성할때 첨부했던 이미지가 프레그먼트에 있는 리사이클러뷰에도 똑같이 적용되도록 구현하고 싶었다!!
coding-juuwon2.tistory.com
그때 쓴 게시글에 있는 내용과 비슷한 내용이다. (아니 거의 똑같은 내용이라고봐도 된다)
저번 게시글을 쓸때 다 이해했다고 생각했는데, 수정하는 코드를 짜려니깐 조금 버벅여서 기록해두려한다!
게시글을 수정할 수 있도록 구현하는중에, 수정버튼을 눌렀을때 텍스트는 다 리사이클러뷰에 반영되는데 이미지는 아직 반영되도록 해놓지 않아서
이미지를 수정하고 수정버튼을 눌렀을때, 리사이클러뷰에 수정된 이미지가 보이도록 해볼것이다
[수정전 코드] - 수정된 텍스트만 적용, 수정된 이미지는 적용되지 않음
수정 전 코드인데 수정된 텍스트만 적용되고, 수정된 이미지는 리사이클러뷰에 반영되지 않는 코드였다
class RecipeEditActivity : AppCompatActivity() {
// key값 선언
private lateinit var key: String
private lateinit var binding: ActivityRecipeEditBinding
private val TAG = RecipeEditActivity::class.java.simpleName
// uid 가져오기위해 초기화
private lateinit var writeUid: String
val storage = Firebase.storage
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_recipe_edit)
// BoardInsideActivity에서 보낸 key값 받아오기
key = intent.getStringExtra("key1").toString()
// 게시글에서 쓴 데이터(글들) 가져와서 레시피수정 레이아웃에 표현하기
getEditBoardData(key)
// 게시글에서 쓴 이미지 가져와서 레이아웃에 표현하기
getEditImageData(key)
// editbutton버튼 눌렀을때
binding.recipeUploadbutton1.setOnClickListener {
// 수정되는 함수 실행
editBoardData(key)
}
// imageArea 이미지 눌렀을때
binding.recipeimageUpload1.setOnClickListener {
// 갤러리로 이동
val gallery = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.INTERNAL_CONTENT_URI)
startActivityForResult(gallery, 100)
}
}
// board데이터 받아오는 함수 (게시글에서 쓴 데이터 가져와서 수정 레아이웃에 표현하기)
private fun getEditBoardData(key: String) {
// 데이터 가져오기
val postListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
// try문에서 에러발생하면 catch문 실행
try {
//데이터 받아오기
val dataModel = dataSnapshot.getValue(RecipeBoardModel::class.java)
// 레이아읏과 연결
binding.recipenameET1.setText(dataModel!!.recipename) // recipenameET1 와 recipename 연결
binding.foodmeterialET1.setText(dataModel.foodmeterial) // foodmeterialET1 와 foodmeterial 연결
binding.recipewriteET1.setText(dataModel.recipe) // recipewriteET1 와 recipe 연결
binding.recipeTipET1.setText(dataModel.recipetip) // recipeTipET1 와 recipetip 연결
// uid가져옴(글쓴사람의 uid)
writeUid = dataModel.uid
} catch (e: Exception) {
Log.d(TAG, "수정완료")
}
}
override fun onCancelled(databaseError: DatabaseError) {
// Getting Post failed, log a message
Log.w(TAG, "loadPost:onCancelled", databaseError.toException())
}
}
// board안에있는 key값을 가져오기
FBRef.recipeboardRef.child(key).addValueEventListener(postListener)
}
// 이미지 다운로드 함수 (게시글에서 쓴 이미지 가져와서 레이아웃에 표현하기)
private fun getEditImageData(key: String) {
// 이미지 다운로드
// Reference to an image file in Cloud Storage
val storageReference = Firebase.storage.reference.child(key + ".png")
// ImageView in your Activity
val imageViewFromFB = binding.recipeimageUpload1
storageReference.downloadUrl.addOnCompleteListener(OnCompleteListener { task ->
// 이미지 업로드 성공
if (task.isSuccessful) {
// Glide를 사용하여 task에서 이미지 직접 다운로드
Glide.with(this)
.load(task.result)
.into(imageViewFromFB)
// 이미지 업로드 실패
} else {
}
})
}
// 수정버튼 눌렀을때 수정(다시 업로드)되는 함수
private fun editBoardData(key : String){
// 데이터 집어넣기
FBRef.recipeboardRef
.child(key)
.setValue(RecipeBoardModel(binding.recipenameET1.text.toString(), // 내가 작성한 recipenameET1값 집어넣음
binding.foodmeterialET1.text.toString(), // 내가 작성한 foodmeterialET1값 집어넣음
binding.recipewriteET1.text.toString(), // 내가 작성한 recipewriteET1값 집어넣음
binding.recipeTipET1.text.toString(), // 내가 작성한 recipeTipET1값 집어넣음
writeUid,
FBAuth.getTime2() )
)
// 이미지 업로드
imageUpload(key)
Toast.makeText(this, "수정완료", Toast.LENGTH_SHORT).show()
finish() // 엑티비티 종료
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
// 갤러리에서 데이터 받아오기
if(resultCode == RESULT_OK && requestCode == 100){
// 받아온 데이터를 레이아웃에 표시(갤러리 데이터가 imageArea에 표시)
binding.recipeimageUpload1.setImageURI(data?.data)
}
}
// 이미지 업로드 함수
private fun imageUpload(key :String){
val storageRef = storage.reference
val mountainsRef = storageRef.child(key + ".png")
val imageView = binding.recipeimageUpload1
imageView.isDrawingCacheEnabled = true
imageView.buildDrawingCache()
val bitmap = (imageView.drawable as BitmapDrawable).bitmap
val baos = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos)
val data = baos.toByteArray()
var uploadTask = mountainsRef.putBytes(data)
uploadTask.addOnFailureListener {
}.addOnSuccessListener { taskSnapshot ->
}
}
}
[수정 후 코드]
일단 파이어베이스 리얼타임데이터베이스에 수정된 imageUrl이 들어가야되는데, 수정전코드에서는 imageUrl에 아무값도 들어가지 않았다
그래서 수정버튼을 눌렀을때 다시 파이어베이스에 업로드되는 함수인 editBoardData()함수에
imageUrl = String 이라고 파라미터를 추가해준뒤, 파이어베이스에 imageUrl 데이터를 집어넣어준다
수정 전 코드에서는 이 함수에서 이미지를 업로드하도록 imageUpload()함수를 추가해줬는데 여기서는 삭제해준다
그리고 이미지를 업로드하는 함수인 imageUpload()함수에
이미지 업로드에 성공했다면, downloadUrl을 사용해서 파이어베이스에 업로드된 이미지의 url을 가져와서
editBoardData함수에 생성된 key값과 imageUrl을 넣어준다
마지막으로 수정버튼을 눌렀을때, imageUpload함수에 key값을 넣어서 실행되도록해준다
(원래는 수정버튼을 눌렀을때 editBoardData함수가 실행되도록 했었는데 그것은 삭제해준다
imageUpload함수 안에 이미 editBoardData함수를 넣어줬기 때문에 , imageUpload함수를 실행하면 editBoardData함수도 저절로 실행되기 때문이다)
- 나는 이부분에서 어떤 함수를 실행해줘야될지 몰라서 헤맸었다...
수정한 전체 코드이다
class RecipeEditActivity : AppCompatActivity() {
// key값 선언
private lateinit var key: String
private lateinit var binding: ActivityRecipeEditBinding
private val TAG = RecipeEditActivity::class.java.simpleName
// uid 가져오기위해 초기화
private lateinit var writeUid: String
val storage = Firebase.storage
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_recipe_edit)
// BoardInsideActivity에서 보낸 key값 받아오기
key = intent.getStringExtra("key1").toString()
// 게시글에서 쓴 데이터(글들) 가져와서 레시피수정 레이아웃에 표현하기
getEditBoardData(key)
// 게시글에서 쓴 이미지 가져와서 레이아웃수정 레이아웃에 표현하기
getEditImageData(key)
// editbutton버튼 눌렀을때
binding.recipeUploadbutton1.setOnClickListener {
// // 수정되는 함수 실행 (삭제해주기)
// editBoardData(key)
imageUpload(key)
}
// imageArea 이미지 눌렀을때
binding.recipeimageUpload1.setOnClickListener {
// 갤러리로 이동
val gallery = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.INTERNAL_CONTENT_URI)
startActivityForResult(gallery, 100)
}
}
// board데이터 받아오는 함수 (게시글에서 쓴 데이터 가져와서 수정 레아이웃에 표현하기)
private fun getEditBoardData(key: String) {
// 데이터 가져오기
val postListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
// try문에서 에러발생하면 catch문 실행
try {
//데이터 받아오기
val dataModel = dataSnapshot.getValue(RecipeBoardModel::class.java)
// 레이아읏과 연결
binding.recipenameET1.setText(dataModel!!.recipename) // recipenameET1 와 recipename 연결
binding.foodmeterialET1.setText(dataModel.foodmeterial) // foodmeterialET1 와 foodmeterial 연결
binding.recipewriteET1.setText(dataModel.recipe) // recipewriteET1 와 recipe 연결
binding.recipeTipET1.setText(dataModel.recipetip) // recipeTipET1 와 recipetip 연결
// uid가져옴(글쓴사람의 uid)
writeUid = dataModel.uid
} catch (e: Exception) {
Log.d(TAG, "수정완료")
}
}
override fun onCancelled(databaseError: DatabaseError) {
// Getting Post failed, log a message
Log.w(TAG, "loadPost:onCancelled", databaseError.toException())
}
}
// board안에있는 key값을 가져오기
FBRef.recipeboardRef.child(key).addValueEventListener(postListener)
}
// 이미지 다운로드 함수 (게시글에서 쓴 이미지 가져와서 레이아웃에 표현하기)
private fun getEditImageData(key: String) {
// 파이어베이스 스토리지에 key.png라고 이름 등록
val storageReference = Firebase.storage.reference.child(key + ".png")
// 이미지 보일 레이아웃 위치 지정
val imageViewFromFB = binding.recipeimageUpload1
storageReference.downloadUrl.addOnCompleteListener(OnCompleteListener { task ->
// 이미지 업로드 성공
if (task.isSuccessful) {
// Glide를 사용하여 task에서 이미지 직접 다운로드
Glide.with(this)
.load(task.result)
.into(imageViewFromFB)
// 이미지 업로드 실패
} else {
}
})
}
// 수정버튼 눌렀을때 수정(다시 업로드)되는 함수
// 파이어베이스 리얼타임데이터베이스에 다시 업로드, key값과 imageUrl값을 넣어서!!
private fun editBoardData(key : String, imageUrl : String){
// 데이터 집어넣기
FBRef.recipeboardRef
.child(key)
.setValue(RecipeBoardModel(binding.recipenameET1.text.toString(), // 내가 작성한 recipenameET1값 집어넣음
binding.foodmeterialET1.text.toString(), // 내가 작성한 foodmeterialET1값 집어넣음
binding.recipewriteET1.text.toString(), // 내가 작성한 recipewriteET1값 집어넣음
binding.recipeTipET1.text.toString(), // 내가 작성한 recipeTipET1값 집어넣음
writeUid,
FBAuth.getTime2(),
imageUrl) // 수정된 imageUrl값 업로드
)
Toast.makeText(this, "수정완료", Toast.LENGTH_SHORT).show()
finish() // 엑티비티 종료
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
// 갤러리에서 데이터 받아오기
if(resultCode == RESULT_OK && requestCode == 100){
// 받아온 데이터를 레이아웃에 표시(갤러리 데이터가 imageArea에 표시)
binding.recipeimageUpload1.setImageURI(data?.data)
}
}
// 이미지 업로드 함수
private fun imageUpload(key :String){
val storageRef = storage.reference
val mountainsRef = storageRef.child(key + ".png")
val imageView = binding.recipeimageUpload1
imageView.isDrawingCacheEnabled = true
imageView.buildDrawingCache()
val bitmap = (imageView.drawable as BitmapDrawable).bitmap
val baos = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos)
val data = baos.toByteArray()
var uploadTask = mountainsRef.putBytes(data)
// 이미지 업로드 실패했을때
uploadTask.addOnFailureListener {
// 이미지 업로드 성공했을때
}.addOnSuccessListener { taskSnapshot ->
// 파이어베이스에 업로드 된 이미지의 다운로드 url을 가져온다
mountainsRef.downloadUrl.addOnSuccessListener { uri->
val imageUrl = uri.toString()
// editBoardData함수에, 생성된 key와 imageUrl넣기
editBoardData(key, imageUrl)
// 업로드 된 이미지의 다운로드 url을 가져오는것애 실패했을때
}.addOnFailureListener {
Toast.makeText(this, "이미지 업로드에 실패했습니다", Toast.LENGTH_SHORT).show()
}
}
}
}
이렇게하면 수정버튼을 눌렀을때, 수정한 글과 이미지가 리사이클러뷰에 잘 반영되는것을 확인할 수 있다
파이어베이스도 확인해보겠다!
이건 수정하기 전 파이어베이스이고
수정하면 이렇게 모든 데이터가 수정이 잘 되는것을 확인할 수 있다
특히 내가 원했던 imageUrl부분도 내가 업로드한 이미지의 url이 잘 수정된것을 볼 수 있다!!
'개발 노트 > Kotlin' 카테고리의 다른 글
[kotlin] 문법 2주차 정리 - 기초 (1) | 2024.03.06 |
---|---|
RecyclerView 레이아웃이 안보이는 문제 [변수명 오류] (1) | 2024.03.05 |
[kotlin] 문법 1주차 정리 - 기초 (1) | 2024.03.05 |
파이어베이스 이미지URL을 통해 이미지 불러오기 (0) | 2024.03.03 |
[kotlin] 연산자와 우선순위 (0) | 2024.03.01 |