【问题标题】:convertView is being passed as null even if the view exists即使视图存在,convertView 也作为 null 传递
【发布时间】:2011-08-05 09:04:25
【问题描述】:

我开发了一个 android 应用程序,其中图像和文本显示在网格视图中,并且当用户向下滚动时会显示接下来的十个项目(图像和文本)。在调用 adapter.notifyDataSetChanged() 之后调用适配器的 getView 方法时会出现问题。适配器回收数据,但位置在网格视图中重新排列和重复。在我添加条件以检查 convertView 是否为空之前,我没有遇到过这个问题。

活动类:

public class DynamicListViewActivity extends Activity implements
    OnScrollListener {

int visibleElements;
int scrollState;
int count;
TextAdapter adapter = new TextAdapter();
int total=200;// total items limit in grid view


@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.grid);
    count=10;
    GridView grid = (GridView) findViewById(R.id.gridview);
    grid.setAdapter(adapter);
    grid.setOnScrollListener(this);

}

public void onScroll(AbsListView view, int firstVisible, int visibleCount,
        int totalCount) {
    visibleElements= visibleCount;
}

public void onScrollStateChanged(AbsListView v, int s) {
    Log.d("ScrollState", s+"");
    scrollState=s;
    isScrollStateComplete();
}

public void isScrollStateComplete(){
if(visibleElements>0 && scrollState==SCROLL_STATE_IDLE && total>count){
        int diff=total-count;
        count+=(diff>=10)?10:diff;//update count to next ten items
        adapter.notifyDataSetChanged();
    }
}


class TextAdapter extends BaseAdapter {
    public int getCount() {
        return count;
    }

    public Object getItem(int pos) {
        return pos;
    }

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

    public View getView(int pos, View convertView, ViewGroup p) {

        View v = convertView;
        System.out.println("pos : "+pos+" boolean "+(v==null));// log to check position and convertView
                  if(v==null){
            v =((LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.textlayout,null);

            ImageView iv = (ImageView) v.findViewById(R.id.album_thumbnail);
            iv.setImageDrawable(getResources().getDrawable(R.drawable.icon));

            TextView tvAlbumName = (TextView)v.findViewById(R.id.album_name);
            tvAlbumName.setText("postion "+pos);

            TextView tvAlbumDesc = (TextView)v.findViewById(R.id.album_description);
            tvAlbumDesc.setText("");

           }

          return v;
    }
}
}

在滚动网格视图正确显示之前。日志:

08-05 14:24:34.440: INFO/ActivityManager(58): Starting activity: Intent {  act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.mis.list.demo/.DynamicListViewActivity }
08-05 14:24:34.642: INFO/System.out(685): pos : 0 boolean true
08-05 14:24:34.710: INFO/System.out(685): pos : 0 boolean false
08-05 14:24:34.710: INFO/System.out(685): pos : 1 boolean true
08-05 14:24:34.730: INFO/System.out(685): pos : 2 boolean true
08-05 14:24:34.800: INFO/System.out(685): pos : 3 boolean true
08-05 14:24:34.860: INFO/System.out(685): pos : 4 boolean true
08-05 14:24:34.880: INFO/System.out(685): pos : 5 boolean true
08-05 14:24:34.910: INFO/System.out(685): pos : 6 boolean true
08-05 14:24:34.920: INFO/System.out(685): pos : 7 boolean true
08-05 14:24:34.960: INFO/System.out(685): pos : 0 boolean true
08-05 14:24:35.030: INFO/ActivityManager(58): Displayed activity com.mis.list.demo/.DynamicListViewActivity: 520 ms (total 520 ms)

滚动结束后

