title: OutOfMemoryError caused by multiple (>120) calls of getView in GridView
body: <p>I am using a GridView to display images. The images are downloaded from a feed and added to a BitmapCache. The GridView is inside of a ViewFlipper (which has a ListView as second View). I'm using GridView for the first time but I've worked with Adapters many times when I used ListViews.</p>
  
  <p>At the moment, the feed only delivers two images. But when I start my Fragment containing the GridView I get an OutOfMemoryError caused bei BitmapFactory.decodeStream(). When I took a deeper look into the logcat, I noticed that getView() inside of my Adapter for the GridView is called many many times. 
  I know that it's nothing special if getView() is called more than once, but the getView()-method in my Adapter gets called over 120 times only for position 0. And I don't really understand why it's called so often. But I'm pretty sure that this caused my memory problem as this method tries to load a bitmap over 100 times in just a few seconds. </p>
  
  <p>As I'm already trying to recycle my view with a ViewHolder I'm quite helpless at the moment and I hope somebody can explain me this massive calls of getView() and/or might give me a hint to solve my problem.</p>
  
  <p>The getView()-mthod of my adapter:</p>
  
  <pre><code>@Override
  public View getView(int position, View convertView, ViewGroup parent) {
      ViewHolder holder;
  
      LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  
      if (convertView == null) {
          holder = new ViewHolder();
          convertView = inflater.inflate(R.layout.pictures_grid_item, parent, false);
          holder.image = (ImageView) convertView.findViewById(R.id.picturesGridImage);
          convertView.setTag(holder);
      } else {
          holder = (ViewHolder) convertView.getTag();
          holder.image.setImageBitmap(null);
      }
  
      Picture picture = (Picture) pictureList.get(position);
      String imageUrl = picture.getUrl();
  
      if (!TextUtils.isEmpty(imageUrl)) {
          holder.image.setTag(imageUrl);
          ImageLoader.getInstance(context).loadImageWithTagCheck(holder.image);
      }
  
      return convertView;
  }
  
  
  private static class ViewHolder {
      ImageView image;
  }
  </code></pre>
  
  <p>The <em>loadImageWithTagCheck()</em>-method just checks if the image has already been downloaded (which deffinitely should be the case)</p>
  
  <p>The Fragment which holds the View:</p>
  
  <pre><code>public class PicturesFragment extends BaseFragment {
  
  private List&lt;Parcelable&gt; pictureList;
  private PicturesGridAdapter adapter;
  
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
      View view = inflater.inflate(R.layout.pictures_fragment, container, false);
      // TODO: Remove final after development
      final MediaActivity activity = (MediaActivity) getActivity();
  
      pictureList = activity.getPictures();
  
      adapter = new PicturesGridAdapter(activity, pictureList);
  
      GridView gridview = (GridView) view.findViewById(R.id.picturesGrid);
      gridview.setAdapter(adapter);
  
      gridview.setOnItemClickListener(new OnItemClickListener() {
          @Override
          public void onItemClick(AdapterView&lt;?&gt; parent, View v, int position, long id) {
              Toast.makeText(activity, "" + position, Toast.LENGTH_SHORT).show();
          }
      });
      return view;
  }
  }
  </code></pre>
  
  <p>BTW: I'm not using *wrap_content* anywhere.</p>
  
  <p>Edit:
  Here's the code of the imageloader. Ofcourse, the ImageLoader is the problem which causes the outOfMemoryError. But I think that the problem is rather something with the adapter because 120 calls of getView() for position 0 just after creating the view can't be right. And the Adapter is just created once so it's >120 calls in a single instance of my adapter.
  (this is a pretty huge and complex project so the "simple" imageloader has a lot of code)</p>
  
  <pre><code>    public void loadImageWithTagCheck(final ImageView view) {
      final String url = (String) view.getTag();
      final Handler uiHandler = new Handler() {
          @Override
          public void handleMessage(Message msg) {
          }
      };
      if (imageHandler != null) {
          imageHandler.post(new Runnable() {
  
              @Override
              public void run() {
                  final Bitmap bmp = getImage(url, view);
                  uiHandler.post(new Runnable() {
  
                      @Override
                      public void run() {
                          String tagUrl = (String) view.getTag();
                          if (tagUrl.equals(url) &amp;&amp; bmp != null
                                  &amp;&amp; !bmp.isRecycled()) {
                              scaleBitmapAndAdjustViewByHeight(view, bmp);
                          } else if (bmp != null) {
                              bmp.recycle();
                          }
                      }
                  });
              }
          });
      }
  }
  
       private Bitmap getImage(String url, View v) {
          Bitmap bmp = null;
  
          if (url != null &amp;&amp; !TextUtils.isEmpty(url)) {
              String md5Url = Utility.md5(url);
              if (cache.containsKey(md5Url)) {
                  bmp = cache.getBitmap(md5Url);
              } else {
                  HttpGet httpGet = new HttpGet();
                  HttpClient httpClient = new DefaultHttpClient();
  
                  HttpResponse response = null;
                  try {
                      URI uri = new URI(url);
                      httpGet.setURI(uri);
                      response = httpClient.execute(httpGet);
  
                      if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                          HttpEntity entity = response.getEntity();
                          if (entity != null) {
                              final BufferedInputStream buffIn = new BufferedInputStream(
                                      entity.getContent(), Utils.IO_BUFFER_SIZE);
                              BitmapFactory.Options options = new BitmapFactory.Options();
                              options.inJustDecodeBounds = true;
                              options.outWidth = v.getWidth();
                              options.outHeight = v.getHeight();
                              options.inPurgeable = true;
                              options.inInputShareable = true;
                              options.inPreferredConfig = Bitmap.Config.RGB_565;
  
                              bmp = BitmapFactory.decodeStream(buffIn, null,
                                      options);
                          }
                      }
                  } catch (URISyntaxException e) {
                      e.printStackTrace();
                  } catch (ClientProtocolException e) {
                      e.printStackTrace();
                  } catch (IOException e) {
                      e.printStackTrace();
                  } catch (IllegalStateException e) {
                      e.printStackTrace();
                  }
  
                  if (bmp != null) {
                      cache.put(md5Url, bmp);
                  }
              }
          }
  
          return bmp;
      }
  
  private void scaleBitmapAndAdjustViewByHeight(final ImageView view,
          final Bitmap bmp) {
      ViewTreeObserver vto = view.getViewTreeObserver();
      vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
  
          @SuppressLint("NewApi")
          @SuppressWarnings("deprecation")
          @Override
          public void onGlobalLayout() {
              if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.JELLY_BEAN) {
                  view.getViewTreeObserver().removeOnGlobalLayoutListener(
                          this);
              } else {
                  view.getViewTreeObserver().removeGlobalOnLayoutListener(
                          this);
              }
  
              // Get current dimensions
              int width = bmp.getWidth();
              int height = bmp.getHeight();
  
              // Determine how much to scale: the dimension requiring less
              // scaling is closer to the its side. This way the image always
              // stays inside your bounding box AND either x/y axis touches
              // it.
              int imageViewHeightFromXMLinPixels = view.getHeight();
              float xScale = (float) ((imageViewHeightFromXMLinPixels * 2.75) / width);
              float yScale = ((float) imageViewHeightFromXMLinPixels)
                      / height;
              float scale = (xScale &lt;= yScale) ? xScale : yScale;
  
              // Create a matrix for the scaling and add the scaling data
              Matrix matrix = new Matrix();
              matrix.postScale(scale, scale);
  
              // Create a new bitmap
              Bitmap scaledBitmap = Bitmap.createBitmap(bmp, 0, 0, width,
                      height, matrix, true);
              width = scaledBitmap.getWidth(); // re-use
  
              view.setImageBitmap(scaledBitmap);
              view.getLayoutParams().width = width;
          }
      });
      view.requestLayout();
  }
  </code></pre>