5

我在 SQLite 表中有以下格式的数据:

id|datetime|col1|col2
1|2013-10-30 23:59:59|aaa|aab
2|2013-10-30 23:59:59|abb|aba
3|2013-10-30 23:59:59|abb|aba
4|2013-10-31 23:59:59|abb|aba
5|2013-10-31 23:59:59|abb|aba

我想实现一个ExpandableListView,以便数据按以下方式分组datetime并显示:

> 2013-10-30 23:59:59 // Group 1
1|aaa|aab
2|abb|aba
3|abb|aba
> 2013-10-31 23:59:59 // Group 2
4|abb|aba
5|abb|aba

我有一个习惯CursorAdapter,我可以很容易地使用它来填充ListView,显示每个项目的日期,但我不知道如何“分组”数据并将其填充到ExpandableListView- 你能给我任何提示吗?

4

2 回答 2

5

我有一个自定义 CursorAdapter,我可以轻松地使用它来填充 ListView,显示每个项目的日期,但我不知道如何“分组”数据并将其填充到 ExpandableListView - 你能给我任何提示吗?

这是我目前在我的项目中使用的解决方案:

您不能(不应该)使用 CursorAdapter因为它不适合您的解决方案。您需要通过扩展来创建和实现自己的适配器BaseExpandableListAdapter

然后,由于您想创建“您自己的分组”,您需要更改您当前的应用程序逻辑:

  • 您需要创建从数据库返回的对象集合(用于演示我将使用名称 Foo)

解决方案:

因此,您的Foo对象应如下所示(由于您的要求,仅创建变量名称以解释解决方案的想法):

public class Foo {

   private String title;
   private List<Data> children;

   public void setChildren(List<Data> children) {
      this.children = children;
   }

}

其中title 将是数据库中的 date 列,children 将是特定(唯一) date 的列

由于您的示例:

id|datetime|col1|col2
1|2013-10-30 23:59:59|aaa|aab
2|2013-10-30 23:59:59|abb|aba
3|2013-10-30 23:59:59|abb|aba
4|2013-10-31 23:59:59|abb|aba
5|2013-10-31 23:59:59|abb|aba

一个特定的日期(对象 Foo 的标题属性)具有更多关联的行,因此这将使用 Foo 对象中定义的子项集合来模拟。

因此,现在您需要在您的 DAO 对象(与数据库通信的对象,它只是术语)的 getAll() 方法(从数据库返回数据的方法通常类似地调用)中以这种逻辑创建 Foo 对象。

由于您需要为每个唯一日期正确初始化子项集合,因此您需要使用两个选择查询。您的第一个选择将返回不同的日期 - 因此,如果您在数据库中有 40 行具有 10 个不同(唯一)日期,那么您的选择将包含 10 行具有这些唯一日期。

好的现在您的 ListView 有了“组”

现在您需要为每个创建的“组”创建其子级。因此,这是第二个选择,它将选择所有行,并且在正确的条件下,您将为每个“组”Foo 对象分配自己的子集。

这是伪代码#1:

String query = "select * from YourTable";
Cursor c = db.rawQuery(query, null);
List<Data> childen = new ArrayList<Data>();
if (c != null && c.moveToFirst()) {
   for (Foo item: collection) {
      // search proper child for current item
      do {
         // if current row date value equals with current item datetime
         if (item.getTitle().equals(c.getString(2))) {
            children.add(new Data(column3, column4)); // fetch data from columns
         } 
      } while (c.moveToNext());

      // assign created children into current item
      item.setChildren(children);

      // reset List that will be used for next item
      children = null;
      children = new ArrayList<Data>();

      // reset Cursor and move it to first row again
      c.moveToFirst();
   }
}
// finally close Cursor and database

所以现在你的集合是“分组的”,现在剩下的工作是在你实现的 ListAdapter 上——这并不棘手。

您需要做的只是正确实现getGroupView()getChildView()方法。

“组方法”中,您将使用 Foo 对象集合中的标题来膨胀和初始化行。这些行将成为 ListView 中的组。

“子方法”中,您将执行相同的操作,但不会从集合中膨胀标题,而是从集合中膨胀当前 Foo 对象的子级。这些行将成为一个特定组的子代。

笔记:

