[TIL] Shared Preferences를 통한 Book Mark 구현하기

박봉팔·2024년 1월 29일
0

Book Mark

Fragment간 북마크 기능을 사용하기 위해 기존에는 object를 사용해 더미 데이터를 공유했다.

하지만 retrofit을 사용해 서버에서 데이터를 받아오기 시작하면서 싱글톤 패턴을 사용한 데이터 관리가 불필요해졌다.

그래서 북마크 기능을 구현하기위해 다양한 고민을 해봤지만, 과제의 필수요소가 요구하는 Main Activity를 이용해 북마크 리스트를 저장하는 것은 Navigation graph를 사용하는 방법으로는 생각하기가 힘들었고, 인터페이스를 통해 구현하자니 너무 많은 인터페이스가 필요할거같아서 선택과제에 있는 Shared Preferences를 통해 북마크 기능을 구현해보기로 했다.


Json

Shared Preference를 사용하기 위해서는 우선 저장하기 위한 아이템 객체를 변환할 필요가 있었다.

따라서 Gson라이브러리를 사용해 객체를 toJaon메서드로 json형태로 변환해 저장하도록 했고, 다시 로드할때는 fromJson메서드를 통해 객체로 변환해 사용하였다.


Preference Util Class

우선 검색 화면과 북마크 화면 두 곳에서 모두 클릭을 통해 북마크를 제거 해야했고, 검색화면에서는 추가까지 해야했기 때문에 모든 화면에서 사용할 수 있도록 Shared Preference를 사용할수 있는 클래스를 따로 구성했다.

클래스에는 프리퍼런스의 모든 목록을 가져오는 메서드와 해당 목록을 확인해, 목록에 아이템이 있을 경우에는 삭제 / 없을 경우에는 추가해주는 메서드를 사용했다.

또한 각 아이템에는 고유한 값으로 image URL을 가지고 있었기때문에 해당값을 키값으로 사용했다.

class PrefUtil(private val context: Context) {
    private val pref = context.getSharedPreferences(MY_FAVORITE, Context.MODE_PRIVATE)
    private val prefEditor = pref.edit()
    private val gson = Gson() // json으로 변환하기위한 Gson 객체

    fun getAll(): MutableList<ImageItemDetail> {
        var items = mutableListOf<ImageItemDetail>()

		// 프리퍼런스의 모든 값을 받아와 각 값들을 fromJson을 통해 객체로 변환해준다.
        pref.all.values.forEach {
            items += gson.fromJson(it.toString(), ImageItemDetail::class.java)
        }
        return items
    }

    fun togglePref(item: ImageItemDetail) {
        val allPrefs = getAll()

        if (allPrefs.contains(item)) {
        	// 북마크에 아이템이 존재할 경우 key값으로 프리퍼런스의 아이템을 삭제
            prefEditor.run {
                remove(item.imageUrl)
                apply()
            }
        } else {
            prefEditor.run {
            	// 북마크에 아이템이 없을 경우 key값으로 imageURL 값을 넣고
                // item을 toJson으로 변환해서 저장
                putString(item.imageUrl, gson.toJson(item))
                apply()
            }
        }
    }
}

Value Update

Preference Util을 통해서 북마크한 값에 손쉽게 접근이 가능했고, 검색 페이지와 북마크 페이지 모두 리사이클러뷰에 같은 어댑터를 사용했기 때문에 북마크 리스트를 매번 새로 전달하고 싶지 않아서 어댑터 내부에서 확인이 가능하도록 구현했다.
(이게 좋은지는 잘 모르겠어서 더 알아봐야 할 듯...)

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
	val item = getItem(position)
    // 프리퍼런스에 저장된 북마크 내용을 불러옴
	val favoriteList = PrefUtil(context).getAll()

	with(holder as SearchItemViewHolder) {
    	...
        ivFavorite.load(
        	//북마크 리스트에 현재 아이템이 있다면 / 없다면, 버튼을 on / off 하도록 만듬
          	if (favoriteList.contains(item)) {
            	R.drawable.btn_favorite_on
          	} else {
            	R.drawable.btn_favorite_off
			}
		)
	}
}

이후 notifyDataSetChangedsubmitList를 통해 북마크 목록이 실시간으로 반영될 수 있도록 구현했다.


오늘은 어땠나요?

안녕하세요 말하는 감자입니다.

똥멍청이가 된 기분을 느끼고 싶으세요?

개발을 하세요!

profile
개발 첫걸음! 가보자구!

0개의 댓글