在Android Listview中设置行背景的问题

时间:2010-12-25 06:09:11

标签: android listview

我有一个应用程序,我希望一次一行可以有一定的颜色。这似乎在95%的时间内起作用,但有时不是只有一行具有这种颜色,它将允许多行具有颜色。具体来说,一行被设置为在点击时具有“特殊”颜色。在极少数情况下,尽管调用了setBackgroundColor,但最后一行被点击仍会保留颜色。

private OnItemClickListener mDirectoryListener = new OnItemClickListener(){
    public void onItemClick(AdapterView parent, View view, int pos, long id){
        if (stdir.getStationCount() == pos) {
            stdir.moreStations();  
            return;
        }

        if (playingView != null)
            playingView.setBackgroundColor(Color.DKGRAY);

        view.setBackgroundColor(Color.MAGENTA);
        playingView = view;
        playStation(pos);
    }
};

我已经通过print语句确认始终调用将行设置为灰色的代码。

有人能想象出这段代码可能间歇性失败的原因吗?如果存在导致它的模式或条件,我无法分辨。

我认为它可能与活动生命周期有关,将“playingView”变量设置为null,但我无法通过切换活动或锁定手机来可靠地重现问题。

private class DirectoryAdapter extends ArrayAdapter {
    private ArrayList<Station> items;

    public DirectoryAdapter(Context c, int resLayoutId, ArrayList<Station> stations){
        super(c, resLayoutId, stations);            
        this.items = stations;
    }

    public int getCount(){
        return items.size() + 1;
    }

    public View getView(int position, View convertView, ViewGroup parent){
        View v = convertView;
        LayoutInflater vi = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        if (position == this.items.size()) {
            v = vi.inflate(R.layout.morerow, null);
            return v;
        }

        Station station = this.items.get(position);
        v = vi.inflate(R.layout.songrow, null);

        if (station.playing)
            v.setBackgroundColor(Color.MAGENTA);
        else if (station.visited)
            v.setBackgroundColor(Color.DKGRAY);
        else
            v.setBackgroundColor(Color.BLACK);

        TextView title  = (TextView)v.findViewById(R.id.title);
        title.setText(station.name);
        return v;
    }    
};

1 个答案:

答案 0 :(得分:2)

ListViews不会为列表中的每个项创建包含视图的实例,而只会为屏幕上实际可见的项创建实例。出于性能原因,他们尝试尽可能少地保留视图,并回收它们。这就是convertView参数。

当视图滚动离开屏幕时,它可能会被回收或销毁。您不能保留对旧视图的引用,并假设它将引用您将来期望它的项目。您应该保存所需列表项的ID,而不是查看它。

此外,您的实施还存在其他一些问题(从最佳实践角度来看)。您似乎忽略了convertView参数并且每次都从头开始创建新视图。如果您有一个长列表,这可能会导致您的应用程序在滚动时陷入困境。其次,不要像你那样添加“更多”元素,而是使用setFooterView()设置它。

来自Google I / O 2010的excellent talk on the ListView涵盖了这些问题和其他问题。这是一个小时,但绝对值得一看。