SharedPreferences에 액세스하는 것은 UI 스레드에서 수행해야합니까?
Gingerbread가 출시되면서 새로운 API 중 일부는 StrictMode를 사용해 실험 해 왔습니다 .
경고 중 하나가에 대한 것임을 알았습니다 getSharedPreferences()
.
이것은 경고입니다.
StrictMode policy violation; ~duration=1949 ms: android.os.StrictMode$StrictModeDiskReadViolation: policy=23 violation=2
getSharedPreferences()
UI 스레드에서 수행 되는 호출에 대해 제공됩니다 .
SharedPreferences
실제로 UI 스레드에서 액세스하고 변경 해야합니까 ?
나는 당신이 이미 그것을 가지고 놀기 때문에 기쁩니다!
참고할 사항 : (게으른 총알 형태)
- 이것이 최악의 문제라면 앱이 좋은 위치에있을 것입니다. :) 쓰기는 일반적으로 읽기보다 느리므로 commit () 대신 SharedPreferenced $ Editor.apply ()를 사용하고 있는지 확인하십시오. apply ()는 GB 및 비동기의 새로운 기능입니다 (그러나 항상 안전하고 수명주기 전환에주의). 리플렉션을 사용하여 GB +에서는 apply ()를, Froyo 이하에서는 commit ()을 조건부로 호출 할 수 있습니다. 이 작업을 수행하는 방법에 대한 샘플 코드가 포함 된 블로그 게시물을 작성하겠습니다.
로드에 관해서는 ...
일단로드되면 SharedPreferences는 싱글 톤이며 프로세스 전체에 캐시됩니다. 따라서 가능한 빨리로드하여 필요에 따라 메모리에 저장하려고합니다. (단순 XML 파일 인 SharedPreferences를 사용하는 경우 크기가 작다고 가정하면 ...) 앞으로 일부 사용자가 버튼을 클릭 할 때 잘못하고 싶지는 않습니다.
하지만 context.getSharedPreferences (...)를 호출 할 때마다 백업 XML 파일이 변경되었는지 확인하기 위해 통계가 표시되므로 어쨌든 UI 이벤트 중에 이러한 통계를 피하고 싶을 것입니다. 통계는 일반적으로 빠르며 (캐시되는 경우가 많음) yaffs는 동시성에 많은 영향을주지 않습니다 (그리고 yaffs에서 실행되는 많은 Android 기기 ... Droid, Nexus One 등). 디스크를 피한다면 , 다른 진행 중이거나 보류중인 디스크 작업에 뒤처지지 않도록합니다.
따라서 onCreate () 중에 SharedPreferences를로드하고 동일한 인스턴스를 다시 사용하여 통계를 피하고 싶을 것입니다.
그러나 onCreate () 중에 환경 설정이 필요하지 않은 경우로드 시간이 앱의 시작을 불필요하게 지연 시키므로 일반적으로 새 스레드를 시작하는 FutureTask <SharedPreferences> 하위 클래스와 같은 것을 .set로 설정하는 것이 좋습니다. () FutureTask 서브 클래스의 값. 그런 다음 필요할 때마다 FutureTask <SharedPreferences>의 멤버를 조회하고 .get ()하십시오. 나는 이것을 Honeycomb의 무대 뒤에서 투명하게 무료로 만들 계획입니다. 이 영역에서 모범 사례를 보여주는 몇 가지 샘플 코드를 릴리스하려고합니다.
다음 주에 StrictMode 관련 주제에 대한 향후 게시물을 보려면 Android 개발자 블로그를 확인하십시오.
공유 기본 설정에 액세스하는 것은 플래시 저장소에서 읽기 때문에 시간이 오래 걸릴 수 있습니다. 많이 읽으십니까? 아마도 SQLite 데이터베이스와 같은 다른 형식을 사용할 수 있습니다.
그러나 StrictMode를 사용하여 찾은 모든 것을 수정하지는 마십시오. 또는 문서를 인용하려면 :
그러나 StrictMode가 찾은 모든 것을 고쳐야한다고 생각하지 마십시오. 특히 정상적인 활동 수명주기 동안 많은 경우의 디스크 액세스가 필요합니다. 실수로 한 일을 찾으려면 StrictMode를 사용하십시오. 하지만 UI 스레드에 대한 네트워크 요청은 거의 항상 문제입니다.
Brad의 대답에 대한 한 가지 미묘한 점 : onCreate ()에서 SharedPreferences를로드하더라도 공유 파일 환경 설정을 읽을 때까지 (백그라운드 스레드에서) getString () 등이 차단되기 때문에 여전히 백그라운드 스레드에서 값을 읽어야합니다.
public String getString(String key, String defValue) {
synchronized (this) {
awaitLoadedLocked();
String v = (String)mMap.get(key);
return v != null ? v : defValue;
}
}
edit ()도 같은 방식으로 차단되지만 apply ()는 포 그라운드 스레드에서 안전 해 보입니다.
(여기에 넣어서 미안합니다. 나는 이것을 Brad의 대답에 대한 코멘트로 넣었을 것입니다. 그러나 나는 방금 가입했고 그렇게 할 충분한 평판이 없습니다.)
나는 이것이 오래된 질문이라는 것을 알고 있지만 내 접근 방식을 공유하고 싶습니다. 독서 시간이 길었고 공유 된 선호도와 글로벌 애플리케이션 클래스를 함께 사용했습니다.
ApplicationClass :
public class ApplicationClass extends Application {
private LocalPreference.Filter filter;
public LocalPreference.Filter getFilter() {
return filter;
}
public void setFilter(LocalPreference.Filter filter) {
this.filter = filter;
}
}
LocalPreference :
public class LocalPreference {
public static void saveLocalPreferences(Activity activity, int maxDistance, int minAge,
int maxAge, boolean showMale, boolean showFemale) {
Filter filter = new Filter();
filter.setMaxDistance(maxDistance);
filter.setMinAge(minAge);
filter.setMaxAge(maxAge);
filter.setShowMale(showMale);
filter.setShowFemale(showFemale);
BabysitApplication babysitApplication = (BabysitApplication) activity.getApplication();
babysitApplication.setFilter(filter);
SecurePreferences securePreferences = new SecurePreferences(activity.getApplicationContext());
securePreferences.edit().putInt(Preference.FILER_MAX_DISTANCE.toString(), maxDistance).apply();
securePreferences.edit().putInt(Preference.FILER_MIN_AGE.toString(), minAge).apply();
securePreferences.edit().putInt(Preference.FILER_MAX_AGE.toString(), maxAge).apply();
securePreferences.edit().putBoolean(Preference.FILER_SHOW_MALE.toString(), showMale).apply();
securePreferences.edit().putBoolean(Preference.FILER_SHOW_FEMALE.toString(), showFemale).apply();
}
public static Filter getLocalPreferences(Activity activity) {
BabysitApplication babysitApplication = (BabysitApplication) activity.getApplication();
Filter applicationFilter = babysitApplication.getFilter();
if (applicationFilter != null) {
return applicationFilter;
} else {
Filter filter = new Filter();
SecurePreferences securePreferences = new SecurePreferences(activity.getApplicationContext());
filter.setMaxDistance(securePreferences.getInt(Preference.FILER_MAX_DISTANCE.toString(), 20));
filter.setMinAge(securePreferences.getInt(Preference.FILER_MIN_AGE.toString(), 15));
filter.setMaxAge(securePreferences.getInt(Preference.FILER_MAX_AGE.toString(), 50));
filter.setShowMale(securePreferences.getBoolean(Preference.FILER_SHOW_MALE.toString(), true));
filter.setShowFemale(securePreferences.getBoolean(Preference.FILER_SHOW_FEMALE.toString(), true));
babysitApplication.setFilter(filter);
return filter;
}
}
public static class Filter {
private int maxDistance;
private int minAge;
private int maxAge;
private boolean showMale;
private boolean showFemale;
public int getMaxDistance() {
return maxDistance;
}
public void setMaxDistance(int maxDistance) {
this.maxDistance = maxDistance;
}
public int getMinAge() {
return minAge;
}
public void setMinAge(int minAge) {
this.minAge = minAge;
}
public int getMaxAge() {
return maxAge;
}
public void setMaxAge(int maxAge) {
this.maxAge = maxAge;
}
public boolean isShowMale() {
return showMale;
}
public void setShowMale(boolean showMale) {
this.showMale = showMale;
}
public boolean isShowFemale() {
return showFemale;
}
public void setShowFemale(boolean showFemale) {
this.showFemale = showFemale;
}
}
}
MainActivity (애플리케이션에서 먼저 호출되는 활동) :
LocalPreference.getLocalPreferences(this);
설명 된 단계 :
- 메인 액티비티는 getLocalPreferences (this)를 호출합니다.-> 이것은 여러분의 환경 설정을 읽고, 여러분의 애플리케이션 클래스에 필터 객체를 설정하고 그것을 반환합니다.
- When you call the getLocalPreferences() function again somewhere else in the application it first checks if it's not available in the application class which is a lot faster.
NOTE: ALWAYS check if an application wide variable is different from NULL, reason -> http://www.developerphil.com/dont-store-data-in-the-application-object/
The application object will not stay in memory forever, it will get killed. Contrary to popular belief, the app won’t be restarted from scratch. Android will create a new Application object and start the activity where the user was before to give the illusion that the application was never killed in the first place.
If I didn't check on null I would allow a nullpointer to be thrown when calling for example getMaxDistance() on the filter object (if the application object was swiped from the memory by Android)
'Programming' 카테고리의 다른 글
C #을 사용하여 현재 활성 창의 제목을 어떻게 얻습니까? (0) | 2020.08.07 |
---|---|
Firebase에서 데이터를 구조화하는 가장 좋은 방법은 무엇인가요? (0) | 2020.08.07 |
플렉스 항목이 부모 컨테이너의 너비가 아닌 콘텐츠 너비를 갖도록합니다. (0) | 2020.08.07 |
OS X v10.9 (Mavericks)에서 GDB 누락 (0) | 2020.08.07 |
스칼라 대 원시 데이터 유형-같은 것입니까? (0) | 2020.08.07 |