使用无限滚动android listview时出现错误

时间:2015-10-11 11:46:04

标签: android listview

我正在创建一个从互联网上检索图像的应用程序,并将它们显示在带有无限滚动的列表视图中。问题是我在滚动一段时间后出现了错误的错误。谁能告诉我这里做错了什么?谢谢

MainActivity:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
      context=this;

     fetchPosts(lPost);
       lv=(ListView) findViewById(R.id.listView1);
       lv.setOnScrollListener(new InfiniteScrollListener(5) {
            @Override
            public void loadMore(int page, int totalItemsCount) {
                fetchPosts(lPost);
            }
        });

        cAdapter = new CustomAdapter(this, prgmNameList,prgmImages, prgmLikeNum, prgmCommentNum);
        lv.setAdapter(cAdapter);

}       



public void fetchImages(String imageName, int position) {

    loadImage task = new loadImage(MainActivity.this, R.id.listView1, imageName, position );

    task.setOnResultsListener(MainActivity.this); 
    task.execute("null");
}

public void fetchPosts(int lastPost){
    LoadPosts lTask = new LoadPosts(MainActivity.this, lastPost);

    lTask.setOnResultsListener(MainActivity.this);
    lTask.execute("asd");

}

@Override
public void onResultsSucceeded(Bitmap image, int position) {

            if(prgmImages.size() > position)
            {
                if(lPost==0)
                    prgmImages.set(position, image);
                else
                    prgmImages.set(position+lPost-5, image);
            }

                    cAdapter.notifyDataSetChanged();

}



@Override
public void onPostsSucceeded(JSONArray obj) throws JSONException {

    //tView.setText(obj.toString());
    lPost += obj.length();

    for (int i = 0; i < obj.length(); i++) {
        JSONObject object = obj.getJSONObject(i);
        String postTitle = object.getString("post_title");
        String imageName = object.getString("image_name");
        String likeNum = object.getString("like_num");
        String commentNum = object.getString("comment_num");
        fetchImages(imageName, i);
        prgmImages.add(null);
        prgmNameList.add(postTitle);
        prgmLikeNum.add(likeNum);
        prgmCommentNum.add(commentNum);

    }


}

CustomAdapter:

public CustomAdapter(MainActivity mainActivity, ArrayList<String>              prgmNameList, ArrayList<Bitmap> prgmImages, ArrayList<String> prgmLikeNum, ArrayList<String> prgmCommentNum) {
    // TODO Auto-generated constructor stub
     context=mainActivity;
     activity=mainActivity;
     inflater = ( LayoutInflater )context.
             getSystemService(Context.LAYOUT_INFLATER_SERVICE);

     result = prgmNameList;
     imageId=prgmImages;
     likeNum=prgmLikeNum;
     commentNum=prgmCommentNum;

}






public class Holder
{
    TextView tv;
    ImageView img;
    TextView likes;
    TextView comments;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    // TODO Auto-generated method stub
    holder=new Holder();
    View rowView = convertView;   
    if(rowView == null)
    {
         rowView = inflater.inflate(R.layout.post_item, null);
    }
         holder.tv=(TextView) rowView.findViewById(R.id.postTitle);
         holder.img=(ImageView) rowView.findViewById(R.id.postImage);       
         holder.likes=(TextView) rowView.findViewById(R.id.likeNum);
         holder.comments=(TextView) rowView.findViewById(R.id.commentNum);
         holder.tv.setText(result.get(position));
         holder.img.setImageBitmap(imageId.get(position));
         holder.likes.setText(likeNum.get(position));
         holder.comments.setText(commentNum.get(position));
     rowView.setOnClickListener(new OnClickListener() {            
        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
         //   Toast.makeText(context, "You Clicked "+result[position], Toast.LENGTH_LONG).show();
        }
    });   
    return rowView;
}

2 个答案:

答案 0 :(得分:2)

