BB10: ListView et problèmes de recyclage

Qu’est ce que le recyclage?

Pour afficher une liste d’objets, on peut tout simplement tous les ajouter à l’écran, simple et efficace. Sur BlackBerry Java on pouvait créer des listes de milliers d’éléments sans soucis de performance. Mais quand les listes deviennent complexes ou infinies, la mémoire vive peut vite saturer.

Il faut alors ne charger que les cellules visibles à l’écran, plus les prochaines à venir. Lorsque l’on scrolle vers le bas, la liste va créer à la volée de nouvelles cellules, tandis que les cellules du dessus sont supprimées.
Mais pourquoi ne pas tout simplement récupérer les cellules du dessus pour les remettre en bas avec les nouvelles données? Ce concept est appelé le recyclage et est fortement utilisé dans beaucoup de frameworks.

SDK BB10: ListItemManager et le recyclage des Listview

Reproduire le problème

Lancer Appworld sur votre BB10 avec une appli comportant de nombreux commentaires. Scrollez dans les commentaires et remonter en haut. Vous ne voyez pas un truc étrange? Là où il y avait 4 étoiles il y en maintenant 5 (par exemple).

C’est typiquement une erreur provenant d’une liste mal recyclée. Pour comprendre d’où elle vient, il faut comprendre comment l’updateItem (cf shéma ci-dessus) fonctionne. Prenez ce code:

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
ListView {
dataModel: XmlDataModel { source: "model.xml" }
listItemComponents: [
ListItemComponent {
type: "contact"

Container {
id: itemRoot

ImageView {
onCreationCompleted: {
if(ListItemData.value == 0){
image = "asset:///images/starOff.png"
}
else{
image = "asset:///images/starOn.png"
}
}
}

Label { text: ListItemData.name }
}
}
]
}

L’essence de l’erreur vient du traitement réalisé pendant le onCreationCompleted: cette méthode n’est appelée qu’à la création de la cellule. Le Label, quant à lui est bien mis à jour: il faut dont toujours privilégier le binding.

Solution

Très bien, nous utilisons donc juste le mauvais slot. Il suffit alors de récupérer le signal datachanged dans le code de la cellule, et modifier l’image ici:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Container {
id: itemRoot
ImageView { id: myImage}
Label { text: ListItemData.name }

ListItem.onDataChanged: {
if(ListItemData.value == 0){
myImage.image = "asset:///images/starOff.png"
}
else{
myImage.image = "asset:///images/starOn.png"
}
}
}

onDataChanged sera appelé dès que la donnée est mise à jour, soit au début et à chaque recyclage.

Ambientlands

Here is my entries for the 100-lines-or-less-js ArcGIS entry.
I definitly wasn’t doing what was expecting, trying to code a full feature webpage instead of a nice autonomous component. Must it was quite fun to code.

Discover a world of music on a map

This app uses both the ArcGIS API for JavaScript and the Souncloud API, to discover the music from the world while browsing a map.

3 Modes of discovering are implemented

  • Travel&Discover: Navigate freely on the map. The local music of the area will automatically plays
  • Play On Click: Disable navigation and force the app to play only the music you have chosen when you select it from an icon’s popup
  • Registered Travel: Display the menu to let you choose between the available travels. Just see and listen!

The music are subject to be changed or removed from soundcloud, so I guess this tools with stop working properly within some years. It’s a shame that they removed their geolocation API disabling the posibility to dynamically select the data.

You can find the 100-line code in https://github.com/bdelville/100-lines-or-less-js/blob/master/ambientlands/js/ambientlands.js