Domanda

Con il rilascio di Gingerbread, ho avuto modo di sperimentare con alcuni dei nuovi API, uno dei quali è StrictMode .

ho notato che una delle avvertenze è per getSharedPreferences().

E 'il monito:

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

ed è dato per una chiamata getSharedPreferences() compiuti nel thread UI.

Qualora l'accesso SharedPreferences e cambia davvero essere fatti fuori dal thread UI?

È stato utile?

Soluzione

Sono contento che si sta già giocando con essa!

Alcune cose da notare: (in forma di proiettile pigro)

  • Se questo è il peggiore dei vostri problemi, la vostra applicazione è probabilmente in un buon posto. :) Scrive sono generalmente più lento di legge, però, in modo da essere sicuri che si sta utilizzando SharedPreferenced $ Editor.apply () al posto di commit (). apply () è nuovo in GB e asincrone (ma sempre sicura, attenta delle transizioni del ciclo di vita). È possibile utilizzare la reflection per chiamare condizionalmente applicare () in GB + e commit () su Froyo o al di sotto. Farò un blogpost con codice di esempio di come fare questo.

Per quanto riguarda il carico, anche se ...

  • una volta caricato, SharedPreferences sono single e cache di processo a livello. così si vuole ottenere è caricato il più presto possibile in modo da avere in memoria prima ne avete bisogno. (Ammesso che sia piccolo, come dovrebbe essere se si sta utilizzando SharedPreferences, un semplice file XML ...) Non si vuole a criticare nel tempo futuro, qualche utente fa clic su un pulsante.

  • ma ogni volta che si chiama context.getSharedPreferences (...), il file XML supporto è stat'd per vedere se è cambiato, quindi ti consigliamo di evitare di quelle statistiche durante gli eventi di interfaccia utente in ogni caso. Uno stat dovrebbe di norma essere veloce (e spesso memorizzata nella cache), ma YAFFS non ha molto in termini di concorrenza (e un sacco di dispositivi Android girare su YAFFS ... Droid, Nexus One, ecc), quindi se si evita di disco , si evita di rimanere bloccati dietro altri in volo o in attesa di operazioni su disco.

  • per cui è probabile desidera caricare le SharedPreferences durante l'onCreate () e ri-utilizzare la stessa istanza, evitando la stat.

  • , ma se non avete bisogno le preferenze in ogni caso durante onCreate (), che il tempo di caricamento è di stallo della tua app start-up inutilmente, quindi è generalmente meglio avere qualcosa di simile a un FutureTask sottoclasse che prende il via un nuovo filo di .SET () il valore del sottoclassi FutureTask. Poi basta occhiata tua FutureTask 's membro ogni volta che ne avete bisogno e .get () esso. Ho intenzione di fare questo libero dietro le quinte a nido d'ape, in modo trasparente. Cercherò di rilasciare alcuni esempi di codice che spettacoli migliori pratiche in questo settore.

Controlla il blog Android Developers per le prossime messaggi su argomenti StrictMode-correlati nella prossima settimana (s).

Altri suggerimenti

Accesso alle preferenze condivise può richiedere molto tempo, perché vengono letti dalla memoria flash. Avete letto un sacco? Forse si potrebbe utilizzare un formato diverso, allora, ad esempio, un database SQLite.

Ma non risolvono tutto ciò che trovate utilizzando StrictMode. O per citare la documentazione:

  

Ma non si sentono in dovere di risolvere tutto che trova StrictMode. In particolare, molti casi di accesso al disco sono spesso necessari durante il normale ciclo di vita attività. Usa StrictMode per trovare cose che hai fatto per caso. richieste di rete sul thread UI sono quasi sempre un problema, però.

Una sottigliezza su La risposta di Brad: anche se si carica lo SharedPreferences in onCreate (), probabilmente si dovrebbe comunque leggere valori sul thread in background, perché getString (), ecc blocco fino a quando la lettura del preferenza file condiviso in finiture (su un thread in background ):

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

modifica () blocca anche allo stesso modo, anche se si applicano () sembra essere sicuro sul thread in primo piano.

(BTW dispiace mettere questo qui. Mi avrebbe messo questo come un commento alla risposta di Brad, ma ho appena aderito e non hanno abbastanza reputazione per farlo.)

So che questa è una vecchia questione, ma voglio condividere il mio approccio. Avevo lunga lettura volte e utilizzato una combinazione di preferenze condivise e la classe di applicazione globale:

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 (attività che vengono chiamati prima nell'applicazione):

LocalPreference.getLocalPreferences(this);

Passi spiegato:

  1. L'attività principale chiama getLocalPreferences (questo) -.> Questo leggerà le tue preferenze, impostare l'oggetto filtro nella classe di applicazione e lo restituisce
  2. Quando si chiama il getLocalPreferences () la funzione di nuovo da qualche altra parte nella domanda di esso prima controlla se non è disponibile nella classe di applicazione, che è molto più veloce.

Nota: sempre controllare se una variabile di ampia applicazione è diverso da NULL, la ragione -> http://www.developerphil.com/dont-store-data-in-the-application-object/

  

L'oggetto applicazione non rimarrà nella memoria per sempre, otterrà ucciso. Contrariamente alla credenza popolare, l'applicazione non verrà riavviato da zero. Android sarà creare un nuovo oggetto Application e avviare l'attività in cui l'utente era prima per dare l'illusione che l'applicazione non è mai stato ucciso, in primo luogo.

Se non ho controllato sul nulla mi avrebbe permesso un nullpointer per essere gettato quando si chiama per esempio getMaxDistance () sull'oggetto filtro (se l'oggetto applicazione è stata fregato dalla memoria da Android)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top