listview wychodzi poza wyjątek pamięci, ale nie ma przecieków pamięci?

Po Honeycomb, Google powiedział, że bitmapy są zarządzane przez stertę (o której mówionotutaj), więc jeśli bitmapa nie jest już dostępna, możemy założyć, że GC się tym zajmuje i uwalnia ją.

Chciałem stworzyć demo, które pokazuje skuteczność pomysłów pokazanych na wykładzie listView (ztutaj), więc zrobiłem małą aplikację. Aplikacja umożliwia użytkownikowi naciśnięcie przycisku, a następnie przeglądanie listy przewija się aż do samego dołu, podczas gdy ma 10000 pozycji, których treścią są elementy android.R.drawable (nazwa i obraz).

Z jakiegoś powodu tracę pamięć, mimo że nie zapisuję żadnych obrazów, więc moje pytanie brzmi: jak to możliwe? Czego mi brakuje?

Przetestowałem aplikację na Galaxy S III, a mimo to wciąż korzystam z wyjątków pamięci, jeśli używam rodzimej wersji adaptera. Nie rozumiem, dlaczego tak się dzieje, ponieważ niczego nie przechowuję.

Oto kod:

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

@all: Wiem, że istnieją optymalizacje dla tego kodu (przy użyciu konwertującego widoku i wzorca widoku viewHolder), ponieważ wspomniałem o wideo z listyView stworzonej przez Google. Uwierz mi, wiem, co jest lepsze; to jest cały punkt kodu.

Powyższy kod ma pokazać, że lepiej jest używać tego, co pokazujesz (i wideo). Ale najpierw muszę pokazać naiwny sposób; nawet naiwny sposób powinien nadal działać, ponieważ nie przechowuję map bitowych ani widoków, a ponieważ Google wykonał ten sam test (stąd otrzymali wykres porównania wydajności).

questionAnswers(4)

yourAnswerToTheQuestion