본문 바로가기

Android Project

[Android/Kotlin] 커뮤니티앱(10) - 게시글 삭제, 수정

이번에는 게시글 삭제, 수정을 할수있도록 해볼것이다

햄버거 버튼을 누르면 삭제와 수정이 가능하도록 할것이기 때문에 레이아웃에 햄버거버튼을 추가로 디자인해준다 

<ImageView
    android:id="@+id/boardSettingIcon"
    android:layout_width="30dp"
    android:layout_height="30dp"
    android:src="@drawable/main_menu"
    android:layout_margin="10dp"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

activity_board_inside.xml

 

activity_board_inside.xml

 

 

햄버거바 클릭시 다이얼로그창을 띄울것이기때문에 다이얼로그창 레이아웃을 생성해서 디자인해준다

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/editBtn"
        android:text="수정버튼"
        android:layout_width="match_parent"
        android:background="@drawable/background_radius_yellow"
        android:layout_margin="20dp"
        android:layout_height="wrap_content"/>

    <Button
        android:id="@+id/removeBtn"
        android:text="삭제버튼"
        android:layout_width="match_parent"
        android:background="@drawable/background_radius_yellow"
        android:layout_margin="20dp"
        android:layout_height="wrap_content"/>

</LinearLayout>

custom_dialog.xml

 

custom_dialog.xml

 

 

그런다음 showDialog()함수를 만들어서 다이얼로그창을 띄우는 코드를 적어주고, 수정버튼을 눌렀을때와 삭제버튼을 눌렀을때 잘 나오는지 확인해보기위해서 토스트메시지를 띄워서 확인해준다 

 

# 게시글 삭제

먼저 삭제버튼 동작하는것부터 작성해볼건데, 삭제버튼을 누르면 게시글이 삭제가 되야할것이다

즉, 삭제버튼을 누르면 키값이 삭제되야하기 때문에, 키값을 찾아서 삭제해주면된다

키값을 찾기위해서 먼저 키값을 선언해준뒤, board안에 key값을 찾아와서 삭제해주면된다 

 

근데 이렇게적고 삭제버튼을 클릭하니깐 앱이 종료되는 문제가 발생했다

데이터를 받아와서 삭제를 했는데, 데이터가 변경되면 getBoardData부분에서 데이터를 불러오는데 해당되는 데이터가 없어서 오류가 발생하는것같다  

그래서 try,catch문을 사용해서 try문이 에러가 발생하면 catch문이 실행이되도록 예외처리를 해준다 

package com.example.mysololife.board

class BoardInsideActivity : AppCompatActivity() {

    private val TAG = BoardInsideActivity::class.java.simpleName

    private lateinit var binding : ActivityBoardInsideBinding

    // key값 선언
    private lateinit var key : String

