android - 使用无限滚动android listview时出现内存不足错误

标签 android listview

我正在创建一个应用程序,它从 Internet 检索图像并将它们显示在无限滚动的 ListView 中。问题是滚动一段时间后出现内存不足错误。谁能告诉我我在这里做错了什么?谢谢

主要 Activity :

@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);

    }


}

自定义适配器:

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;
}

最佳答案

这里有一些提高列表性能和摆脱 OOM 的要点

  1. Android 应用程序的堆非常有限,因此您不应下载大量位图并将其存储在 List 中,它会引发 OOM。

    解决方案是在调用 getView() 时开始下载,所以不是 holder.img.setImageBitmap(imageId.get(position)); 你应该有一个下载图像的请求.

    在 Android 中管理图像列表很困难,您必须注意:

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

    为简单起见,我建议您使用这样的库:

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

    Glide.with(mContext)
        .load(IMAGE_URL)
        .into(holder.img);
    

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

  2. 来自安卓文档

Your code might call findViewById() frequently during the scrolling of ListView, which can slow down performance.

更多信息 here .

所以你必须将这些行移动到 if(rowView == 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);
  1. 您不应该在每次调用 getView() 时都创建一个新的 Holder!

这是 getView() 的正确实现

@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;
}

更多信息 here .

希望它的帮助:)

关于android - 使用无限滚动android listview时出现内存不足错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33064587/

相关文章:

c# - Winforms ListView MouseUp 事件多次触发

android - 如何从设备上的命令行卸载 android 应用程序

android - 无法从我的 Android 应用程序获取电话号码?

android - 如何删除 Android Studio 中的操作菜单?

android - 事件点击 android.support.design.widget.NavigationView 上的项目

java - 如何在 Material 设计世界中创建主/细节

java - 位于 ListView 行中的按钮总是在最后一行触发

android - ListView inside SwipeRefreshLayout inside Drawer(Layout) : does not lock scroll direction

Android ListView 字体大小和字体

java - 在 Android 布局中使用 ListView 滚动中间内容