08-05 14:26:15.740: DEBUG/ScrollState(685): 1
08-05 14:26:15.830: DEBUG/dalvikvm(685): GC_EXTERNAL_ALLOC freed 3624 objects / 257464 bytes in 71ms
08-05 14:26:16.210: INFO/System.out(685): pos : 8 boolean false
08-05 14:26:16.210: INFO/System.out(685): pos : 9 boolean true
08-05 14:26:16.250: DEBUG/ScrollState(685): 0
08-05 14:26:16.260: INFO/System.out(685): pos : 0 boolean true
08-05 14:26:16.271: INFO/System.out(685): pos : 0 boolean false
08-05 14:26:16.271: INFO/System.out(685): pos : 1 boolean false
08-05 14:26:16.271: INFO/System.out(685): pos : 2 boolean false
08-05 14:26:16.271: INFO/System.out(685): pos : 3 boolean false
08-05 14:26:16.271: INFO/System.out(685): pos : 4 boolean false
08-05 14:26:16.271: INFO/System.out(685): pos : 5 boolean false
08-05 14:26:16.280: INFO/System.out(685): pos : 6 boolean false
08-05 14:26:16.280: INFO/System.out(685): pos : 7 boolean false
08-05 14:26:16.280: INFO/System.out(685): pos : 8 boolean false
08-05 14:26:16.280: INFO/System.out(685): pos : 9 boolean false
08-05 14:26:16.280: INFO/System.out(685): pos : 10 boolean false
08-05 14:26:16.280: INFO/System.out(685): pos : 11 boolean true
08-05 14:26:16.371: DEBUG/dalvikvm(685): GC_EXTERNAL_ALLOC freed 644 objects / 33224 bytes in 41ms
08-05 14:26:45.270: WARN/KeyCharacterMap(685): No keyboard for id 0
08-05 14:26:45.270: WARN/KeyCharacterMap(685): Using default keymap: /system/usr/keychars/qwerty.kcm.bin
08-05 14:26:45.341: INFO/System.out(685): pos : 12 boolean true
08-05 14:26:45.351: INFO/System.out(685): pos : 13 boolean true
08-05 14:26:45.371: INFO/System.out(685): pos : 14 boolean true
08-05 14:26:45.380: INFO/System.out(685): pos : 15 boolean true
08-05 14:26:45.450: INFO/System.out(685): pos : 16 boolean false
08-05 14:26:45.450: INFO/System.out(685): pos : 17 boolean false
08-05 14:26:45.460: INFO/System.out(685): pos : 18 boolean false
08-05 14:26:45.460: INFO/System.out(685): pos : 19 boolean false

但网格显示重复值,而不是按应有的顺序显示。 对不起,我是新用户,不允许发布图片。

在日志中我看到位置 0 convertView==null 为真。

当我计划下载图像以代替当前使用的图像视图的 android 图标时,如何设置此权限。

请帮忙。

【问题讨论】:

  • 如果没有View可以复用,Android会将null传递给convertView参数

标签: android gridview adapter convertview


【解决方案1】:

您对 convertView 的解释不正确。

public View getView(int position, @Nullable View convertView, ViewGroup parent) {

    View v = convertView;

    //If convertView is null create a new view, else use convert view
    if (v == null)
        v = ((LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.textlayout, null);

    ImageView iv = (ImageView) v.findViewById(R.id.album_thumbnail);
    iv.setImageDrawable(getResources().getDrawable(R.drawable.icon));

    TextView tvAlbumName = (TextView)v.findViewById(R.id.album_name);
    tvAlbumName.setText("postion "+pos);

    TextView tvAlbumDesc = (TextView)v.findViewById(R.id.album_description);
    tvAlbumDesc.setText("");

    return v;
}

是你应该做的。

由于您所做的事情,在 convertView 不为空的情况下,您只是返回了 convertView 而没有更新您的数据,因此您的图像被重复了。只有在convertView 为空的情况下,您才会设置数据。

适配器与列表视图系统之间的约定:如果传递的convertView为空,则新建一个,否则重复使用。

【讨论】:

  • 感谢您的回复 vikram。但我正在做同样的事情,因为我不希望重新创建现有视图。正如你所看到的代码。如果 convertView 为空,则创建视图并最终返回视图。我什至添加了一条 else 语句来检查这是否可行,但结果是一样的。
  • 你必须把它留给系统。系统对此进行了优化。此外,当调用 getView(View,Position) 时,您必须使用 Position 处的数据更新 View,而您没有这样做。 [观看](www.youtube.com/watch?v=wDBM6wVEO70)
  • 嘿,谢谢维克拉姆。我会检查并纠正。万分感谢。现在我懂了。 :)
  • 我曾尝试使用此示例:androidarena.co.in/… 但面临与问题相同的问题。代码哪里出错了?
【解决方案2】:

Vikram Bodicherla 是正确的 (+1),您的实现不正确,他的代码示例正确地解决了您的问题。不过,我想推荐以下 Google I/O 2010 演讲:The world of ListView。时长一小时,但您将对ListView 的工作原理以及如何编写适配器以正确配合它有更深入的了解。

【讨论】:

    【解决方案3】:

    如果 Android 确定代表一行的 View 不再可见,它允许 getView() 方法通过 convertView 参数重用它。

    性能优化的适配器将新数据分配给 convertView。这样可以避免扩展 XML 文件和创建新的 Java 对象。

    如果没有 View 可供重用,Android 会将 null 传递给 convertView 参数。因此,适配器实现需要对此进行检查。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-08-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-07
      • 2017-11-25
      • 2017-03-20
      相关资源
      最近更新 更多