Autore Topic: SharedPreferences & NullPointerException  (Letto 892 volte)

Offline wlf

  • Utente normale
  • ***
  • Post: 359
  • Respect: +8
    • Mostra profilo
  • Dispositivo Android:
    Xperia
SharedPreferences & NullPointerException
« il: 17 Novembre 2014, 10:25:14 CET »
0
Salve,
sto utilizzando le SharedPreferences per salvare i settaggi della mia App; nella onCreate della MainActivity istanzio le mie SharedPreferences  e ne leggo il contenuto:

Codice: [Seleziona]
SharedPreferences  sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
APP_TYPE = sharedPref.getString("type", "0");

APP_TYPE è definito come:
Codice: [Seleziona]
public static String APP_TYPE;
Invece di passare questo valore tramite l'intent dalla MainActivity a quelle successive (put & get) ho preferito dichiarare una variabile statica pubblica.
Dalle activity successive quindi mi capita di testare il lavore inserito:

Codice: [Seleziona]
if (MainActivity.APP_TYPE.equals("0")) {
...
}

Non frequentemente mi capitano degli errori nell'App alla riga sopra indicata del tipo sottostante:

Codice: [Seleziona]
java.lang.NullPointerException
Pratiacmente è come se APP_TYPE non fosse valorizzata, ma come potete vedere nella onCreate della MainActivity la leggo e gli assegno "0" se non dovesse essere presente nelle SharedPreferences.
Ho fatto un esempio con la variabile sopra indicata, ma mi può accadere la stessa cosa anche per altre variabili dichiarate allo stesso identico modo "public static" sempre nalla MainActivity.

Sono a chiedervi quindi se è possibile che ciò accada ed eventualmente il motivo.

Grazie.

« Ultima modifica: 17 Novembre 2014, 10:26:54 CET da wlf »

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 4043
  • keep it simple
  • Respect: +567
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
Re:SharedPreferences & NullPointerException
« Risposta #1 il: 17 Novembre 2014, 11:39:53 CET »
+1
Per questa tua necessità io sceglierei un approccio un po' più complicato, ma decisamente più affidabile.

Estendi l'oggetto Application (non si spiega in un rigo, ma ci dovrebbe essere un tutorial nel forum e ce ne sono diversi sul web)
L'oggetto esteso da Application è di fatto statico e cosa più importante è accessibile da ogni activity con getApplication().
In questo modo puoi metterci dentro le varie variabili "globali" dell'applicazione, senza doverti preoccupare del ciclo di vita delle varie activity.
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline wlf

  • Utente normale
  • ***
  • Post: 359
  • Respect: +8
    • Mostra profilo
  • Dispositivo Android:
    Xperia
Re:SharedPreferences & NullPointerException
« Risposta #2 il: 17 Novembre 2014, 15:06:32 CET »
0
Estendi l'oggetto Application (non si spiega in un rigo, ma ci dovrebbe essere un tutorial nel forum e ce ne sono diversi sul web)
L'oggetto esteso da Application è di fatto statico e cosa più importante è accessibile da ogni activity con getApplication().
In questo modo puoi metterci dentro le varie variabili "globali" dell'applicazione, senza doverti preoccupare del ciclo di vita delle varie activity.

Ok, ma posso accedere alle variabili globali dell'oggetto Application solamente tramite getter/setter? :(

Oppure posso fare come nell'esempio sottostante:

Codice: [Seleziona]
public class myApplication extends Application {
        public static String APP_TYPE;
}

.. poi nell'activity
Codice: [Seleziona]
myApplication.APP_TYPE = sharedPref.getString("type", "0");
e
Codice: [Seleziona]
if (myApplication.APP_TYPE.equals("0")) {
...
}
« Ultima modifica: 17 Novembre 2014, 15:18:33 CET da wlf »

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 4043
  • keep it simple
  • Respect: +567
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
Re:SharedPreferences & NullPointerException
« Risposta #3 il: 17 Novembre 2014, 16:46:51 CET »
+1
A parte che non serve che sia static (può essere una normale variabile), si, una volta ottenuta la reference all'oggetto application, puoi accedervi direttamente (basta che sia public).
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline wlf

  • Utente normale
  • ***
  • Post: 359
  • Respect: +8
    • Mostra profilo
  • Dispositivo Android:
    Xperia
Re:SharedPreferences & NullPointerException
« Risposta #4 il: 17 Novembre 2014, 17:10:01 CET »
0
A parte che non serve che sia static (può essere una normale variabile), si, una volta ottenuta la reference all'oggetto application, puoi accedervi direttamente (basta che sia public).

