代码之家  ›  专栏  ›  技术社区  ›  Juri

具有多个“表”数据的ListView的优化建议

  •  5
  • Juri  · 技术社区  · 14 年前

    我刚刚遇到了以下情况。我有一个Android应用程序,我猜可能会发生在多个应用程序中。它是关于标记/标签/分类的,你想怎么叫就怎么叫。我在SQLite数据库中基本上有以下关系

     --------                 --------------              ---------
    |  Tags  |               |  DeviceTags  |            | Devices |
    |--------|               |--------------|            |---------|
    | ID     | 1 ------ *    | ID           | * ------ 1 | ID      |
    | NAME   |               | TAGS_ID      |            | NAME    |
     --------                | DEVICE_ID    |            | ...     |
                              --------------              ---------
    

    一切都是通过我写的内容提供者公开的。到目前为止一切都很好。

    我的问题来了 . 对于简单的设备列表,我创建了一个定制的ResourceCursorAdapter,在其中我在bindView方法中设置了相应的信息

    @Override
    public void bindView(final View view, final Context context, final Cursor cursor) {
      final int objectId = cursor.getInt(cursor.getColumnIndex(Devices._ID));
    
      TextView deviceName = (TextView) view.findViewById(R.id.deviceName);
      deviceName.setText(...); //set it from the cursor
      ...
      TextView associatedTagsView = (TextView)...;
      associatedTagsView.setText(...); //<<<???? This would need a call to a different table
      ...
    }
    

    如您所见,为了能够知道我的设备关联了哪种类型的标记,我需要查询设备标记。所以我做了:

    @Override
    public void bindView(final View view, final Context context, final Cursor cursor) {
       ...
       TextView associatedTagsView = (TextView)view.findViewById(R.id.deviceTags);
       String tagsString = retrieveTagsString(view.getContext().getContentResolver(), objectId);
       ...
    }
    
    private String retrieveTagsString(ContentResolver contentResolver, int objectId) {
        Cursor tagForDeviceCursor =  contentResolver.query(DroidSenseProviderMetaData.TABLE_JOINS.TAG_DEVICETAG,...);
        if(tagForDeviceCursor != null && tagForDeviceCursor.moveToFirst()){
            StringBuffer result = new StringBuffer();
    
            boolean isFirst = true;
            do{
                if(!isFirst)
                    result.append(", ");
                else
                    isFirst = false;
    
                result.append(retrieve name from cursor column...);
            }while(tagForDeviceCursor.moveToNext());
    
            return result.toString();
        }       
        return null;
    }
    

    我测试了这个,它实际上工作得很好,但说实话,我觉得做这个不太好。我觉得有点奇怪。。。

    //编辑:

    在Commonware的反馈之后,这里有一点澄清。我对在CursorAdapter中对DB进行第二次查询感到奇怪,基本上这会导致每行一次查询,我担心这会严重影响我的性能(我仍然需要在具有大量数据的真实设备上进行测试,看看这会有多大影响)。

    我的问题

    2 回复  |  直到 14 年前
        1
  •  3
  •   CommonsWare    14 年前

    1. 最后,你的问题很模糊
    2. 你的问题取决于你自己对“这”是什么的解释,而我们对此并不知情

    因此,我不清楚你认为什么是“奇怪的”。 do...while() 循环?:-)

    我将冒一个险,猜测您关心的是为您的数据库中的每一行执行第二次查询和一轮字符串连接 ListView . 这完全取决于您认为“逗号分隔的标记列表”是数据模型的一部分还是表示的一部分。如果这是演讲的一部分,我不明白你怎么能避免你在这里做的事情。

    ContentProvider 提供逗号分隔的标记列表作为您首先查询的内容的一部分(未显示)。

        2
  •  0
  •   Andrew Whitaker    13 年前

    我用大约100个条目测试了我的解决方案(在我的问题中提出的)。它仍然可以使用,但是滚动并不像人们期望的那样平滑。正如Commonware已经指出的那样,最好的方法是调整数据模型,或者至少在最后适当地聚合它 游标包含在UI上显示所需的所有数据 .

    我不想完全改变底层的数据模型。我所做的是以某种方式(即s.t)聚合数据。ContentProvider返回的游标包含设备的数据,包括一个已准备好的字符串,该字符串表示相关标签的名称:

    | ID | NAME             | ... | LABELSSTRING   |
    ------------------------------------------------
    | 1  | "My Device name" | ... | "Work, Friend" |
    | 1  | "Some other"     | ... |                |
    | 1  | "Yet another"    | ... | "Work"         |
    

    group_concat(X, Y) function .