[ListView] ListView personnalisée avec tri alphabétique
Bonjour à tous,
Je rencontre quelques difficultés pour mettre en place une listeView dans laquelle les éléments sont rangés par ordre alphabétique. Ce que je veux faire, dans ce cas, c'est lire un fichier xml contenant des informations sur des musiques, puis les classé par ordre alphabétique en affichant le nom et le genre. Le tout séparé en section (comme pour les contacts).
Pour cela, j'ai donc deux layouts, et deux Adapter personnalisés. Un pour gérer les sections, un autre pour l'affichage de la liste avec les informations personnalisé. En faisant des tests, j'ai essayé d'afficher une liste simple avec des sections, cela fonctionne. J'ai également essayé d'afficher ma liste avec les infos que je veux, ça marche aussi. Par contre, lorsque je combine, les deux, j'ai une erreur d'exécution lorsque j'essaye de scroller dans la liste. Pourtant, elle s'affiche correctement au lancement de l'application (et avec l'aspect voulu).
Voici le code que j'utilise. D'abord l'Adapter qui permet de gérer les sections :
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 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
|
abstract public class MusicAdapter extends BaseAdapter{
abstract protected View getHeaderView(String caption, int index,
View convertView, ViewGroup parent);
private List<Section> sections = new ArrayList<Section>();
private static int TYPE_SECTION_HEADER = 0;
public MusicAdapter() {
super();
}
public void addSection(String caption, ItemAdapter adapter){
sections.add(new Section(caption, adapter));
}
public Object getItem(int position){
for (Section section : this.sections){
if (position == 0){
return section;
}
int size = section.adapter.getCount() + 1;
if (position < size){
return section.adapter.getItem(position - 1);
}
position -= size;
}
return null;
}
public int getCount(){
int total = 0;
for (Section section : this.sections){
total += section.adapter.getCount() + 1;
}
return total;
}
public int getItemViewType(int position){
int typeOffset = TYPE_SECTION_HEADER + 1;
for (Section section : this.sections) {
if (position == 0) {
return (TYPE_SECTION_HEADER);
}
int size = section.adapter.getCount() + 1;
if (position < size) {
return (typeOffset + section.adapter
.getItemViewType(position - 1));
}
position -= size;
typeOffset += section.adapter.getViewTypeCount();
}
return -1;
}
public boolean areAllItemsSelectable(){
return false;
}
public boolean isEnabled(int position) {
return (getItemViewType(position) != TYPE_SECTION_HEADER);
}
@Override
public View getView(int position, View convertView, ViewGroup parent){
int sectionIndex = 0;
for (Section section : this.sections){
if (position == 0){
return (getHeaderView(section.caption, sectionIndex, convertView, parent));
}
int size = section.adapter.getCount() + 1;
if (position < size){
return (section.adapter.getView(position - 1, convertView,
parent));
}
position -= size;
sectionIndex++;
}
return null;
}
@Override
public long getItemId(int position){
return position;
}
class Section {
String caption;
ItemAdapter adapter;
Section(String caption, ItemAdapter adapter) {
this.caption = caption;
this.adapter = adapter;
}
}
} |
L'Adapter pour l'affichage d'une listView personnalisée :
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 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
|
public class ItemAdapter extends BaseAdapter{
private ListeMusicContainer<Music> mList;
private LayoutInflater mInflater;
public ItemAdapter(Context context, ListeMusicContainer<Music> musics){
mInflater = LayoutInflater.from(context);
mList = musics;
}
@Override
public int getCount() {
return mList.size();
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null){
convertView = mInflater.inflate(R.layout.list_item, null);
holder = new ViewHolder();
holder.nom = (TextView) convertView.findViewById(R.id.nomAlbum);
holder.genre = (TextView) convertView.findViewById(R.id.genreAlbum);
convertView.setTag(holder);
}
else{
holder = (ViewHolder) convertView.getTag();
}
holder.nom.setText(mList.getItem(position).getNom());
holder.genre.setText(mList.getItem(position).getGenre());
return convertView;
}
static class ViewHolder{
TextView nom;
TextView genre;
}
} |
Et enfin, l'activité qui est censé faire l'affichage :
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 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
|
public class TestView extends ListActivity {
/** Called when the activity is first created. */
private ListView mListView;
private static String[] items;
private XmlDataParser mParser;
private ListeMusicContainer<Music> mList;
private MusicAdapter mAdapter = new MusicAdapter() {
protected View getHeaderView(String caption, int index,
View convertView, ViewGroup parent) {
TextView result = (TextView) convertView;
if (convertView == null) {
result = (TextView) getLayoutInflater().inflate(
R.layout.header, null);
}
result.setText(caption);
return (result);
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mParser = new XmlDataParser();
mList = mParser.parseXml(this);
ListeMusicContainer<Music> groupe = new ListeMusicContainer<Music>();
String currLetter = null;
for (int i = 0; i < mList.size(); i++){
if (!mList.getItem(i).getLabel().equalsIgnoreCase(currLetter) && currLetter != null){
mAdapter.addSection(mList.getItem(i).getLabel().toUpperCase(), new ItemAdapter(this, groupe));
groupe = new ListeMusicContainer<Music>();
currLetter = mList.getItem(i).getLabel();
}
if (currLetter == null){
currLetter = mList.getItem(i).getLabel();
}
groupe.addData(mList.getItem(i));
}
setListAdapter(mAdapter);
}
} |
J'obtiens les log suivants avec logcat au moment du plantage :
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 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
|
I/ActivityManager( 42): Displayed activity com.view/.TestView: 1480 ms (total
1480 ms)
D/dalvikvm( 975): GC_EXTERNAL_ALLOC freed 1214 objects / 78504 bytes in 96ms
D/AndroidRuntime( 975): Shutting down VM
W/dalvikvm( 975): threadid=1: thread exiting with uncaught exception (group=0x4
001d800)
E/AndroidRuntime( 975): FATAL EXCEPTION: main
E/AndroidRuntime( 975): java.lang.NullPointerException
E/AndroidRuntime( 975): at com.view.ItemAdapter.getView(ItemAdapter.java
:51)
E/AndroidRuntime( 975): at com.view.MusicAdapter.getView(Music
Adapter.java:91)
E/AndroidRuntime( 975): at android.widget.AbsListView.obtainView(AbsList
View.java:1294)
E/AndroidRuntime( 975): at android.widget.ListView.makeAndAddView(ListVi
ew.java:1727)
E/AndroidRuntime( 975): at android.widget.ListView.fillDown(ListView.jav
a:652)
E/AndroidRuntime( 975): at android.widget.ListView.fillGap(ListView.java
:623)
E/AndroidRuntime( 975): at android.widget.AbsListView.trackMotionScroll(
AbsListView.java:2944)
E/AndroidRuntime( 975): at android.widget.AbsListView.onTouchEvent(AbsLi
stView.java:2065)
E/AndroidRuntime( 975): at android.widget.ListView.onTouchEvent(ListView
.java:3315)
E/AndroidRuntime( 975): at android.view.View.dispatchTouchEvent(View.jav
a:3766)
E/AndroidRuntime( 975): at android.view.ViewGroup.dispatchTouchEvent(Vie
wGroup.java:897)
E/AndroidRuntime( 975): at android.view.ViewGroup.dispatchTouchEvent(Vie
wGroup.java:936)
E/AndroidRuntime( 975): at android.view.ViewGroup.dispatchTouchEvent(Vie
wGroup.java:936)
E/AndroidRuntime( 975): at android.view.ViewGroup.dispatchTouchEvent(Vie
wGroup.java:936)
E/AndroidRuntime( 975): at com.android.internal.policy.impl.PhoneWindow$
DecorView.superDispatchTouchEvent(PhoneWindow.java:1671)
E/AndroidRuntime( 975): at com.android.internal.policy.impl.PhoneWindow.
superDispatchTouchEvent(PhoneWindow.java:1107)
E/AndroidRuntime( 975): at android.app.Activity.dispatchTouchEvent(Activ
ity.java:2086)
E/AndroidRuntime( 975): at com.android.internal.policy.impl.PhoneWindow$
DecorView.dispatchTouchEvent(PhoneWindow.java:1655)
E/AndroidRuntime( 975): at android.view.ViewRoot.handleMessage(ViewRoot.
java:1785)
E/AndroidRuntime( 975): at android.os.Handler.dispatchMessage(Handler.ja
va:99)
E/AndroidRuntime( 975): at android.os.Looper.loop(Looper.java:123)
E/AndroidRuntime( 975): at android.app.ActivityThread.main(ActivityThrea
d.java:4627)
E/AndroidRuntime( 975): at java.lang.reflect.Method.invokeNative(Native
Method)
E/AndroidRuntime( 975): at java.lang.reflect.Method.invoke(Method.java:5
21)
E/AndroidRuntime( 975): at com.android.internal.os.ZygoteInit$MethodAndA
rgsCaller.run(ZygoteInit.java:868)
E/AndroidRuntime( 975): at com.android.internal.os.ZygoteInit.main(Zygot
eInit.java:626)
E/AndroidRuntime( 975): at dalvik.system.NativeStart.main(Native Method)
W/ActivityManager( 42): Force finishing activity com.view/.TestView |
Les données sont récupérées d'un fichier xml, et le sont vraisemblablement correctement puisque j'arrive à les afficher sans erreurs en faisant une liste simple. J'ai également essayé en mettant des données en dur pour remplir la liste, ça fonctionne un peu plus longtemps avant de planter avec le même message d'erreur.
Je sais vraiment pas d'où peut venir le problème donc si l'un de vous à une idée, ce serait vraiment super.
Merci d'avance