Ok, tolgo lo static! ;)

Visto che l'appetito vien mangiando sarebbe errato implementare la lettura/scrittura delle SharedPreferences cercando di centralizzarla?

Codice: [Seleziona]
public class myApplication extends Application {
        public String APP_TYPE;
        SharedPreferences sharedPref;
        SharedPreferences.Editor myEditor;

        @Override
        public void onCreate() {
        // TODO Auto-generated method stub
                    super.onCreate();
                sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
                APP_TYPE = sharedPref.getString("type", "0");
                myEditor = sharedPref.edit();
        }

        @Override
        protected void onTerminate() {
                super.onStop();
                    myEditor.putString("type", APP_TYPE);
                    myEditor.commit();
        }
}

Praticamente all'entrata dell'App vengono letti tutti i valori e caricati in variabili globali richiamabili da tutte le activity e alla chiusura vengono riscritti con i valori "corretti.
Ci sono delle controindicazioni a procedere in questo senso?

« Ultima modifica: 20 Novembre 2014, 16:37:01 CET da wlf »

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 4043
  • keep it simple
  • Respect: +567
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
Re:SharedPreferences & NullPointerException
« Risposta #5 il: 17 Novembre 2014, 18:12:31 CET »
+1
Visto che l'appetito vien mangiando sarebbe errato implementare la lettura/scrittura delle SharedPreferences cercando di centralizzarla?

Effettivamente faccio qualcosa del genere anche nelle mie app. Centralizzo nell'oggetto application gli oggetti che poi vengono usati dalle varie activity: per esempio il client http, il databasehelper e la reference alle sharedpreferences. Per non ricrearli ogni volta che cambio activity.

Quasi sicuramente ci sono metodi migliori e questo ha anche qualche controindicazione, però bene o male ho sempre fatto app di bassa complessità e non avevo molta motivazione a fare qualcosa di più complesso.

L'unica cosa che sconsiglio è fare affidamento sull'evento di chiusura dell'app, ma di salvare al più tardi alla chiusura dell'activity. Perchè l'oggetto application di un'app sopravvive alla chiusura dell'app stessa, finchè android non decide di liberarsi anche di quello. Vuol dire che se ad esempio dopo un'ora riavvii l'app, potrebbe essere vivo ancora l'oggetto application di prima, inclusi tutti i dati.
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline wlf

  • Utente normale
  • ***
  • Post: 359
  • Respect: +8
    • Mostra profilo
  • Dispositivo Android:
    Xperia
Re:SharedPreferences & NullPointerException
« Risposta #6 il: 17 Novembre 2014, 18:32:07 CET »
0
Effettivamente faccio qualcosa del genere anche nelle mie app. Centralizzo nell'oggetto application gli oggetti che poi vengono usati dalle varie activity: per esempio il client http, il databasehelper e la reference alle sharedpreferences. Per non ricrearli ogni volta che cambio activity.

Io l'avevo pensato solametne per le SharedPreferences, ma l'idea di centralizzare anche il client http e il databasehelper non sarebbe male, anzi è un ottima idea IMHO. ;)
Potrei chiederti la cortesia di postare un esempio succinto? :)

Citazione
Quasi sicuramente ci sono metodi migliori e questo ha anche qualche controindicazione, però bene o male ho sempre fatto app di bassa complessità e non avevo molta motivazione a fare qualcosa di più complesso.

Mi sfuggono le controindicazioni e quale sia la tecnica migliore ...
In teoria dovrebbe funzionare anche per le App più complesse ...

Citazione
L'unica cosa che sconsiglio è fare affidamento sull'evento di chiusura dell'app, ma di salvare al più tardi alla chiusura dell'activity. Perchè l'oggetto application di un'app sopravvive alla chiusura dell'app stessa, finchè android non decide di liberarsi anche di quello. Vuol dire che se ad esempio dopo un'ora riavvii l'app, potrebbe essere vivo ancora l'oggetto application di prima, inclusi tutti i dati.

Quindi dovrei spostare eventualmente anche la lettura sulla onResume invece che la onCreate?
Oppure più semplicemente dovrei lasciare sulla extentds Application solo le variabili globali e dichiarare un paio di funzioni di lettura/scrittura delle SharedPreferences e dichiarare una classe astratta "extends Activity" nella quale inserire nella onResume la chiamata alla funzione della extends Application di lettura e alla onPause il richiamo alla funzione di scrittura?


