0

我制作了一个运行良好的 CustomListAdapater,但是,当我快速滚动列表时,会弹出很多垃圾收集消息。

是否有制作高效自定义 ListAdapter 的最佳实践?

这就是我目前所拥有的东西,但效果不佳。

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    RelativeLayout centreView;
    //Get the current alert object

    if (convertView == null) {
        centreView = new RelativeLayout(getContext());
        LayoutInflater vi;
        vi = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        vi.inflate(resource, centreView, true);
    }
    else
    {
        centreView = (RelativeLayout) convertView;
    }

    TextView name = (TextView) centreView.findViewById(R.id.class_name);
    TextView venue = (TextView) centreView.findViewById(R.id.class_venue);
    TextView time = (TextView) centreView.findViewById(R.id.class_time);
    TextView room = (TextView) centreView.findViewById(R.id.class_room);
    TextView id = (TextView) centreView.findViewById(R.id.class_id);
    TextView dayTV = (TextView) centreView.findViewById(R.id.class_day);
    TextView desc = (TextView) centreView.findViewById(R.id.class_description);
    TextView json = (TextView) centreView.findViewById(R.id.class_json);

    String timeString;
    try {
        JSONObject thisRow = items.get(position);
        name.setText(thisRow.getString("className"));

        dayTV.setText(thisRow.getString("theDate"));
        json.setText(thisRow.toString());
        venue.setText(thisRow.getString("venue"));
        final String ID = thisRow.getString("id");
        id.setText(ID);


        desc.setText(thisRow.getString("description"));


        timeString = thisRow.getString("startTime");
        timeString += " - "+thisRow.getString("endTime");
        time.setText(timeString);



        room.setText(thisRow.getString("room"));


        final Button alter = (Button) centreView.findViewById(R.id.is_alt);
        alter.setVisibility(View.INVISIBLE);
        final JSONArray alterations = thisRow.getJSONArray("alteration");

        if (alterations.getJSONObject(0).getString("show").equals("yes")) {
            alter.setVisibility(View.VISIBLE);
            alter.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    ActivityViewTimetable actVT = (ActivityViewTimetable) getContext();
                    actVT.showAlterations(alterations);
                }
            });
        }


    } catch (JSONException e) {
        Log.e("FUApp", "JSON Error (TimetableItemsArrayAdapter): " + e.getMessage());
    }

    return centreView;
}

PS。我引用的一些 TextView 不再需要了,我现在只是整理出哪些。

编辑:这就是我最终得到的

static class ViewHolder {
    TextView name;
    TextView venue;
    TextView time;
    TextView room;
    TextView id;
    TextView dayTV;
    TextView desc;
    TextView json;
    JSONObject jsonObj;
    String classNameString;
    String theDate;
    String venueString;
    String idString;
    String description;
    String startTime;
    String endTime;
    String roomString;
    JSONArray alterations;
}

 if (convertView == null) {
        centreView = new RelativeLayout(getContext());
        LayoutInflater vi;
        vi = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        vi.inflate(resource, centreView, true);
        holder = new ViewHolder();
        holder.name = (TextView) centreView.findViewById(R.id.class_name);
        holder.venue = (TextView) centreView.findViewById(R.id.class_venue);
        holder.time = (TextView) centreView.findViewById(R.id.class_time);
        holder.room = (TextView) centreView.findViewById(R.id.class_room);
        holder.id = (TextView) centreView.findViewById(R.id.class_id);
        holder.dayTV = (TextView) centreView.findViewById(R.id.class_day);
        holder.desc = (TextView) centreView.findViewById(R.id.class_description);
        holder.json = (TextView) centreView.findViewById(R.id.class_json);
        holder.jsonObj = items.get(position);
        try {
            holder.classNameString = holder.jsonObj.getString("className");
            holder.theDate = holder.jsonObj.getString("theDate");
            holder.venueString = holder.jsonObj.getString("venue");
            holder.idString = holder.jsonObj.getString("id");
            holder.description = holder.jsonObj.getString("description");
            holder.startTime = holder.jsonObj.getString("startTime");
            holder.endTime = holder.jsonObj.getString("endTime");
            holder.roomString = holder.jsonObj.getString("room");
            holder.alterations = holder.jsonObj.getJSONArray("alteration");
        }
        catch (JSONException e) {
            Log.e("FUApp", "JSONError getting details: "+e.getMessage());
        }
        centreView.setTag(holder);
    }

使用这个我的列表一点也不落后。

4

2 回答 2

1

使用视图持有者

您的代码可能会findViewById()在 ListView 滚动期间频繁调用,这会降低性能。即使适配器返回一个膨胀的视图进行回收,您仍然需要查找元素并更新它们。避免重复使用的一种方法findViewById()是使用“视图持有者”设计模式。

http://developer.android.com/training/improving-layouts/smooth-scrolling.html

您可以在 Adapter 类的构造函数中初始化 Layout Infalter

编辑:

 ViewHolder holder;
 if (convertView == null) {
    holder = new ViewHolder();
    convertView = inflater.inflate(R.layout.mylayouttoinflate, null);
    // initialize views like holder.text = (TextView)convertView.findViewByID(R.id.text);
    convertView.setTag(holder);
} else {
    holder = (ViewHolder) convertView.getTag();
}
  // set text to text view
  holder.text.setText("hi");
 return convertView; 
于 2013-09-06T10:20:46.730 回答
0

实际上,这似乎是最好的方法。列表视图将对所有未显示到屏幕的项目调用 getView,即使它们之前已经创建。感谢这些行:

   if (convertView == null) {
    centreView = new RelativeLayout(getContext());
    LayoutInflater vi;
    vi = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    vi.inflate(resource, centreView, true);
}

您的视图不会再次创建。我认为你已经为这部分尽了最大的努力。

还有 viewHolder 模式可以有效地存储数据,但我从未使用过它。;)。

于 2013-09-06T10:21:22.450 回答