Problèmes avec un ListParameter

… qui fait planter l'application

Le problème exposé dans ce sujet a été résolu.

Bonjour,

Je suis en train de mettre en place un écran de paramètres sur mon application Android, en utilisant la méthode préconisée par Google, mais je rencontre quelques difficultés avec un ListParameter : actuellement, lorsque je clique sur le bouton qui doit afficher ma liste, je tombe dans une NullPointerException que je ne comprends pas trop.

Ci-dessous mes codes. Qu'est-ce que je fais mal ? :-/

Merci d'avance

Classe MainSettingsActivity

Elle est totalement générée par Android Studio. J'ai simplement enlevé du code qui concernait Honeycomb, puisque mon application n'est compatible qu'à partir de KitKat.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package tk.deuchnord.phonejuicechecker;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.support.v7.app.ActionBar;
import android.preference.PreferenceFragment;
import android.preference.PreferenceManager;
import android.preference.RingtonePreference;
import android.text.TextUtils;
import android.view.MenuItem;

import java.util.List;

/**
 * A {@link PreferenceActivity} that presents a set of application settings. On
 * handset devices, settings are presented as a single list. On tablets,
 * settings are split by category, with category headers shown to the left of
 * the list of settings.
 * <p/>
 * See <a href="http://developer.android.com/design/patterns/settings.html">
 * Android Design: Settings</a> for design guidelines and the <a
 * href="http://developer.android.com/guide/topics/ui/settings.html">Settings
 * API Guide</a> for more information on developing a Settings UI.
 */
public class MainSettingsActivity extends AppCompatPreferenceActivity {
    /**
     * A preference value change listener that updates the preference's summary
     * to reflect its new value.
     */
    private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() {
        @Override
        public boolean onPreferenceChange(Preference preference, Object value) {
            String stringValue = value.toString();

            if (preference instanceof ListPreference) {
                // For list preferences, look up the correct display value in
                // the preference's 'entries' list.
                ListPreference listPreference = (ListPreference) preference;
                int index = listPreference.findIndexOfValue(stringValue);

                // Set the summary to reflect the new value.
                preference.setSummary(
                        index >= 0
                                ? listPreference.getEntries()[index]
                                : null);

            } else {
                // For all other preferences, set the summary to the value's
                // simple string representation.
                preference.setSummary(stringValue);
            }
            return true;
        }
    };

    /**
     * Helper method to determine if the device has an extra-large screen. For
     * example, 10" tablets are extra-large.
     */
    private static boolean isXLargeTablet(Context context) {
        return (context.getResources().getConfiguration().screenLayout
                & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE;
    }

    /**
     * Binds a preference's summary to its value. More specifically, when the
     * preference's value is changed, its summary (line of text below the
     * preference title) is updated to reflect the value. The summary is also
     * immediately updated upon calling this method. The exact display format is
     * dependent on the type of preference.
     *
     * @see #sBindPreferenceSummaryToValueListener
     */
    private static void bindPreferenceSummaryToValue(Preference preference) {
        // Set the listener to watch for value changes.
        preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);

        // Trigger the listener immediately with the preference's
        // current value.
        sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
                PreferenceManager
                        .getDefaultSharedPreferences(preference.getContext())
                        .getString(preference.getKey(), ""));
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setupActionBar();
        addPreferencesFromResource(R.xml.pref_general);
    }

    /**
     * Set up the {@link android.app.ActionBar}, if the API is available.
     */
    private void setupActionBar() {
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            // Show the Up button in the action bar.
            actionBar.setDisplayHomeAsUpEnabled(true);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean onIsMultiPane() {
        return isXLargeTablet(this);
    }
}

Fichier pref_general.xml

Ce fichier donne le layout de la page de configuration. Si la CheckBoxPreference fonctionne bien, le ListPreference fait planter l'application lorsque je clique dessus.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">

    <PreferenceCategory
        android:title="@string/notifications">

        <ListPreference
            android:key="notification-low-battery"
            android:title="@string/lowBatteryNotif"
            android:dialogTitle="@string/dialogLowBattery"
            android:entries="@array/lowBatteryEntries"
            android:entryValues="@array/lowBatteryEntryValues"
            android:defaultValue="20" />

        <CheckBoxPreference
            android:key="notification-full-battery"
            android:title="@string/fullBatteryNotif"
            android:summaryOn="@string/fullBatteryNotifSummaryOn"
            android:summaryOff="@string/fullBatteryNotifSummaryOff"
            android:defaultValue="false" />

    </PreferenceCategory>

</PreferenceScreen>

Fichier strings.xml

