ExpandableListAdapter und SQLite

  • Antworten:6
  • Bentwortet
Sebastian Klaiber
  • Forum-Beiträge: 44

27.12.2010, 10:45:50 via Website

Hallo,

ich arbeite gerade an einer App mit ExpandableListAdapter und SQLite Datenbank, mich würde interessieren ob der Aufbau des Adapters so richtig ist? Hab danach auch schon gegoogelt aber noch kein gutes Tutroial gefunden. Vor allem ob es richtig ist die Cursor im Adapter zu öffnen. Hier mal mein ExpandableListAdapter wäre euch sehr dankbar wenn ihr euch das mal anschaut und mir sagt wie ich den Adapter optimieren kann bzw. verbessern kann! Danke

1public class CategoriesAdapter extends BaseExpandableListAdapter {
2 private Context mContext;
3
4 private ShoppingListDatabaseHelper mDbHelper;
5 private SQLiteDatabase mDb;
6
7 private Cursor mCategoriesCursor;
8 private Cursor mItemsCursor;
9
10 public CategoriesAdapter(Context context, SQLiteDatabase db, Cursor categoriesCursor) {
11 mContext = context;
12 mDb = db;
13 mCategoriesCursor = categoriesCursor;
14 }
15
16 @Override
17 public int getGroupCount() {
18 return mCategoriesCursor.getCount();
19 }
20
21 @Override
22 public int getChildrenCount(int groupPosition) {
23 Cursor itemsCursor = Item.findAllByCategoryId(mDb, getGroupId(groupPosition));
24 int count = itemsCursor.getCount();
25 itemsCursor.close();
26 return count;
27 }
28
29 @Override
30 public Object getGroup(int groupPosition) {
31 mCategoriesCursor.moveToPosition(groupPosition);
32 if (mCategoriesCursor.getCount() > 0){
33 return mCategoriesCursor;
34 }
35 return null;
36 }
37
38 @Override
39 public Object getChild(int groupPosition, int childPosition) {
40 mItemsCursor = Item.findAllByCategoryId(mDb, getGroupId(groupPosition));
41 mItemsCursor.moveToPosition(childPosition);
42 if (mItemsCursor.getCount() > 0){
43 return mItemsCursor;
44 }
45 return null;
46 }
47
48 @Override
49 public long getGroupId(int groupPosition) {
50 Cursor categoriesCursor = (Cursor) getGroup(groupPosition);
51 if (categoriesCursor != null && !categoriesCursor.isNull(groupPosition)) {
52 return categoriesCursor.getInt(categoriesCursor.getColumnIndexOrThrow(Category.ID));
53
54 }
55 return -1;
56 }
57
58 @Override
59 public long getChildId(int groupPosition, int childPosition) {
60 Cursor itemsCursor = (Cursor) getChild(groupPosition, childPosition);
61 Log.v("CategoriesCursor", new Integer(itemsCursor.getCount()).toString());
62 if (itemsCursor.getCount() > 0){
63 int id = itemsCursor.getInt(itemsCursor.getColumnIndexOrThrow(Item.ID));
64 itemsCursor.close();
65 return id;
66 }
67 return 0;
68 }
69
70 @Override
71 public boolean hasStableIds() {
72 return true;
73 }
74
75 @Override
76 public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
77
78 Cursor categoriesCursor = (Cursor) getGroup(groupPosition);
79 if (convertView == null && categoriesCursor != null){
80 LayoutInflater inflater = LayoutInflater.from(mContext);
81 convertView = inflater.inflate(R.layout.group_row, null);
82
83 if (categoriesCursor != null) {
84 TextView groupTv = (TextView) convertView.findViewById(R.id.group_text);
85 groupTv.setText(categoriesCursor.getString(mCategoriesCursor.getColumnIndexOrThrow(Category.NAME)));
86 }
87 }
88 return convertView;
89 }
90
91 @Override
92 public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
93 Cursor itemsCursor = (Cursor) getChild(groupPosition, childPosition);
94 if (convertView == null) {
95 LayoutInflater inflater = LayoutInflater.from(mContext);
96 convertView = inflater.inflate(R.layout.child_row, null);
97 if (itemsCursor != null) {
98 TextView childTv = (TextView) convertView.findViewById(R.id.child_text);
99 TextView amountView = (TextView) convertView.findViewById(R.id.child_amount);
100 childTv.setText(itemsCursor.getString(itemsCursor.getColumnIndexOrThrow(Item.NAME)));
101 amountView.setText(itemsCursor.getString(itemsCursor.getColumnIndexOrThrow(Item.AMOUNT)));
102 }
103 }
104 itemsCursor.close();
105 return convertView;
106 }
107
108 @Override
109 public boolean isChildSelectable(int groupPosition, int childPosition) {
110 return true;
111 }
112
113}

