【问题标题】:ViewHolder in ListView adapter not workingListView 适配器中的 ViewHolder 不起作用
【发布时间】:2014-01-30 15:55:56
【问题描述】:

我一直在尝试使用 ViewPager 使我的 ListView 滚动更流畅,但它一直在崩溃。我尝试了大约 3 种类型的解决方案。屏幕打开,显示加载指示器,但过了一会儿(大约 3-5 秒)它崩溃了。要从 URL 加载图像,我使用 nostra13 的Universal-Image-Loader lib。在不添加 ViewHolder 的情况下一切正常。

适配器类中的我的 LogCat 和 getView + ViewHolder:

LogCat

    01-30 17:01:53.713: E/AndroidRuntime(12702): FATAL EXCEPTION: main
01-30 17:01:53.713: E/AndroidRuntime(12702): java.lang.NullPointerException
01-30 17:01:53.713: E/AndroidRuntime(12702):    at com.example.animalist.AnimalAdapter$1.onLoadingComplete(AnimalAdapter.java:123)
01-30 17:01:53.713: E/AndroidRuntime(12702):    at com.nostra13.universalimageloader.core.DisplayBitmapTask.run(DisplayBitmapTask.java:74)
01-30 17:01:53.713: E/AndroidRuntime(12702):    at android.os.Handler.handleCallback(Handler.java:587)
01-30 17:01:53.713: E/AndroidRuntime(12702):    at android.os.Handler.dispatchMessage(Handler.java:92)
01-30 17:01:53.713: E/AndroidRuntime(12702):    at android.os.Looper.loop(Looper.java:143)
01-30 17:01:53.713: E/AndroidRuntime(12702):    at android.app.ActivityThread.main(ActivityThread.java:4263)
01-30 17:01:53.713: E/AndroidRuntime(12702):    at java.lang.reflect.Method.invokeNative(Native Method)
01-30 17:01:53.713: E/AndroidRuntime(12702):    at java.lang.reflect.Method.invoke(Method.java:507)
01-30 17:01:53.713: E/AndroidRuntime(12702):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
01-30 17:01:53.713: E/AndroidRuntime(12702):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
01-30 17:01:53.713: E/AndroidRuntime(12702):    at dalvik.system.NativeStart.main(Native Method)
01-30 17:01:57.957: I/wpa_supplicant(15739): Reset vh_switch_counter due to receive LINKSPEED cmd

在 AnimalAdapter.java - getView + ViewHolder

 static class ViewHolder{
        TextView animalView;
        TextView areaView;
        ImageView notfound;
        ImageView animalPic;
        ProgressBar indicator;
    }
    
    
    public View getView(int position, View convertView, ViewGroup parent){
        
        ViewHolder holder = null;
        
        
        
        if(convertView == null){
              LayoutInflater mLayoutInflater = LayoutInflater.from(mContext);
              convertView = mLayoutInflater.inflate(R.layout.animal_row_item, null);
              holder = new ViewHolder();
              
             holder.animalView = (TextView) convertView.findViewById(R.id.animal_text);
              holder.areaView = (TextView) convertView.findViewById(R.id.area_text);
            holder.notfound = (ImageView) convertView.findViewById(R.id.notfoundimg);
              holder.animalPic = (ImageView)convertView.findViewById(R.id.animal_pic);
              holder.indicator = (ProgressBar)convertView.findViewById(R.id.progress);
               convertView.setTag(holder);
          }
          
        else{
            holder = (ViewHolder) convertView.getTag();
                    
        }  
        
          final Animal animal = mAnimals.get(position);
          
          
          
          
          holder.notfound.setVisibility(View.INVISIBLE);
          holder.indicator.setVisibility(View.VISIBLE);
          holder.animalPic.setVisibility(View.INVISIBLE);
          
            //Setup a listener we can use to switch from the loading indicator to the Image once it's ready
            ImageLoadingListener listener = new ImageLoadingListener(){


                ViewHolder holder = null;
                @Override
                public void onLoadingStarted(String arg0, View arg1) {
                    // TODO Auto-generated method stub

                }

                @Override
                public void onLoadingCancelled(String arg0, View arg1) {
                    // TODO Auto-generated method stub

                }

                @Override
                public void onLoadingComplete(String arg0, View arg1, Bitmap arg2) {
                    holder.indicator.setVisibility(View.INVISIBLE);
                    holder.animalPic.setVisibility(View.VISIBLE);
                    holder.notfound.setVisibility(View.INVISIBLE);
                }

                @Override
                public void onLoadingFailed(String arg0, View view, FailReason arg2) {
                    holder.notfound.setVisibility(View.VISIBLE);
                    holder.indicator.setVisibility(View.INVISIBLE);
                    holder.animalPic.setVisibility(View.INVISIBLE);
                }

            };

            
            
          imageLoader.displayImage(animal.getImgUrl(), holder.animalPic,options, listener);
          holder.animalView.setText(animal.getAnimal());
          holder.areaView.setText(animal.getArea());
          
          
          
          
          
          convertView.setOnClickListener(new OnClickListener() {
              
                @Override
                public void onClick(View view) {
                    
                    Intent intent = new Intent(getContext(), MoreActivity.class);
                    
                    intent.putExtra("about", animal.getAbout());
                    intent.putExtra("animal", animal.getAnimal());
                    intent.putExtra("imgUrl", animal.getImgUrl());
                    getContext().startActivity(intent);
                }
          });
          
          return convertView;
      }

