无法在自定义适配器中使用LayoutInflater

8
我正在研究编写一个自定义适配器,以便在每行中填充3个文本视图的列表视图。我已经找到了很多例子代码来完成这个任务,但最好的一篇文章是在这里:http://www.anddev.org/custom_widget_adapters-t1796.html 在修复了最新Android SDK的一些编译器问题后,我对它进行了一些微小的调整,然后运行起来,但是却遇到了异常:
ERROR/AndroidRuntime(281): java.lang.UnsupportedOperationException: addView(View, LayoutParams) is not supported in AdapterView
因此,我进行了大量的研究,并找到了许多可能的原因和解决方法。但是没有一种方法能够改变现状。我的适配器代码目前如下:
public class WeatherAdapter extends BaseAdapter {

    private Context context;
    private List<Weather> weatherList;

    public WeatherAdapter(Context context, int rowResID,
                        List<Weather> weatherList ) { 
        this.context = context;
        this.weatherList = weatherList;
    }

    public int getCount() {                        
        return weatherList.size();
    }

    public Object getItem(int position) {     
        return weatherList.get(position);
    }

    public long getItemId(int position) {  
        return position;
    }

    public View getView(int position, View convertView, ViewGroup parent) { 
        Weather weather = weatherList.get(position);

        //LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        LayoutInflater inflater = LayoutInflater.from(context);

        View v = inflater.inflate(R.layout.weather_row, null, true);
        TextView cityControl = (TextView)v.findViewById( R.id.city );
        TextView temperatureControl = (TextView)v.findViewById( R.id.temperature );
        ImageView skyControl = (ImageView)v.findViewById( R.id.sky );
        return v;
    }

}

我已经尝试了获取inflater的注释方式和当前未注释的方式。我尝试将“parent”传递给inflate以及null,并传递“true”,“false”和完全省略最后一个参数。它们都没有起作用,到目前为止我找到的所有示例都来自于2008年,我感觉有点过时。

如果有人能帮忙解决这个问题,我会很感激。

4个回答

16

我认为这一行有问题:

View v = inflater.inflate(R.layout.weather_row, null, true);

你需要换成如下代码:

View v = inflater.inflate(R.layout.weather_row, parent, false);

false 设置后,膨胀视图与其父视图解除绑定,独立于其父视图存在。这在 AdapterView 中自定义视图时似乎是一种被广泛接受的设计方式,我对此感到非常困惑。但上述模式对我有效。


2
当使用AdapterView时,您希望视图独立于父级,getView()会为您处理将其附加到父级的工作。 - Austyn Mahoney
@AustynMahoney 我不会说 getView() 会处理它,因为是编写它的人,我更愿意说 调用getView()的任何东西(换句话说,框架)会负责附加由getView()返回的视图。 - Joffrey

6

我也是一个新手,所以这个答案请参考并谨慎使用——如果不起作用,请继续谷歌搜索。因为我通常使用 ListViewGridView 以及扩展自 BaseAdapter 的自定义 Adapter,所以不熟悉 AdapterView

您可以尝试在 WeatherAdapter 类内创建类似以下的内容:

public void addToList(Weather mWeather) {
    weatherList.add(mWeather);
}

接着,在调用 WeatherAdapter 的类中:

weatherAdapter.addToList(weatherToAdd);
weatherAdapter.notifyDataSetChanged();

此外,您需要在getView方法中进行更多的优化: http://www.youtube.com/watch?v=wDBM6wVEO70

3
针对 AdaptertView addView 方法:

void addView(View child)

这个方法不被支持,当被调用时会抛出 UnsupportedOperationException 异常。" (来自Android文档)

可能是由于膨胀程序调用了 addView 方法,而从 AdapterView 或其 AdapterView 中无法进行此操作。
根据文档描述:

"Adapter 对象充当 AdapterView 和该视图的底层数据之间的桥梁。适配器提供对数据项的访问。适配器还负责为数据集中的每个项目制作视图"。

我认为可以从一个简单的 Activity 模型中完成膨胀操作和所有其他操作,例如在其他类中检索数据和显示数据。
希望这能够有所帮助!

1

@Axel22的回答很关键,但你的代码还有一些其他问题。首先,根据您的喜好,应该扩展BaseAdapter或ArrayAdapter之一。其次,您应该习惯使用ViewHolder来避免过多调用findViewById,并(最重要的)回收您的View。

private Class ViewHolder {
  public TextView cityControl;
  public TextView temperatureControl;
  public ImageView skyControl;
  public ViewHolder(TextView cityControl, TextView temperatureControl, ImageView skyControl) {
    this.cityControl = cityControl;
    this.temperatureControl = temperatureControl;
    this.skyControl = skyControl;
  }

您的getView函数可以重复使用视图,并使用以下方式利用ViewHolder类:
public View getView(int position, View convertView, ViewGroup parent) { 
    Weather weather = weatherList.get(position);
    // This is how you attempt to recycle the convertView, so you aren't 
    // needlessly inflating layouts.
    View v = convertView;
    ViewHolder holder;
    if (null == v) {
        v = LayoutInflater.from(getContext()).inflate(R.layout.weather_row, parent, false);
        TextView cityControl = (TextView)v.findViewById( R.id.city );
        TextView temperatureControl = (TextView)v.findViewById( R.id.temperature );
        ImageView skyControl = (ImageView)v.findViewById( R.id.sky );
        holder = new ViewHolder(cityControl, temperatureControl, skyControl);
        v.setTag(holder);
    } else {
        holder = (ViewHolder) v.getTag();
    }

    holder.cityControl.setText("Metropolis");
    holder.temperatureControl.setText("78");
    holder.skyControl.setImageResource(R.drawable.daily_planet);

    return v;

}

如果想要更多示例(以及其他优化技巧),请参考此博客文章(或者直接搜索ViewHolder)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接