由于#1。为了演示目的,我简化了源代码。但是“在行动中”你可以改变一些事情:

  • 通常建议使用列名而不是c.getString(2)获取第二列,因此您应该使用 c.getColumnIndex("columnName")

  • 将源代码包装到 try-finally 块并在 finnaly 块中关闭并释放使用的源(如游标和数据库)是一种很好的做法。

  • 您可以在 Foo 类中创建将项目直接添加到集合中的公共方法,而不是“重用”相同的子集合(代码片段#2)。

代码片段#2:

public class Foo {

   private String title;
   private List<Data> children = new ArrayList<Data>();

   public void addChild(Data child) {
      this.children.add(child);
   }
   ...
}

概括:

希望你能理解我(我试图以尽可能简单的方式解释事情,不幸的是面对面的个人交流是最好的,但这个解决方案对我们不可用),我也希望我能帮助你解决你的问题。

于 2013-12-05T11:39:30.943 回答
3

您的数据建模和表示可以在 Java 代码中建模为LinkedHashMap<String, List<Data>>,其中Data可能如下所示:

public class Data {
    private int id;
    private String col1;
    private String col2;

    public Data(int id, String col1, String col2) {
        this.id = id;
        this.col1 = col1;
        this.col2 = col2;
    }

    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getCol1() {
        return col1;
    }
    public void setCol1(String col1) {
        this.col1 = col1;
    }
    public String getCol2() {
        return col2;
    }
    public void setCol2(String col2) {
        this.col2 = col2;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(id).append(", ").append(col1).append(", ").append(col2);
        return sb.toString();
    }
}

为什么LinkedHasMap?因为您需要保留插入数据的顺序。所以你的 SQLite 读取方法可能如下所示:

public LinkedHashMap<String, List<Data>> readData(SQLiteDatabase db) {
    LinkedHashMap<String, List<Data>> result = new LinkedHashMap<String, List<Data>>();
    Cursor cursor = null;
    try {
        cursor = db.query("MY_TABLE", new String[] {
                "datetime", "id", "col1", "col2"
        }, null, null, null, null, "datetime, id ASC");
        while (cursor.moveToNext()) {
            String dateTime = cursor.getString(cursor.getColumnIndex("datetime"));
            int id = cursor.getInt(cursor.getColumnIndex("id"));
            String col1 = cursor.getString(cursor.getColumnIndex("col1"));
            String col2 = cursor.getString(cursor.getColumnIndex("col2"));
            List<Data> list = null;
            if (result.containsKey(dateTime)) {
                list = result.get(dateTime);
            } else {
                list = new ArrayList<Data>();
                result.put(dateTime, list);
            }
            list.add(new Data(id, col1, col2));
        }
    } catch (Exception ex) {
        Log.e("TAG", null, ex);
    } finally {
        if (cursor != null) {
            cursor.close();
        }
    }
    return result;
}

一个基本的适配器应该是这样的:

public class ExpAdapter extends BaseExpandableListAdapter {
    private LinkedHashMap<String, List<Data>> input;

    private LayoutInflater inflater;

    public ExpAdapter(LayoutInflater inflater, LinkedHashMap<String, List<Data>> input) {
        super();
        this.input = input;
        this.inflater = inflater;
    }

    @Override
    public Object getChild(int groupPosition, int childPosition) {
        return getChildData(groupPosition, childPosition);
    }

    private Data getChildData(int groupPosition, int childPosition) {
        String key = getKey(groupPosition);
        List<Data> list = input.get(key);
        return list.get(childPosition);
    }

    private String getKey(int keyPosition) {
        int counter = 0;
        Iterator<String> keyIterator = input.keySet().iterator();
        while (keyIterator.hasNext()) {
            String key = keyIterator.next();
            if (counter++ == keyPosition) {
                return key;
            }
        }
        // will not be the case ...
        return null;
    }

    @Override
    public long getChildId(int groupPosition, int childPosition) {
        return getChildData(groupPosition, childPosition).getId();
    }

    @Override
    public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
            View convertView, ViewGroup parent) {
        TextView simpleTextView = null;
        if (convertView == null) {
            // inflate what you need, for testing purposes I am using android
            // built-in layout
            simpleTextView = (TextView) inflater.inflate(android.R.layout.simple_list_item_1,
                    parent, false);
        } else {
            simpleTextView = (TextView) convertView;
        }
        Data data = getChildData(groupPosition, childPosition);
        simpleTextView.setText(data.toString());
        return simpleTextView;
    }

    @Override
    public int getChildrenCount(int groupPosition) {
        String key = getKey(groupPosition);
        return input.get(key).size();
    }

    @Override
    public Object getGroup(int groupPosition) {
        return getKey(groupPosition);
    }

    @Override
    public int getGroupCount() {
        return input.size();
    }

    @Override
    public long getGroupId(int groupPosition) {
        return 0;
    }

    @Override
    public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
            ViewGroup parent) {
        TextView simpleTextView = null;
        if (convertView == null) {
            // inflate what you need, for testing purposes I am using android
            // built-in layout
            simpleTextView = (TextView) inflater.inflate(android.R.layout.simple_list_item_1,
                    parent, false);
        } else {
            simpleTextView = (TextView) convertView;
        }
        simpleTextView.setText(getKey(groupPosition));
        return simpleTextView;
    }

    @Override
    public boolean hasStableIds() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        return true;
    }

}

虽然它在基本活动中的简单用途是这样的:

public class MyExpandableActivity extends FragmentActivity {
    private ExpandableListView expListView;

    @Override
    protected void onCreate(Bundle savedInstance) {
        super.onCreate(savedInstance);
        setContentView(R.layout.expandable_layout);
        expListView = (ExpandableListView) findViewById(R.id.exp_listview);
        fillList();
    }

    private void fillList() {
        LinkedHashMap<String, List<Data>> input = getMockList(); // get the collection here
        ExpAdapter adapter = new ExpAdapter(LayoutInflater.from(this), input);
        expListView.setAdapter(adapter);
    }
}

Activity的简单布局:

<ExpandableListView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/exp_listview"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

说得通?

于 2013-12-10T08:56:27.957 回答