Antworten
Gian U.
  • Forum-Beiträge: 117

30.12.2010, 13:38:09 via Website

Ich hab mir jetzt nicht den ganzen Adapter angeschaut, aber eine Optimierung wäre sicherlich das Verwenden eines ViewHolders. Schau dir mal das an: http://youtu.be/wDBM6wVEO70 (so um 11:00)
Ist zwar für eine ListView, lässt sich aber auch für eine ExpandableListView anwenden.

Mnemono - Efficient learning!

Antworten
Sebastian Klaiber
  • Forum-Beiträge: 44

30.12.2010, 16:57:56 via Website

Bei dem Adapter habe ich dass Problem, wenn ich z.B. zwei Einträge habe, einem davon eine anderen Kategorie zuweise. Nach einem auf und zu klappen der Kategorie dieser dann den Namen des anderen Eintrages hat. Aber nur in der View in der Datenbank stimmt der Eintrag noch. Hoffe das das soweit verständlich ist und mir jemand weiterhelfen kann.

ciao

Antworten
Gian U.
  • Forum-Beiträge: 117

31.12.2010, 10:59:23 via Website

Du musst die Daten jedes mal neu setzen. Der ViewHolder ist dazu da, dass du die Views nicht mehr suchen musst. D.h. du musst den Inhalt nach dem Laden des ViewHolders in die im ViewHolder gespeicherten Views einsetzen.

Mnemono - Efficient learning!

Antworten
Sebastian Klaiber
  • Forum-Beiträge: 44

02.01.2011, 10:53:45 via Website

Danke so hat es funktioniert mit dem ViewHolder!

Antworten
Gelöschter Account
  • Forum-Beiträge: 294

31.03.2011, 23:41:10 via Website

In den meisten Fällen reicht bei einer Kombination von EpandableListActivity mit SQLite ein SimpleCursorTreeAdapter. Damit spart man sich den ganzen Overhead (wie im Code oben zu sehen). Und vor allen Dingen muss man nix cachen - dafür hat man ja Android und die Datenbank - die speichern und recyclen ja auch schon wie wild.

Dem SimpleCursorTreeAdapter gibt man einen GroupCursor (dieser enthält lediglich die Root-Einträge mit ihren _ids), die beiden Layouts für die Root- und die Child-Zeile, die Spaltennamen aus Root- und Child-Cursor und die View-IDs für die Root- und Child-Layouts. Im Grunde genommen ist das nur ein etwas aufgeblähter SimpleCursorAdapter:

1MySimpleCursorTreeAdapter mySimpleCursorTreeAdapter = new MySimpleCursorTreeAdapter(this,
2 cursorGroup,
3 R.layout.rowgroup,
4 new String[] { "root_name" }, // Spalte aus GroupCursor
5 new int[] { R.id.rowgroup_text },
6 R.layout.rowchild,
7 new String[] { "child_name" }, // Spalte aus ChildCursor
8 new int[] { R.id.rowchild_text } );

Der MySimpleCursorTreeAdapter (hier eine Inner-Class) will dann nur noch beim Anklicken eines Root-Eintrags den Cursor für die zu diesem Root passenden Childs wissen. Das ist alles. Diese ganze "Cacherei" von Datenbank-Inhalten in ArrayListen erscheint mir etwas widersinnig.

1private class MySimpleCursorTreeAdapter extends SimpleCursorTreeAdapter{
2
3 public MySimpleCursorTreeAdapter(Context context, Cursor cursor, int groupLayout, String[] groupFrom, int[] groupTo, int childLayout, String[] childFrom, int[] childTo) {
4 super(context, cursor, groupLayout, groupFrom, groupTo, childLayout, childFrom, childTo);
5 }
6
7 @Override
8 protected Cursor getChildrenCursor(Cursor cursor) {
9 Cursor cursorChild = null;
10
11 long rootId = cursor.getLong(0);
12
13 cursorChild = datenbank.fetchChilds(sqliteDatabase, rootId); // Alle Childs zu dieser Root-ID
14
15 if (cursorChild != null) {
16 startManagingCursor(cursorChild);
17 }
18
19 return cursorChild;
20 }
21}

Gruß
Harald

Antworten