Ce fichier contient les différentes chaînes de caractères de l'application en anglais. Je l'ai tronqué pour n'avoir que ce qui concerne les paramètres.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<resources>
    <!-- ... -->

    <!-- Strings related to Settings -->

    <string name="notifications">Notifications</string>
    <string name="lowBatteryNotif">Low battery</string>
    <string name="lowBatteryNotifSummaryPrefix">Alert me when the battery level reaches </string>
    <string name="lowBatteryNotifSummarySufix">%.</string>
    <string name="lowBatteryNotifSummaryNever">Don\'t alert me when the battery level is low</string>
    <string name="dialogLowBattery">"M'alerter quand la batterie atteint..."</string>

    <string name="fullBatteryNotif">Full battery</string>
    <string name="fullBatteryNotifSummaryOn">Notify me when the battery is full.</string>
    <string name="fullBatteryNotifSummaryOff">Don\'t notify me when the battery is full.</string>

    <string-array name="lowBatteryEntries">
        <item>Never</item>
        <item>10%</item>
        <item>15%</item>
        <item>20%</item>
        <item>25%</item>
        <item>30%</item>
        <item>40%</item>
        <item>50%</item>
    </string-array>

    <string-array name="lowBatteryEntryValues">
        <item>-1</item>
        <item>10</item>
        <item>15</item>
        <item>20</item>
        <item>25</item>
        <item>30</item>
        <item>40</item>
        <item>50</item>
    </string-array>
</resources>

LogCat

Ci-dessous, le log de l'exception levée au moment où je clique sur l'item ListPreference :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
12-20 16:42:01.541 4118-4118/tk.deuchnord.phonejuicechecker E/AndroidRuntime: FATAL EXCEPTION: main
                                                                              Process: tk.deuchnord.phonejuicechecker, PID: 4118
                                                                              java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.Object.toString()' on a null object reference
                                                                                  at android.widget.ArrayAdapter.createViewFromResource(ArrayAdapter.java:394)
                                                                                  at android.widget.ArrayAdapter.getView(ArrayAdapter.java:362)
                                                                                  at android.widget.AbsListView.obtainView(AbsListView.java:2387)
                                                                                  at android.widget.ListView.measureHeightOfChildren(ListView.java:1270)
                                                                                  at android.widget.ListView.onMeasure(ListView.java:1182)
                                                                                  at android.view.View.measure(View.java:17496)
                                                                                  at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5466)
                                                                                  at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1438)
                                                                                  at android.widget.LinearLayout.measureVertical(LinearLayout.java:724)
                                                                                  at android.widget.LinearLayout.onMeasure(LinearLayout.java:615)
                                                                                  at android.view.View.measure(View.java:17496)
                                                                                  at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5466)
                                                                                  at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1438)
                                                                                  at android.widget.LinearLayout.measureVertical(LinearLayout.java:724)
                                                                                  at android.widget.LinearLayout.onMeasure(LinearLayout.java:615)
                                                                                  at android.view.View.measure(View.java:17496)
                                                                                  at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5466)
                                                                                  at android.widget.FrameLayout.onMeasure(FrameLayout.java:430)
                                                                                  at android.view.View.measure(View.java:17496)
                                                                                  at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5466)
                                                                                  at android.widget.FrameLayout.onMeasure(FrameLayout.java:430)
                                                                                  at android.view.View.measure(View.java:17496)
                                                                                  at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5466)
                                                                                  at android.widget.FrameLayout.onMeasure(FrameLayout.java:430)
                                                                                  at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2636)
                                                                                  at android.view.View.measure(View.java:17496)
                                                                                  at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2031)
                                                                                  at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1168)
                                                                                  at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1400)
                                                                                  at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1078)
                                                                                  at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5875)
                                                                                  at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767)
                                                                                  at android.view.Choreographer.doCallbacks(Choreographer.java:580)
                                                                                  at android.view.Choreographer.doFrame(Choreographer.java:550)
                                                                                  at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753)
                                                                                  at android.os.Handler.handleCallback(Handler.java:739)
                                                                                  at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                                  at android.os.Looper.loop(Looper.java:135)
                                                                                  at android.app.ActivityThread.main(ActivityThread.java:5349)
                                                                                  at java.lang.reflect.Method.invoke(Native Method)
                                                                                  at java.lang.reflect.Method.invoke(Method.java:372)
                                                                                  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:908)
                                                                                  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:703)
+0 -0

Salut Jérôme,

1
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.Object.toString()' on a null object reference

Généralement, cette erreur signifie qu'une de tes chaines de caractères n'a pas pu être récupérée à l'intérieur de ta liste en tant que chaine de caractères et donc, n'a pas pu initialiser une variable sur laquelle un toString() a été appelé.

Je testerais 2 choses, toutes les 2 dans la ressource lowBatteryEntryValues :

  • Changer la valeur -1 par une autre.
  • Mettre des guillemets dans les items de l'array.
+1 -0

Salut,

Merci pour ton aide, Andr0, c'était bien les guillemets qu'il fallait ajouter sur les valeurs du <string-array name="lowBatteryEntries"> (en anglais et en français) :)

Par contre, je serais curieux de savoir pourquoi il m'a fallu en ajouter ici, alors que ça ne m'était pas utile jusque là :-°

+0 -0

Salut,

Content que ton problème soit réglé. Une explication plausible est la détection du type. Dans ta ressource, tu définis que des entiers. Le SDK Android l'a peu-être détecté et n'a donc pas construit une liste de String comme il aurait dû le faire.

Bien entendu, je n'en suis pas certain mais ça me semble la raison la plus logique.

+0 -0

Je ne suis pas sûr : getEntries est la liste de string qui contient les valeurs "lisibles pour des êtres humains", et il n'y a que sur celui-là que j'ai dû le faire, pas sur l'autre liste qui ne contient que des nombres (d'ailleurs, -1 est une valeur qui semble fonctionner sans problème) :-/

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte