1

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

已经实现:到目前为止,我已经实现了OrderOverviewActivity使用LoaderManager和内容提供者来访问数据库中的信息。我确实使用MyCursorAdapter它扩展CursorAdapter并覆盖了它的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()看起来像这样:

    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);
        }
    }

问题的核心:请注意,数量是通过从HashMap<String, String>对象中提取的String.valueOf(data, 0, data.size)。恐怕它会创建一个字符串对象,稍后必须对其进行垃圾收集,从而破坏性能。有没有更好的方法从地图中设置数量 TextView 值?

4

4 回答 4

1

我不同意 yanchenko 的观点,CharArrayBuffer在基于适配器的情况下使用它是一个很好的改进Cursor(尤其是当Cursor有很多String列要使用时)。要摆脱这个额外String的选项,第一个选择是让它成为mQuantity HashMap不起作用的关键(以及它的类,final所以你根本无法让它工作)。

识别行的另一种方法是无论如何都_id需要的列ListView

与此相关,您可以:

  • 有两个s 都具有一个值(_id)HashMap作为键,一个将保存 the ,另一个将保存实际数量(或一个在 和 代码之间的映射映射,另一个是您当前的映射)。这两个映射将被同步(如果您删除一个长 id 的值,您也会将其从另一个中删除,添加值等时也是如此)。在该方法中,您将使用 _id 中的 _id 获取名称,但这需要自动装箱操作(to )。LongCOLUMN_CODE_idgetView()CursorlongLong

    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); 
     } 
    }  
    
  • 尽管_id是 along并且您有相当数量的值,但您可以将其作为 a 来威胁int(因为您将处于最大值的边界int)。这样做将允许您简单地将 aSparseArray与自定义类一起使用(在 and 之间long进行转换int):

    class 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键(因此没有自动装箱)到代码和数量值之间进行映射。

于 2013-08-10T06:48:39.977 回答
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);

}

公共视图新视图

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

}

于 2013-08-07T20:41:35.353 回答
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

于 2013-08-08T11:18:04.517 回答
0

我宁愿不要弄乱CharArrayBuffers并String在.TextViewHolder

这样,您将使代码更具可读性,并让平台使用字符串池进行缓存。这也意味着最佳性能。

IE

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. 这个版本。

并根据结果在最后两个之间选择最易读的一个。(:

于 2013-08-08T11:44:58.090 回答