Paylaşılan Tercihlere erişim UI İş Parçacığından yapılmalı mı?


113

Gingerbread'in yayınlanmasıyla, yeni API'lerden bazıları üzerinde deneyler yapıyorum, bunlardan biri StrictMode .

Uyarılardan birinin bunun için olduğunu fark ettim getSharedPreferences().

Bu uyarıdır:

StrictMode policy violation; ~duration=1949 ms: android.os.StrictMode$StrictModeDiskReadViolation: policy=23 violation=2

ve getSharedPreferences()UI iş parçacığında yapılan bir çağrı için veriliyor .

Meli SharedPreferenceserişebilir ve gerçekten UI iş parçacığı kapalı yapılacak değişiklikler?


Her zaman tercih işlemlerini UI iş parçacığında yaptım. Sanırım bir IO operasyonu olduğu için mantıklı geliyor
Falmarri

Yanıtlar:


184

Onunla zaten oynadığına sevindim!

Dikkat edilmesi gereken bazı şeyler: (tembel madde işareti biçiminde)

  • Sorunlarınızın en kötüsü buysa, uygulamanız muhtemelen iyi bir noktadadır. :) Yazılar genellikle okumalardan daha yavaştır, bu nedenle commit () yerine SharedPreferenced $ Editor.apply () kullandığınızdan emin olun. apply () GB ve zaman uyumsuz olarak yenidir (ancak her zaman güvenlidir, yaşam döngüsü geçişlerine dikkat eder). GB + 'da koşullu olarak apply () ve Froyo veya altında commit () çağırmak için yansımayı kullanabilirsiniz. Bunun nasıl yapılacağına dair örnek kod içeren bir blog gönderisi yapacağım.

Yüklemeyle ilgili olsa da ...

  • Paylaşılan Tercihler, yüklendikten sonra tekildir ve işlem genelinde önbelleğe alınır. bu yüzden onu olabildiğince erken yüklemek istersiniz, böylece ihtiyacınız olmadan önce hafızaya alırsınız. (Küçük olduğu varsayılarak, basit bir XML dosyası olan SharedPreferences kullanıyorsanız olması gerektiği gibi ...) Gelecekte bazı kullanıcılar bir düğmeyi tıkladığında hata yapmak istemezsiniz.

  • ancak context.getSharedPreferences (...) 'ı her çağırdığınızda, destekleyici XML dosyası değiştirilip değiştirilmediğini görmek için stat'lenir, bu nedenle yine de UI olayları sırasında bu istatistiklerden kaçınmak isteyeceksiniz. Bir istatistik normalde hızlı olmalı (ve genellikle önbelleğe alınmalıdır), ancak yaffs eşzamanlılık konusunda pek bir şeye sahip değildir (ve birçok Android cihazı yaffs üzerinde çalışır ... Droid, Nexus One, vb.), Bu nedenle diskten kaçınırsanız , diğer uçuş sırasında veya bekleyen disk işlemlerinin gerisinde kalmaktan kaçınırsınız.

  • bu nedenle, muhtemelen onCreate () işleminiz sırasında SharedPreferences'ı yüklemek ve istatistikten kaçınarak aynı örneği yeniden kullanmak isteyeceksiniz.

  • ancak onCreate () sırasında tercihlerinize yine de ihtiyacınız yoksa, bu yükleme süresi uygulamanızın başlangıcını gereksiz yere geciktirir, bu nedenle genellikle .set için yeni bir iş parçacığı başlatan bir FutureTask <SharedPreferences> alt sınıfına sahip olmak daha iyidir. () FutureTask alt sınıflarının değeri. Sonra ne zaman ihtiyacınız olursa FutureTask <SharedPreferences> üyesine bakın ve .get () yapın. Bunu Honeycomb'daki perde arkasında şeffaf bir şekilde ücretsiz yapmayı planlıyorum. Bu alandaki en iyi uygulamaları gösteren bazı örnek kodlar yayınlamaya çalışacağım.

Önümüzdeki hafta (lar) da StrictMode ile ilgili konularda gelecek gönderiler için Android Developers bloguna göz atın.


Vay canına, doğrudan kaynaktan bu kadar net bir cevap almayı beklemiyordum! Çok teşekkürler!
cottonBallPaws