你有什么想法,如何改进它?

提前致谢

【问题讨论】:

  • 你的 AnimalAdapter.java 的第 82 行是什么?
  • 删除View vi = convertView;并使用if(convertView == null){convertView = mLayoutInflater.inflate(R.layout.animal_row_item, null);
  • 您好,非常感谢您的回答,这是真的。但我得到不同的(但我认为不那么严重)错误。我更新了我的代码
  • 我知道这与您的问题 100% 相关,但恕我直言,您应该停止使用 Universalimageloader 并改用 Picasso (square.github.io/picasso) 更简单、更稳定、更强大。
  • 感谢推荐!我一定会试试的

标签: java android listview android-adapter universal-image-loader


【解决方案1】:

你在堆栈跟踪中的事实

01-30 16:45:09.003: E/AndroidRuntime(12533):    at android.widget.ListView.measureHeightOfChildren(ListView.java:1264)
01-30 16:45:09.003: E/AndroidRuntime(12533):    at android.widget.ListView.onMeasure(ListView.java:1127)

建议您返回的 convertView 是 null

关于您的第二个问题,ImageLoadingListener 中的 ViewHolder 实例始终为null。您应该注意相应地对其进行初始化

【讨论】:

  • 你知道如何更好地初始化它吗?现在它终于加载了我的文本对象,当它加载图像时,它崩溃了。所以问题肯定存在
【解决方案2】:

我认为您的逻辑不对,在您测试的getView() 方法中:

if (vi == null){

但是你应该测试是否:

if (convertView == null) {

尝试更改它,应该可以这样。

---- 编辑----

您初始化ViewHolder 的方式对我来说似乎没问题,然后您通过findViewById() 为每个实例分配一个View,这没关系 - 如果您得到一个设置可见性的NullPointerException,这意味着出于某种原因,findViewById() 返回了一个空对象 - 即,它没有找到名称为 R.id.progress 的 id(可能在您的布局中没有使用该名称的此类元素)。

---- 编辑----

下面是我的适配器 getView() 方法的示例:

public static class vhItem {
  TextView maintext;
  TextView topictext; 
  ImageView mainimage;
  TextView users; 
}

@Override
public View getView(final int position, View convertView, final ViewGroup parent) {
  vhItem viewHolder;

  if (convertView == null) {
    final LayoutInflater inflater = ((Activity) context).getLayoutInflater();
    convertView = inflater.inflate(resourceId, parent, false);

    viewHolder = new vhItem();
    viewHolder.maintext = (TextView) convertView.findViewById(R.id.chanlist_chan);
    viewHolder.topictext = (TextView) convertView.findViewById(R.id.chanlist_topic);
    viewHolder.mainimage = (ImageView) convertView.findViewById(R.id.chanlist_featured);
    viewHolder.users = (TextView) convertView.findViewById(R.id.chanlist_usercount);

    // I've set a contextual menu for each row this way, but it's not required
    ((Activity) context).registerForContextMenu(convertView);
  }
  else
    viewHolder = (vhItem) convertView.getTag();

  viewHolder.maintext.setText((String) getItem(position));
  viewHolder.mainimage.setTag(getItem(position));
  viewHolder.mainimage.setOnClickListener(new View.OnClickListener() {
    public void onClick(final View v) {
      AlertDialog.Builder builder = new AlertDialog.Builder(context);
      ...
      dialog.show();
    }
  });

  return convertView; 
}

【讨论】:

  • getView OP的第一行设置converViewvi,这不是问题
  • 您好,非常感谢您的回答,这是真的。但我得到不同的(但我认为不那么严重)错误。我更新了我的代码
  • holder.indicator.setVisibility(View.INVISIBLE); 当我删除它时,它会在下面的列中显示错误,依此类推
  • @Marson indicator 是空检查初始化和 id。你所有的初始化都是错误的
  • @Marson 我已经更新了我的答案,看看它是否适合你的场景。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-08-22
  • 1970-01-01
  • 2021-07-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-22
相关资源
最近更新 更多