Offline wlf

  • Utente normale
  • ***
  • Post: 359
  • Respect: +8
    • Mostra profilo
  • Dispositivo Android:
    Xperia
Re:SharedPreferences & NullPointerException
« Risposta #7 il: 20 Novembre 2014, 16:28:19 CET »
0
Effettivamente faccio qualcosa del genere anche nelle mie app. Centralizzo nell'oggetto application gli oggetti che poi vengono usati dalle varie activity.

Esiste magari qualche esempio da cui trarre ispirazione? Ho provato a cercare qui sul forum ma non ho trovato nessun topic nel quale si dicuta riguardo ad una centralizzazione degli oggetti che vengono utilizzati in modo ricorsivo dalle varie activity. :(
Ogni suggerimento è ben accetto! :)

Citazione
per esempio il client http, il databasehelper e la reference alle sharedpreferences. Per non ricrearli ogni volta che cambio activity.

Mi è abbastanza chiaro per il client http e per le sharedpreferences, probabilmente però ho capito male io, ma per quanto riguarda il database più che il databseheper non bisognerebbe centralizzare il dbAdapter? ;)

--- edit ---
Ho corretto la parte di codice sopra perché non esiste l'onStop() in Application, esiste l'onTerminate(). :)
« Ultima modifica: 20 Novembre 2014, 16:38:28 CET da wlf »

Offline arlabs

  • Utente normale
  • ***
  • Post: 434
  • Respect: +49
    • Mostra profilo
  • Dispositivo Android:
    GalaxyS6, Nexus5
  • Play Store ID:
    AR Labs
  • Sistema operativo:
    Windows 10
Re:SharedPreferences & NullPointerException
« Risposta #8 il: 20 Novembre 2014, 18:24:37 CET »
0
Mi pare che sia scritto di non fare affidamento sulla onTerminate.

Io cmq, forse perché vengo dalla programmazione C++, faccio più uso dei singleton, anche per i settings.
Carico alla creazione della App, e salvo ad ogni onPause di una Activity che può modificare i settings.

Ciao.

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 4043
  • keep it simple
  • Respect: +567
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
Re:SharedPreferences & NullPointerException
« Risposta #9 il: 20 Novembre 2014, 19:12:41 CET »
+1
Esiste magari qualche esempio da cui trarre ispirazione?

Premetto che non è sicuramente il metodo migliore, ma in fondo mi ci trovo bene e mi piace.

Più o meno faccio così:

Codice (Java): [Seleziona]
public class XxxxxxApp extends Application {
   
   // objects
   private SharedPreferences prefs = null;
   private DatabaseHelper dbHelper = null;
   private OkHttpClient client = null;
   // application instance
   private static XxxxxxApp instance = null;
   
   // easy access to instance, avoid call and cast getApplicationContext()
   public static XxxxxxApp getInstance() {
      checkInstance();
      return instance;
   }

   // check app instance
   private static void checkInstance() {
      if (instance==null) {
         LOGE("Cannot create Application instance");
         throw new IllegalStateException("Application not created yet!");
      }
         
   }

   // accessor for SharedPreferences
   public SharedPreferences getPref() {
      if (prefs==null) {
         checkInstance();
         prefs = PreferenceManager.getDefaultSharedPreferences(this);
      }
      return prefs;
   }
   
   // accessor for DatabaseHelper
   public DatabaseHelper getDbHelper() {
      if (dbHelper==null) {
         checkInstance();
         dbHelper = new DatabaseHelper(this);
      }
      return dbHelper;
   }
   
   // accessor for OkHttpClient
   public OkHttpClient getHttpClient() {
      if (client==null) {
         checkInstance();
         client = new OkHttpClient();
         client.setConnectTimeout(10,TimeUnit.SECONDS);
         client.setWriteTimeout(10,TimeUnit.SECONDS);
         client.setReadTimeout(10,TimeUnit.SECONDS);
      }
      return client;
   }

}
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline wlf

  • Utente normale
  • ***
  • Post: 359
  • Respect: +8
    • Mostra profilo
  • Dispositivo Android:
    Xperia
Re:SharedPreferences & NullPointerException
« Risposta #10 il: 21 Novembre 2014, 10:27:01 CET »
0
Mi pare che sia scritto di non fare affidamento sulla onTerminate.

Questo era chiaro, ma ho corretto l'inesattezza per non trarre in errore qualcun'altro che casomai seguisse il thread! ;)