9
Bu harika yazının yeni okuyucularının yararı için, yukarıda @Brad Fitzpatrick tarafından belirtilen blog gönderisinin bağlantısını aşağıda bulabilirsiniz: android geliştiricisinin Brad tarafından sıkı mod hakkındaki blog yazısı . Gönderide ayrıca, paylaşılan tercihleri ​​depolamak için android sürümüne dayalı olarak apply (gingerbread'den itibaren) veya commit'i (froyo) kullanmak için örnek kodun bir bağlantısı vardır: [koşullu olarak uygula veya kaydet] ( code.google.com/p/zippy-android / source / browse / trunk / samples /… )
tony m

4
Bu hala ICS \ JB ile alakalı mı?
ekatz

5

Paylaşılan tercihlere erişim, flash bellekten okundukları için epey zaman alabilir. Çok okur musun? Belki o zaman farklı bir format kullanabilirsiniz, örneğin bir SQLite veritabanı.

Ancak StrictMode kullanarak bulduğunuz her şeyi düzeltmeyin. Veya belgeleri alıntılamak için:

Ancak StrictMode'un bulduğu her şeyi düzeltmek zorunda hissetmeyin. Özellikle, normal etkinlik yaşam döngüsü sırasında birçok disk erişimi durumu genellikle gereklidir. Kazara yaptığınız şeyleri bulmak için StrictMode kullanın. UI iş parçacığındaki ağ istekleri neredeyse her zaman bir sorundur.


6
Ancak SQLite aynı zamanda flash depolamadan okunması gereken bir dosya değil - tercihler dosyasına kıyasla daha büyük ve daha karmaşık bir dosya. Tercihlerle ilişkili veri miktarı için, bir tercihler dosyasının bir SQLite veritabanından çok daha hızlı olacağını varsayıyorum.
Tom

Bu doğru. Brad'in daha önce de bahsettiği gibi, bu neredeyse her zaman sorun değildir - ve aynı zamanda SharedPreferences'ı bir kez yüklemenin (belki bir FutureTask kullanan bir İş Parçacığında bile) ve tek bir örneğe olası herhangi bir erişim için tutmanın iyi bir fikir olduğunu belirtiyor.
mreichelt

5

Brad'in cevabıyla ilgili bir incelik: Paylaşılan Tercihleri ​​onCreate () 'e yükleseniz bile, bitişlerde paylaşılan dosya tercihini okuyana kadar (arka planda) getString () vb. Blok olduğundan muhtemelen arka plan iş parçacığındaki değerleri okumalısınız:

public String getString(String key, String defValue) {
    synchronized (this) {
        awaitLoadedLocked();
        String v = (String)mMap.get(key);
        return v != null ? v : defValue;
    }
}

edit () aynı şekilde engeller, ancak apply () ön plan iş parçacığında güvenli görünüyor.

(BTW bunu buraya yazdığım için üzgünüm. Bunu Brad'in cevabına bir yorum olarak koyardım, ancak yeni katıldım ve bunu yapmak için yeterli itibarım yok.)


1

Bunun eski bir soru olduğunu biliyorum ama yaklaşımımı paylaşmak istiyorum. Uzun okuma sürelerim vardı ve paylaşılan tercihler ile küresel uygulama sınıfının bir kombinasyonunu kullandım:

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 (uygulamanızda ilk çağrılan etkinlik):

LocalPreference.getLocalPreferences(this);

Açıklanan adımlar:

  1. Ana aktivite getLocalPreferences (this) -> çağırır bu, tercihlerinizi okuyacak, uygulama sınıfınızdaki filtre nesnesini ayarlayacak ve onu döndürecektir.
  2. GetLocalPreferences () işlevini uygulamada başka bir yerde tekrar çağırdığınızda, önce çok daha hızlı olan uygulama sınıfında bulunup bulunmadığını kontrol eder.

NOT: DAİMA bir uygulama geniş değişkeninin NULL'den farklı olup olmadığını kontrol edin, neden -> http://www.developerphil.com/dont-store-data-in-the-application-object/

Uygulama nesnesi sonsuza kadar bellekte kalmayacak, öldürülecektir. Yaygın inanışın aksine, uygulama sıfırdan yeniden başlatılmayacak. Android, yeni bir Uygulama nesnesi oluşturacak ve uygulamanın ilk etapta asla öldürülmediği yanılsamasını vermek için kullanıcının daha önce bulunduğu etkinliği başlatacaktır.

Boş değeri kontrol etmediysem, örneğin filtre nesnesinde getMaxDistance () çağırırken bir nullpointer atılmasına izin verirdim (uygulama nesnesi Android tarafından bellekten kaydırıldıysa)


0

SharedPreferences sınıfı, diskteki XML dosyalarının içinde bazı okur ve yazar, bu nedenle tıpkı diğer IO işlemleri gibi bu da engelliyor olabilir. Şu anda SharedPreferences'da depolanan veri miktarı, API çağrıları tarafından tüketilen zamanı ve kaynağı etkiler. Minimum miktarda veri için, verileri almak / koymak birkaç milisaniye (hatta bazen bir milisaniyeden daha az) meselesidir. Ancak bir uzmanın bakış açısından, API çağrılarını arka planda yaparak performansı artırmak önemli olabilir. Eşzamansız bir SharedPreferences için Datum kitaplığına bakmanızı öneririm .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.