SharedPreferences가 어느 순간 갑자기 초기화가 되어 있습니다.

조회수 1641회

안드로이드 포그라운드 서비스를 구현했고 그 안에서 일정 초마다 지속적으로 작동하는 핸들러(약 3초마다 재귀 형식으로 작동) 내부에서 SharedPreferences로 값을 저장하는 앱이 있습니다. 대부분 잘 작동되는 듯 보이지만 불규칙한 주기로 앱 내에 SharedPreferences로 저장되어 있던 모든 데이터들이 삭제되어 있네요.(서비스 뿐만이 아니고 다른 액티비티에서도 SharedPreferences로 저장한 데이터도 삭제되었습니다.) 서비스 내에서 핸들러가 계속 돌아가서 폰이 못버티고 터져버린 것인지 잘 모르겠습니다. 혹시 사용자가 직접 데이터 삭제한 것 외에도 값이 초기화가 되는 문제가 있나요?(당연하지만 SharedPreferences에서 제공하는 삭제 함수는 안썼습니다.)

public Boolean read() {    
SharedPreferences pref = getApplicationContext().getSharedPreferences("app", Context.MODE_MULTI_PROCESS);
return pref.getBoolean("data", false);
}
public void write(boolean value) {
SharedPreferences pref = getApplicationContext().getSharedPreferences("app", Context.MODE_MULTI_PROCESS);
SharedPreferences.Editor editor = pref.edit();
editor.putBoolean("data", value);
editor.commit();
}

MultiDex를 상속 받은 클래스 내에서 자료형과 이름만 다르고 저런 식으로 모두 저장했습니다. 정말 간절하니 꼭 답변 부탁드립니다.

추가) 핸들러 내부에서 로그를 보니 아래와 같은 로그가 특정 주기로 계속 보였습니다.

background concurrent copying gc freed 7060(663kb) allocspace objects ....
I/zygote64: Do partial code cache collection, code=61KB, data=39KB
I/zygote64: After code cache collection, code=61KB, data=39KB
I/zygote64: Increasing code cache capacity to 256KB

혹시 이것과 연관있지 않나 올려봅니다.

1 답변

  • 좋아요

    0

    싫어요
    채택 취소하기

    Documentation에 따르면 Context.MODE_MULTI_PROCESS 상수가 API level 23에서 Deprecated 되었음을 알 수 있습니다. 사실 SharedPreferences를 MODE_MULTI_PROCESS 모드로 읽는다고 여러 프로세스가 접근할 때의 안정성을 보장하지는 않습니다. MODE_MULTI_PROCESS는 단지 getSharedPreferences() 단계에서 같은 SharedPreferences를 이미 다른 곳에서 사용하고 있는 지 체크하지 않게 하는 것 뿐입니다.

    또한 여러 곳에서 SharedPreferences를 수정할 경우 초기 값으로 리셋이 되버리는 문제가 있습니다. https://stackoverflow.com/questions/31056285/shared-preferences-deleted-automatically https://stackoverflow.com/questions/7438195/sharedpreferences-are-sometimes-deleted

    따라서 Documentation에서 추천하는 대로 ContentProvider를 이용하거나, 아니면 SharedPreferences를 관리하는 하나의 클래스를 만들어서 쓰셔야할 것 같습니다.

    • (•́ ✖ •̀)
      알 수 없는 사용자
    • 그렇다면 A클래스(기존에 사용하던 SharedPreferences 클래스)에는 메인이나 다른 액티비티에서 날아오는 SharedPreferences만 쓰게 하고 새로 만든 B클래스에는 서비스 핸들러에서 찍히는 SharedPreferences만 저장되게 만들면 될까요? 아니면 그냥 서비스 핸들러 데이터 저장 부분만 SQLite를 새로 만들어서 저장을 해야할까요? 따로 정해진 시간없이 사용자가 앱을 삭제하기 까지 무한정 값을 업데이트해야 하는형식인데 괜찮을까요 SWC 2020.9.5 13:37
    • 제가 잘 이해한 것인지는 모르겠지만 클래스를 나누셔도 결국 다른 곳에서 동시에 SharedPreferences를 건드리면 똑같이 값이 날라갈 수도 있습니다. Java의 synchronized를 이용해서 SharedPreferences에 차례대로 쓰게하는 방법을 사용해보는 것도 좋습니다. 만약 이러한 디자인으로 설계하실 때에는 SharedPreferences.Editor 클래스의 commit() 메서드 대신 apply() 메서드를 쓰는 것이 좋습니다. apply()는 commit()과 다르게 비동기적이기 때문에 Blocking이 없습니다. 알 수 없는 사용자 2020.9.5 17:06
    • 답변 감사합니다. 스택오버플로우를 보니 SQLite로 하는 것이 좋다고 해서 일단 commit부분을 전부 apply로 바꿔보고 그래도 초기화가 된다면 서비스 핸들러 부분에만 SQLite를 적용해 보겠습니다. 마지막으로, 저기 로그에 찍혀있는 " background concurrent... ", " I/zygote64: " 부분은 큰 문제가 없다고 생각하면 되나요? SWC 2020.9.5 17:41
    • 잘하면 좀 큰 문제일 수도 있습니다. 저 로그는 Garbage Collector이랑 관련이 있는데, 메모리 누수가 있을 수도 있으니 LeakCanary 같은 누수 감지 도구를 써서 확인해보세요. 알 수 없는 사용자 2020.9.5 20:21

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)