    override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)

        binding = DataBindingUtil.setContentView(this,R.layout.activity_board_inside )
        

        // 햄버거바 클릭시
        binding.boardSettingIcon.setOnClickListener {

            // 다이얼로그 띄우기
            showDialog()
        }


        // TalkFragment에서 보낸 key값 받아오기
        key = intent.getStringExtra("key").toString()

        getBoardData(key)
        getImageData(key)
    }




    // 다이얼로그창 띄우는 함수
    private fun showDialog(){

        val mDialogView = LayoutInflater.from(this).inflate(R.layout.custom_dialog, null)
        val mBuilder = AlertDialog.Builder(this)
            .setView(mDialogView)
            .setTitle("게시글 수정,삭제")

        val alertDialog = mBuilder.show()

        // 수정버튼 눌렀을때
        alertDialog.findViewById<Button>(R.id.editBtn)?.setOnClickListener {
            Toast.makeText(this, "수정버튼 테스트", Toast.LENGTH_SHORT).show()
        }
        // 삭제버튼 눌렀을때
        alertDialog.findViewById<Button>(R.id.removeBtn)?.setOnClickListener {

            // 파이어베이스에 board안에 key값을 찾아와서 삭제
            FBRef.boardRef.child(key).removeValue()
            Toast.makeText(this, "삭제완료", Toast.LENGTH_SHORT).show()
            finish()    // 엑티비티 종료
        }
    }

            ...



    // board데이터 받아오는 함수
    private fun getBoardData(key : String){

        // 데이터 가져오기
        val postListener = object : ValueEventListener {
            override fun onDataChange(dataSnapshot: DataSnapshot) {

                
                // try문에서 에러발생하면 catch문 실행
                try {

                    //데이터 받아오기
                    val dataModel = dataSnapshot.getValue(BoardModel::class.java)

                    // 레이아읏과 연결
                    binding.titleArea.text = dataModel!!.title   // titleArea와 BoardModel 연결
                    binding.textArea.text = dataModel!!.content  // textArea와 BoardModel 연결
                    binding.timeArea.text = dataModel!!.time     // timeArea와 BoardModel 연결

                } 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.boardRef.child(key).addValueEventListener(postListener)

    }
}

BoardInsideActivity.kt

 

이렇게하고 확인해보면 게시글이 오류없이 잘 삭제되는것을 확인할수있다

 

 

 

근데 게시글은 한번 삭제하면 다시 복구할수 없으므로 삭제버튼을 눌렀을때 다이얼로그창을 한번 더 띄워서 정말 삭제할것인지 확인하고 삭제하면 좋겠다고 생각이 들어서, 삭제버튼을 눌렀을때 다이얼로그를 한번 더 추가해주었다

아까는 다이얼로그 버튼을 만들어서 사용했다면, 지금은 기본 형태의 다이얼로그를 사용했다

 

삭제 버튼을 눌렀을때 다이얼로그가 나타나면서 "정말로 삭제하시겠습니까? 삭제하시면 복구할수없습니다" 라는 메시지가 뜨고 "네"를 누르면 게시물이 삭제되고, 

"아니오"를 누르면 finish()로 그냥 엑티비티가 종료되도록 코드를 짜주었다

마지막에 꼭 builder.show()를 써줘야지 다이얼로그가 띄워진다. 빼먹지말고 작성해주도록하자!!

// 삭제버튼 눌렀을때
alertDialog.findViewById<Button>(R.id.removeBtn)?.setOnClickListener {

    // "정말 삭제하겠습니다?" 다이얼로그 추가
    val builder = AlertDialog.Builder(this)
    builder.setTitle("게시글 삭제")
        .setMessage("정말로 삭제하시겠습니까? 삭제하시면 복구할수없습니다")

        .setPositiveButton("네",
            DialogInterface.OnClickListener{ dialog, id ->

                // 파이어베이스에 board안에 key값을 찾아와서 삭제
                FBRef.boardRef.child(key).removeValue()
                Toast.makeText(this, "삭제완료", Toast.LENGTH_SHORT).show()
                finish()    // 엑티비티 종료
            })
        .setNegativeButton("아니오",
            DialogInterface.OnClickListener{ dialog, id ->
                finish()
            })

    // 다이얼로그 띄워주기
    builder.show()
}

BoardInsideActivity.kt

 

이렇게 수정해준 결과 다이얼로그가 잘 나타나는것을 볼수있다

 

 

https://stickode.tistory.com/104

 

[Kotlin][Android] Alert Dialog 다이얼로그 띄우기

안녕하세요. 이번 시간에는 Dialog를 띄워보도록 하겠습니다. 우선 Dialog가 무엇인지 알아봅시다. 안드로이드 개발자라면 당연히 안드로이드 개발자 사이트에서 봐야겠지요? developer.android.com/guide/

stickode.tistory.com

이 블로그 내용을 참고해서 해당 다이얼로그를 만들어주었다

 

 

 

 

# 게시물 수정

이번엔 게시물 수정을 만들어보도록 하겠다

 

게시물 수정 버튼을 누르면 수정을 할수있는 엑티비티가 나와야되기 때문에 새로운 엑티비티와 레이아웃을 만들어준다

수정하는거는 글쓰기 페이지랑 똑같이 만들어도 상관이 없을것이다

게시물 수정 레이아웃은 글쓰기 페이지랑 똑같이 만들어준다

그런다음 BoardInsideActiivity로 가서 수정버튼을 눌렀을때 BoardEditActivity로 이동하는 코드를 짜준다

<?xml version="1.0" encoding="utf-8"?>
<layout>

    <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=".board.BoardEditActivity">

        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical">

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="60dp">

                    <TextView
                        android:text="수정 페이지"
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:textColor="@color/black"
                        android:gravity="center"/>

                </LinearLayout>

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="0.5dp"
                    android:background="#000000"/>

                <EditText
                    android:id="@+id/titleArea"
                    android:layout_margin="20dp"
                    android:layout_width="match_parent"
                    android:background="@android:color/transparent"
                    android:hint="제목을 입력해주세요"
                    android:layout_height="60dp"/>

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="0.5dp"
                    android:layout_marginLeft="20dp"
                    android:layout_marginRight="20dp"
                    android:background="#000000"/>

                <EditText
                    android:id="@+id/contentArea"
                    android:layout_margin="20dp"
                    android:layout_width="match_parent"
                    android:hint="내용을 입력해주세요"
                    android:background="@android:color/transparent"
                    android:layout_height="60dp"/>

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="0.5dp"
                    android:layout_marginLeft="20dp"
                    android:layout_marginRight="20dp"
                    android:background="#000000"/>

                <ImageView
                    android:id="@+id/imageArea"
                    android:src="@drawable/plusbtn"
                    android:layout_marginTop="20dp"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"/>

                <Button
                    android:id="@+id/editBtn"
                    android:text="수정"
                    android:layout_width="match_parent"
                    android:background="@drawable/background_radius_yellow"
                    android:layout_marginTop="50dp"
                    android:layout_marginLeft="20dp"
                    android:layout_marginRight="20dp"
                    android:layout_height="wrap_content"/>

            </LinearLayout>

        </ScrollView>

    </LinearLayout>

</layout>

activity_board_edit.xml

 

activity_board_edit.xml

 

 

근데 수정버튼을 눌렀을때 엑티비티에 이미 내가 입력해놓은 제목,내용,이미지의 데이터들이 들어있어야될것이다

따라서 입력해놓은 정보들을 받아와야한다 

BoardInsideActivity에서 key값을 바탕으로 board에 대한 정보를 받아왔었다

그래서 BoardInsideActivity에서 putExtra를 사용해서 key값을 BoardEditActivity로 넘겨준다 

// 수정버튼 눌렀을때
alertDialog.findViewById<Button>(R.id.editBtn)?.setOnClickListener {

    // BoardEditActivity로 이동
    val intent = Intent(this, BoardEditActivity::class.java)

    // BoardEditActivity로 key값 넘겨줌
    intent.putExtra("key", key)

    startActivity(intent)
}

BoardInsideActivity.kt

 

 

먼저 키값을 선언해주고, BoardInsideActivity에서 보낸 key값을 받아와준다 

그리고 이전에 BoardInsideActivity에서 사용했던 board데이터 받아오는 함수와 이미지 다운로드 함수를 거의 똑같이 사용해서 수정버튼을 눌렀을때 데이터들을 가져오도록 할것이다.

getEditBoardDate함수에서 레이아웃을 연결하는 부분은 TextView가 아닌 EditText부분이기 때문에 setText()를 사용해서 레이아웃과 데이터를 연결해준다

전체 코드이다

package com.example.mysololife.board

class BoardEditActivity : AppCompatActivity() {

    // key값 선언
    private lateinit var key : String

    private lateinit var binding : ActivityBoardEditBinding

    private val TAG = BoardEditActivity::class.java.simpleName


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.activity_board_edit)


        // BoardInsideActivity에서 보낸 key값 받아오기
        key = intent.getStringExtra("key").toString()


        // 게시글에서 쓴 데이터 가져와서 레아이웃에 표현하기
        getEditBoardData(key)
        // 게시글에서 쓴 이미지 가져와서 레이아웃에 표현하기
        getEditImageData(key)

    }


    // 이미지 다운로드 함수 (게시글에서 쓴 이미지 가져와서 레이아웃에 표현하기)
    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.imageArea

        storageReference.downloadUrl.addOnCompleteListener (OnCompleteListener { task ->

            // 이미지 업로드 성공
            if(task.isSuccessful){
                // Glide를 사용하여 task에서 이미지 직접 다운로드
                Glide.with(this)
                    .load(task.result)
                    .into(imageViewFromFB)

                // 이미지 업로드 실패
            }else{

            }
        })

    }


    // board데이터 받아오는 함수 (게시글에서 쓴 데이터 가져와서 레아이웃에 표현하기)
    private fun getEditBoardData(key : String){

        // 데이터 가져오기
        val postListener = object : ValueEventListener {
            override fun onDataChange(dataSnapshot: DataSnapshot) {


                // try문에서 에러발생하면 catch문 실행
                try {

                    //데이터 받아오기
                    val dataModel = dataSnapshot.getValue(BoardModel::class.java)

                    // 레이아읏과 연결
                    binding.titleArea.setText(dataModel!!.title)   // titleArea와 BoardModel 연결
                    binding.contentArea.setText(dataModel.content)  // contentArea와 BoardModel 연결


                } 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.boardRef.child(key).addValueEventListener(postListener)

    }


}

BoardEditActivity.kt

 

이렇게 여기까지 작성해주면 수정버튼을 클릭했을때 내가 이전에 작성해놓았던 제목,내용,이미지 관련 데이터가 들어간것을 확인해볼수있다

 

 

 

 

# 수정버튼 눌렀을때 

이제는 수정버튼을 눌렀을때 수정된 게시글이 적용되도록 해볼것이다

 

데이터를 집어넣을때 uid데이터를 넣을때 writeUid를 만들어서 집어넣지 않고, FBAuth.getUid()를 사용해서 현재 나의 Uid값을 가져와도된다

수정 버튼을 눌렀을때 제목,내용,날짜,이미지가 수정이 가능하도록 코드를 짜주었다

package com.example.mysololife.board

class BoardEditActivity : AppCompatActivity() {

    // key값 선언
    private lateinit var key : String

    private lateinit var binding : ActivityBoardEditBinding

    private val TAG = BoardEditActivity::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_board_edit)


        // BoardInsideActivity에서 보낸 key값 받아오기
        key = intent.getStringExtra("key").toString()


        // 게시글에서 쓴 데이터 가져와서 레아이웃에 표현하기
        getEditBoardData(key)
        // 게시글에서 쓴 이미지 가져와서 레이아웃에 표현하기
        getEditImageData(key)


        // editBtn버튼 눌렀을때
        binding.editBtn.setOnClickListener {
            editBoardData(key)
        }


        // imageArea 이미지 눌렀을때
        binding.imageArea.setOnClickListener {

            // 갤러리로 이동
            val gallery = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.INTERNAL_CONTENT_URI)
            startActivityForResult(gallery, 100)

        }


    }


    // 수정버튼 눌렀을때 수정되는 함수
    private fun editBoardData(key : String){

        // 데이터 집어넣기
        FBRef.boardRef
            .child(key)
            .setValue(BoardModel(binding.titleArea.text.toString(),     // text
                                 binding.contentArea.text.toString(),   // content
                                 writeUid,                              // uid      // FBAuth.getUid() 로 써도됨
                                 FBAuth.getTime())                      // time
            )

        // 이미지 업로드
        imageUpload(key)

        Toast.makeText(this, "수정완료", Toast.LENGTH_SHORT).show()

        finish()  // 엑티비티 종료
    }



    // 이미지 다운로드 함수 (게시글에서 쓴 이미지 가져와서 레이아웃에 표현하기)
    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.imageArea

        storageReference.downloadUrl.addOnCompleteListener (OnCompleteListener { task ->

            // 이미지 업로드 성공
            if(task.isSuccessful){
                // Glide를 사용하여 task에서 이미지 직접 다운로드
                Glide.with(this)
                    .load(task.result)
                    .into(imageViewFromFB)

                // 이미지 업로드 실패
            }else{
                Toast.makeText(this, "이미지가 없습니다", Toast.LENGTH_SHORT).show()
            }
        })

    }


    // board데이터 받아오는 함수 (게시글에서 쓴 데이터 가져와서 레아이웃에 표현하기)
    private fun getEditBoardData(key : String){

        // 데이터 가져오기
        val postListener = object : ValueEventListener {
            override fun onDataChange(dataSnapshot: DataSnapshot) {

                // try문에서 에러발생하면 catch문 실행
                try {

                    //데이터 받아오기
                    val dataModel = dataSnapshot.getValue(BoardModel::class.java)

                    // 레이아읏과 연결
                    binding.titleArea.setText(dataModel!!.title)   // titleArea와 BoardModel 연결
                    binding.contentArea.setText(dataModel.content)  // contentArea와 BoardModel 연결

                    // 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.boardRef.child(key).addValueEventListener(postListener)
    }



    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        // 갤러리에서 데이터 받아오기
        if(resultCode == RESULT_OK && requestCode == 100){

            // 받아온 데이터를 레이아웃에 표시(갤러리 데이터가 imageArea에 표시)
            binding.imageArea.setImageURI(data?.data)
        }
    }



    // 이미지 업로드 함수
    private fun imageUpload(key :String){

        val storageRef = storage.reference
        val mountainsRef = storageRef.child(key + ".png")

        val imageView = binding.imageArea

        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 {
            // Handle unsuccessful uploads
        }.addOnSuccessListener { taskSnapshot ->
            // taskSnapshot.metadata contains file metadata such as size, content-type, etc.
            // ...
        }
    }


}

BoardEditActivity.kt

 

그런데 이렇게 코드를 짰더니

수정버튼을 눌러서 수정을 했을때 사진 등록이 바로 적용이되지 않는? 다시 게시물을 눌러서 확인했을때는 잘 반영이 되지만, 수정하고 나온 즉시에는? 이미지가 적용이 되지 않는 문제가 발생하였다.

그래서 수정버튼을 눌렀을때 코드 실행이 다 된후 마지막에 finish()를 써줌으로써 엑티비티가 종료되도록 적용해서 문제를 해결했다

 

이렇게 코드를 짜주면 수정부분이 잘 작동하는것을 확인할수있다