Citazione
Io cmq, forse perché vengo dalla programmazione C++, faccio più uso dei singleton, anche per i settings.
Carico alla creazione della App, e salvo ad ogni onPause di una Activity che può modificare i settings.

Che differenza concreta c'è tra i singleton ed il metodo proposto da Bradipao utilizzando le variabili nella Application invece che nella MainActivity?
Volendo si può comunque fare in modo che i dati vengano caricati i settings nella onCreate dell'Application e salvarli ad ogni onPause delle Activity che possono modificarli.  ;)
Non vedo nessuna differenza nel comportamento ...

Chiedo lumi se sia corretto spostare sempre nella Application il LocationManager per individuare le coordinate GPS; io ora lo utilizzo in più Activity e lo faccio partire nella onResume e blocco nella onPause. Non posso semplicemente utilizzare le coordinate della MainActivity perché casomai uno fa partire l'App e poi va in una sottoactivity transitoria senza coordinate GPS e mette in pausa lo smarpthone, si sposta e poi lancia una sottoActivity facendo l'azione che voglio tracciare, a questo punto se non aggiorno le coordinate mi trovo l'operazione con le coordinate errate della MainActivity. :(
Visto che nella Main l'utente può eseguire una ricerca e gli serve quindi un punto da cui cercare mentre nelle sottoactivity annidate può eseguire delle azioni ho bisogno in almeno 3-4 posti diversi delle coordinate; posso quindi centralizzare anche questo nella Application? :)

Offline arlabs

  • Utente normale
  • ***
  • Post: 434
  • Respect: +49
    • Mostra profilo
  • Dispositivo Android:
    GalaxyS6, Nexus5
  • Play Store ID:
    AR Labs
  • Sistema operativo:
    Windows 10
Re:SharedPreferences & NullPointerException
« Risposta #11 il: 21 Novembre 2014, 14:25:17 CET »
0
La differenza tra Singleton e Application sta solo nel come vuoi strutturare l'architettura software.

Usando il Singleton limiti le dipendenze e disaccoppi due cose che non sono strettamente correlate fra loro.
Se hai una libreria che fa alcune cose, può avere una classe Settings in tale libreria, che salva le preferenze senza aver necessariamente accesso ad una classe Application.


Offline wlf

  • Utente normale
  • ***
  • Post: 359
  • Respect: +8
    • Mostra profilo
  • Dispositivo Android:
    Xperia
Re:SharedPreferences & NullPointerException
« Risposta #12 il: 21 Novembre 2014, 18:02:27 CET »
0
Prendo spunto da questo esempio singleton.

A quanto vedo Application devi comunque istanziarla, poi chiarametne avendo una classe dati separata/disaccoppiata questa potrebbe risultare più chiara. Si potrebbero fare diverse classi, una per i settings, una per l'http client, una per il DbAdapter, una per il GPS listener, etc. Se in un singleton avessi bisogno del contex dovrei passarlo?

Dal mio punto di vista, da inesperto, non ci vedo una grossa differenza.
Accedere alla classe Application che controindicazioni avrebbe? Ti stai forse riferndo al fatto che la classe Application imbottita di diverse variabili di diverso tipo e con diversi metodi potrebbe diventare un guazzabuglio invece con una serie di oggetti più semplici singleton si potrebbe realizzare il tutto in maniera più chiara ed ordinata?


Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 4043
  • keep it simple
  • Respect: +567
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
Re:SharedPreferences & NullPointerException
« Risposta #13 il: 21 Novembre 2014, 18:09:38 CET »
0
A quanto vedo Application devi comunque istanziarla,

Application viene già istanziata in automatico all'apertura dell'app. E' la base di un'app android.
Estendendola aggiungi solamente variabili e funzioni a quella standard.
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline wlf

  • Utente normale
  • ***
  • Post: 359
  • Respect: +8
    • Mostra profilo
  • Dispositivo Android:
    Xperia
Re:SharedPreferences & NullPointerException
« Risposta #14 il: 21 Novembre 2014, 18:32:21 CET »
0
Application viene già istanziata in automatico all'apertura dell'app. E' la base di un'app android.
Estendendola aggiungi solamente variabili e funzioni a quella standard.

Io mi riferivo al fatto che deve ottenere l'istanziarla di Application anche nell'Activity per poter utilizzare poi il metodo in application e utilizzare i metodi della singleton ... oppure probabilmente l'esempio che ho trovato io è fuorviante ed ha contribuito a farmi dell'altra confusione! :)