Mobile Front/Android(kotlin)

[kotlin] RecyclerView Refresh in Fragment(리사이클러뷰 갱신, 리사이클러뷰 목록 갱신하는 법, fragment recyclerview refresh, notifyDataSetChanged)

koh1018 2021. 4. 2. 09:15
반응형

 

* * * 내용의 본론이 급한 사람은 밑의 빨간 글씨부터 읽으면 됩니다 * * *

 

 

며칠간 방법을 찾느라 삽질의 삽질한 것을 드디어 구현했다..!

 

그것은 바로 RecyclerView의 Refresh(갱신) 방법이었다.

정말 오랫동안 구글링을 했는데, 굉장히 다양한 방법들이 있었고 그 중 대다수를 실패했다.

 

삭제를 했으면 갱신이 되어야 UI상에 리액션이 되고 이를 통해 앱이 올바르게 작동하고 있음을 사용자가 인지할텐데 이것이 안되니 무척 고민이었다..

 

필자가 원하는 것은

목록 추가 버튼을 누르면 -> 다른 액티비티에 넘어간 후 -> 그 액티비티에서 추가할 데이터의 정보를 입력한 후 -> 저장을 누르고 나오면 -> 리사이클러뷰가 UI상에서 저절로 갱신 되는 것이었다.

 

MainActivity의 레이아웃이다.

필자의 MainActivity는 위의 사진과 같이 맨아래 BottomNavigationView가 있고, 그 위에 AdMob, 그 위에 Fragment가 있는 구조였다.

그리고 문제의 RecyclerView는 Fragment안에 있었다.

 

 


 

필자가 처음 사용했던 방법은 Activity의 생명주기를 이용한 방법이었다.

Activity의 경우 다른 Activity로 이동하게 되었다 돌아오면 OnRestart()라는 주기를 거친다.

이를 이용해서 OnRestart()단에서 앱을 종료했다가 다시 시작하게 해 갱신하는 방식을 사용했다.

 

하지만 이는 무척 거친 방법이었다..

높은 안드로이드 버전 폰의 경우 문제없이 잘 작동했으나 낮은 버전 폰의 경우 그냥 그대로 앱이 꺼지고 말았다.

그리고 확실하게, 이는 제대로 된 방법이 아닌 것 같았다.

 

 

그래서 더 찾아보던중 notifyDataSetChanged() 메소드에 대해 알게 되었다.

이를 바로 적용해보았지만 역시나 UI 상의 변화는 없었다.

 

계속 시도해도 변화가 없자 이번엔 supportFragmentManager.beginTransaction().detach(프래그먼트).attach(프래그먼트).commit() 를 이용해 Fragment 자체를 갱신시켜보려고 해봤다.

하지만 이 방법은 앱이 강제종료되는 문제를 가져왔다..(데이터를 추가하면 앱이 강제종료되었다.)

 

startActivityForResult() 를 이용해 접근하는 방식도 있었지만 이는 OnRestart() 주기를 이용하는 것과 별반 다를게 없다고 생각이 들었다.

 

 

우선 OnRestart() 주기에서 Refresh를 해야 하는 건 맞다고 생각이 들었고 문제는 Activity의 OnRestart() 주기에서 어떻게 Fragment안의 RecyclerView를 갱신할 거냐는 것이었다.

 

계속해서 찾아보고 시도한 결과

stackoverflow.com/questions/50115471/refresh-recyclerview-fragment-from-another-fragments-adapter 의 답변을 응용해 문제를 해결할 수 있었다.

그것은 무척 심플하고 확실한 방법이었다.

 

 

 

 

* * * 본론 * * *

 

 

RecyclerView가 있는 Fragment와 그 Fragment가 있는 Activity에 각각 몇줄의 코드만 추가해주면 된다.

 

우선 Fragment의 경우,

 

1. RecyclerView에 넣을 때 쓰는 데이터 변수를 클래스 변수로 선언한다.

2. RecyclerView의 어댑터 변수도 클래스 변수로 선언해둔다.

class MainFragment : Fragment() {

    var data = mutableListOf<Memo>()

    var adapter: CustomAdapter? = null
    
    }

 

3. 클래스의 메소드를 하나 추가해 어댑터 변수에 수정된 데이터를 넣고(필자는 adapter에 setData라는 메소드를 추가했었기 때문에 이렇게 작성했다. 어떤 방식으로든 adapter의 field인 데이터에 수정된 데이터를 넣어주기만 하면 된다.)

4. notifyDataSetChanged()를 해준다.

fun refreshAdapter() {

	//
	// 수정된 데이터를 다시 로드하는 코드 작성
        //
        
        adapter?.setData(data)
        adapter?.notifyDataSetChanged()
    }

 

 

이제 Activity의 경우,

 

5. OnRestart() 주기에 위의 Fragment에서 작성한 메소드( refreshAdapter() )가 실행될 수 있도록해준다. (필자는 위의 Fragment 이름이 MainFragment였다. 각자 원하는 Fragment이름에 맞게 작성해주면 된다.)

// 액티비티 재실행시 갱신
    override fun onRestart() {
        super.onRestart()
        MainFragment().refreshAdapter()
    }

 

 

이제 별다른 동작 없이도(+앱을 재시작하게 하지 않아도..) 데이터를 추가, 삭제할 때 RecyclerView의 내용이 UI 상에서 바로바로 변경된다!

 

 

P.S. 공식 문서에 따르면 notifyDataSetChanged()는 높은 cost의 방식이라고 한다. 편의를 위해 이 메소드를 사용했지만 조금 더 공부해서 다른 notify를 사용하면 더 효율적인 앱을 만들 수 있을 것 같다.

 

 

반응형