listview内存异常,但没有内存泄漏?

and*_*per 3 android garbage-collection out-of-memory android-3.0-honeycomb android-4.0-ice-cream-sandwich

在Honeycomb之后,Google表示位图是由堆管理的(这里谈到),所以如果不再可以访问位图,我们可以假设GC处理它并释放它.

我想创建一个演示,显示为listView讲座(从这里)显示的想法的效率,所以我做了一个小应用程序.该应用程序允许用户按下按钮,然后列表视图一直滚动到底部,而它有10000个项目,其内容是android.R.drawable项目(名称和图像).

出于某种原因,即使我没有保存任何图像,我也会内存不足,所以我的问题是:它怎么可能?我错过了什么?

我已经在Galaxy S III上测试了应用程序,但是如果我使用适配器的原生版本,我会不断出现内存异常.我不明白为什么会这样,因为我不存储任何东西.

这是代码:

public class MainActivity extends Activity
  {
  private static final int LISTVIEW_ITEMS =10000;
  long                     _startTime;
  boolean                  _isMeasuring   =false;

  @Override
  public void onCreate(final Bundle savedInstanceState)
    {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    final ListView listView=(ListView)findViewById(R.id.listView);
    final Field[] fields=android.R.drawable.class.getFields();
    final LayoutInflater inflater=(LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    // listen to scroll events , so that we publish the time only when scrolled to the bottom:
    listView.setOnScrollListener(new OnScrollListener()
      {
        @Override
        public void onScrollStateChanged(final AbsListView view,final int scrollState)
          {
          if(!_isMeasuring||view.getLastVisiblePosition()!=view.getCount()-1||scrollState!=OnScrollListener.SCROLL_STATE_IDLE)
            return;
          final long stopTime=System.currentTimeMillis();
          final long scrollingTime=stopTime-_startTime;
          Toast.makeText(MainActivity.this,"time taken to scroll to bottom:"+scrollingTime,Toast.LENGTH_SHORT).show();
          _isMeasuring=false;
          }

        @Override
        public void onScroll(final AbsListView view,final int firstVisibleItem,final int visibleItemCount,final int totalItemCount)
          {}
      });
    // button click handling (start measuring) :
    findViewById(R.id.button).setOnClickListener(new OnClickListener()
      {
        @Override
        public void onClick(final View v)
          {
          if(_isMeasuring)
            return;
          final int itemsCount=listView.getAdapter().getCount();
          listView.smoothScrollToPositionFromTop(itemsCount-1,0,1000);
          _startTime=System.currentTimeMillis();
          _isMeasuring=true;
          }
      });
    // creating the adapter of the listView
    listView.setAdapter(new BaseAdapter()
      {
        @Override
        public View getView(final int position,final View convertView,final ViewGroup parent)
          {
          final Field field=fields[position%fields.length];
          // final View inflatedView=convertView!=null ? convertView : inflater.inflate(R.layout.list_item,null);
          final View inflatedView=inflater.inflate(R.layout.list_item,null);
          final ImageView imageView=(ImageView)inflatedView.findViewById(R.id.imageView);
          final TextView textView=(TextView)inflatedView.findViewById(R.id.textView);
          textView.setText(field.getName());
          try
            {
            final int imageResId=field.getInt(null);
            imageView.setImageResource(imageResId);
            }
          catch(final Exception e)
            {}
          return inflatedView;
          }

        @Override
        public long getItemId(final int position)
          {
          return 0;
          }

        @Override
        public Object getItem(final int position)
          {
          return null;
          }

        @Override
        public int getCount()
          {
          return LISTVIEW_ITEMS;
          }
      });
    }
  }
Run Code Online (Sandbox Code Playgroud)

@all:我知道这个代码有优化(使用convertView和viewHolder设计模式),因为我已经提到过Google制作的listView视频.相信我,我知道什么更好; 这是代码的重点.

上面的代码应该表明最好使用你(和视频)显示的内容.但首先我需要表现出天真的态度; 即使是天真的方式仍然可以工作,因为我不存储位图或视图,并且因为Google已经完成了相同的测试(因此他们得到了性能比较图).

Joe*_*Joe 7

蒂姆评论很有见.您的代码不会convertView在其BaseAdapter.getView()方法中使用并且每次都持续膨胀新视图的事实是导致它最终耗尽内存的主要原因.

上次我检查时,ListView将保留该getView()方法在其内部"回收站"容器中返回的所有视图,只有当ListView它与窗口分离时才会被清除.这个"回收站"是它如何生产所有这些convertViewgetView()在适当时将其供应回来.

作为测试,您甚至可以注释掉为视图指定图像的代码部分:

                // final int imageResId = field.getInt(null);
                // imageView.setImageResource(imageResId);
Run Code Online (Sandbox Code Playgroud)

你仍然会在一点上得到内存分配失败:)