以下是一些可以提高列表性能并摆脱OOM的要点

  1. Android应用程序的堆非常有限,因此您不应该在List中下载和存储大量的Bitmap,它会触发OOM。

    解决方案是在调用getView()时开始下载,因此您应该要求holder.img.setImageBitmap(imageId.get(position));而不是Glide.with(mContext) .load(IMAGE_URL) .into(holder.img); 下载图像。

    在Android中管理图片列表很困难,你必须要注意:

    • 重新调整位图大小
    • 线程并发
    • 缓存管理

    为简单起见,我建议您使用以下库:

    例如,要使用Glide下载图像,您需要:

    if(rowView == null)

    Glide / Picasso将管理位图大小调整,并发和缓存:)

  2. 来自android doc

  3.   

    在滚动ListView期间,您的代码可能经常调用findViewById(),这会降低性能。

    更多信息here

    所以你必须将这些行移到holder.tv=(TextView) rowView.findViewById(R.id.postTitle); holder.img=(ImageView) rowView.findViewById(R.id.postImage); holder.likes=(TextView) rowView.findViewById(R.id.likeNum); holder.comments=(TextView) rowView.findViewById(R.id.commentNum); 条件

    getView()
    1. 您不应在每次getView()来电时创建新的持有人!
    2. 以下是@Override public View getView(final int position, View convertView, ViewGroup parent) { Holder holder; // Check if the item's view is recycled if(convertView == null) { // The item's view doesn't exist // Create the item's view LayoutInflater inflater = ((Activity) mContext).getLayoutInflater(); convertView = inflater.inflate(R.layout.post_item, null); holder = new Holder(); // Create the holder holder.tv=(TextView) rowView.findViewById(R.id.postTitle); holder.img=(ImageView) rowView.findViewById(R.id.postImage); holder.likes=(TextView) rowView.findViewById(R.id.likeNum); holder.comments=(TextView) rowView.findViewById(R.id.commentNum); // Store the holder with the view. convertView.setTag(holder); } else { // The item's view already exist // Retrieve the older holder = (Holder) convertView.getTag(); } holder.tv.setText(result.get(position)); holder.img.setImageBitmap(imageId.get(position)); Glide.with(mContext) .load(imageUrls.get(position)) .into(holder.img) holder.likes.setText(likeNum.get(position)); holder.comments.setText(commentNum.get(position)); convertView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO impl } }); return convertView; }

      的正确实现
      {{1}}

      更多信息here

      希望它的帮助:)

答案 1 :(得分:0)

您似乎加载了很多位图,如果不再使用它们,则不会释放内存。

你可以这样做(当位图是你不再需要的位图时)

bitmap.recycle();
bitmap=null;

在适配器类中使用持有者时出错。这不会影响内存问题,但会降低应用的性能。通常,您使用视图来避免经常调用findViewById。如果rowview == null,则应在viewholder和layout之间链接一次。 如果你已经完成了这个,并且第二次从getView加载相同的视图,则rowview将是!= null,你不需要再调用findViewById,这样可以节省大量的时间。

所以你的代码应该是这样的:

if(rowview==null)
 {
  rowView = inflater.inflate(R.layout.post_item, null);
  holder.tv=(TextView) rowView.findViewById(R.id.postTitle);
  holder.img=(ImageView) rowView.findViewById(R.id.postImage);       
  holder.likes=(TextView) rowView.findViewById(R.id.likeNum);
  holder.comments=(TextView) rowView.findViewById(R.id.commentNum);
 }
 holder.tv.setText(result.get(position));
 holder.img.setImageBitmap(imageId.get(position));
 holder.likes.setText(likeNum.get(position));
 holder.comments.setText(commentNum.get(position));
 rowView.setOnClickListener(new OnClickListener() {            
    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
     //   Toast.makeText(context, "You Clicked "+result[position], Toast.LENGTH_LONG).show();
    }
});