如何有效地从HashMap显示来自SQLite的记录的值?

时间:2013-08-02 14:31:26

标签: android android-listview

目标:应用程序应允许用户为显示的项目添加数量。考虑从所有可能产品的列表中创建产品订单。产品代码列表可能很长(如数万件甚至更多)。另一方面,订单所选项目的数量非常小(最多几个或几十个)。

已实施:到目前为止,我已实施了使用OrderOverviewActivity的{​​{1}}和内容提供商,以便从数据库中访问信息。我使用扩展LoaderManager的{​​{1}}并覆盖其MyCursorAdapterCursorAdapter方法。

newView()还会创建一个bindView()实例,其中包含对子视图的引用,以及从光标位置提取的值的缓冲区 - 如下所示:

newView()

ViewHolder看起来像这样:

private static class ViewHolder {
    public TextView code;
    public CharArrayBuffer codeBuffer = new CharArrayBuffer(20);

    public TextView name;
    public CharArrayBuffer nameBuffer = new CharArrayBuffer(100);

    public TextView quantity;
    public CharArrayBuffer quantityBuffer = new CharArrayBuffer(10);
}

newView()使用holder缓冲区来避免创建许多 public View newView(Context context, Cursor cursor, ViewGroup parent) { View v = mInflater.inflate(mLayout, parent, false); ViewHolder holder = new ViewHolder(); holder.code = (TextView) v.findViewById(R.id.code); holder.name = (TextView) v.findViewById(R.id.name); holder.quantity = (TextView) v.findViewById(R.id.quantity); v.setTag(holder); return v; } 个对象:

bindView()

问题的核心:请注意,数量是通过String public void bindView(View view, Context context, Cursor cursor) { ViewHolder holder = (ViewHolder) view.getTag(); cursor.copyStringToBuffer(1, holder.codeBuffer); // ProductTable.COLUMN_CODE cursor.copyStringToBuffer(2, holder.nameBuffer); // ProductTable.COLUMN_NAME holder.code.setText(holder.codeBuffer.data, 0, holder.codeBuffer.sizeCopied); holder.name.setText(holder.nameBuffer.data, 0, holder.nameBuffer.sizeCopied); // The quantity (v for value) from the HashMap<String, String>. String v = mQuantity.get(String.valueOf(holder.codeBuffer.data, 0, holder.codeBuffer.sizeCopied)); if (v != null) { holder.quantity.setText(v); holder.quantity.setBackgroundColor(Color.DKGRAY); } else { holder.quantity.setText(null); holder.quantity.setBackgroundColor(Color.TRANSPARENT); } } 对象中提取的。我担心它会创建一个字符串对象,以后必须进行垃圾回收,从而破坏性能。有没有更好的方法从地图设置数量TextView值?

4 个答案:

答案 0 :(得分:1)

我不同意yanchenko对CharArrayBuffer的看法,在基于Cursor的适配器中使用它是一个很好的改进(特别是当Cursor有许多String列时使用)。要摆脱额外的String,第一个选项就是将其作为mQuantity HashMap无效的关键(而且它是final的类,这样你就可以它根本不起作用。

标识行的另一种方法是_id所需的ListView列。

与此相关,您可以:

  • 让两个HashMap都具有Long值作为关键字(_id),其中一个将保留COLUMN_CODE,另一个将保留实际数量(或_id和代码之间的一个地图映射,另一个是您当前的地图。这两个映射将被同步(如果你为一个长id删除一个值,你也将它从另一个中删除,当你添加值时也是如此)。在getView()方法中,您可以使用Cursor中的_id获取名称,但这需要自动装箱操作(longLong)。

    class DataWrapper {
     private HashMap<Long, String> mCodeMapping = new HashMap<Long, String>();
     private HashMap<Long, String> mQuantityMapping = new HashMap<String, String>();
    
     public String getCode(long id) {
          return mCodeMapping.get(id);
     }
    
     public String getQuantity(long id) {
          return mQuantityMapping.get(getCode());
     }
    
     public String getQuantity(String code) {
          return mQuantityMapping.get(code);
     }
    
     public void put(long id, String code, String quantity) {
         mCodeMapping.put(id, code);
         mQuantityMapping .put(code, quantity); 
     } 
    }  
    
  • 虽然_idlong并且您拥有相当数量的值,但您可以将其威胁为int(因为您将在int的边界内最大SparseArray个值)。这样做可以让您只使用long自定义类(在intclass WrapperData { String code; //or use the CharArraybuffer? String quantity; } SparseArray<WrapperData> data = new SparseArray<WrapperData>(); // in the getView() method WrapperData wd = data.get((int) _id_value); // further use wd.code or wd.quantity 之间进行投射):

    SparseArray
  • 最后一个选项是实现自己的类,如long,它允许您在简单的{{1}}键(因此没有自动装箱)与代码和数量值之间进行映射。

答案 1 :(得分:0)

将字符串变量添加到ViewHolder类中,作为为Holder类分配并与位置映射的克隆内存实例。除了刚刚完成赋值使用NEW关键字,所以你将获得未与HASHMAP映射的新STRING对象。

私有静态类ViewHolder {

public String quantityStr;

public TextView code;
public CharArrayBuffer codeBuffer = new CharArrayBuffer(20);

public TextView name;
public CharArrayBuffer nameBuffer = new CharArrayBuffer(100);

public TextView quantity;
public CharArrayBuffer quantityBuffer = new CharArrayBuffer(10);

}

public查看newView

{    ...   holder.quantityStr = new String (mQuantity.get(String.valueOf(holder.codeBuffer.data,0,holder.codeBuffer.sizeCopied)));

}

答案 2 :(得分:0)

我认为它不会创建一个新的字符串实例,因为字符串常量池中已经存在一个字符串常量。

String str = "test";
String str2 = "test";
char[] strArray = {'t', 'e', 's','t'};
System.out.println(str.hashCode());
System.out.println(str2.hashCode());
System.out.println(String.valueOf(strArray).hashCode());

结果与打击相同: 3556498 3556498 3556498

答案 3 :(得分:0)

我宁愿不与CharArrayBuffer混在一起,也不会在String中使用TextView s + Holder

这样您就可以使代码更具可读性,并让平台使用String池进行缓存。这也意味着最佳表现。

private static class ViewHolder {

    public TextView code;
    public TextView name;
    public TextView quantity;

}

public void bindView(View view, Context context, Cursor cursor) {

    ViewHolder holder = (ViewHolder) view.getTag();

    String code = cursor.getString(1);
    String name = cursor.getString(2);

    String quantity = mQuantity.get(code);

    holder.code.setText(code);
    holder.name.setText(name);

    if (quantity != null) {
        holder.quantity.setText(quantity);
        holder.quantity.setBackgroundColor(Color.DKGRAY);
    } else {
        holder.quantity.setText("");
        holder.quantity.setBackgroundColor(Color.TRANSPARENT);
    }

}

我建议你先运行一系列3个性能分析测试:

  1. 根本没有String v = mQuantity.get(String.valueOf(holder.codeBuffer.data, 0, holder.codeBuffer.sizeCopied));来电。
  2. 初始版本。
  3. 此版本。
  4. 根据结果选择最后两个之间最易读的结果。 (: