title: Bitmap creation and drawing speed slow... and fast
body: <p>This is in small part a question (because I don't understand why it makes a difference), and in large part a post to hopefully help some other poor programmer out there.</p>
  
  <p>I have a library of code that I wrote about 5-7 years ago when first starting Android programming, and it has functions to read a file into memory (which get used for a number of things), and a function to load a bitmap from a .png file.  The latter function used the "read file" function to read the bytes from the file into a byte array and then creates a Bitmap from it.  I know this isn't really clean code, nor is it probably the best way to do it, but it works, and why muck with something that works?</p>
  
  <p>Except... the last few revs of Android (and Oreo in particular) have caused the drawing (from Bitmaps) in my apps to REALLY slow WAYYYYYY down.  I struggled for days, trying to figure out what was going on, and finally stumbled upon a fix... which I don't understand.</p>
  
  <p>Here's the core of the "load .png file into Bitmap" function (as it was).  Note that the whole "if-for-for" transparency stuff can probably be completely ignored, it's a special case for converting pixels of one or two colors into transparent pixels. At entry to this block, the .png file has already been read into 'bits'.</p>
  
  <pre><code>BitmapFactory.Options bfo = new BitmapFactory.Options();
  bfo.inPreferredConfig = Bitmap.Config.valueOf("ARGB_8888");
  Bitmap imbm = BitmapFactory.decodeByteArray(bits, 0, flen, bfo);// this makes an IMmutable bitmap
  bits = null;
  System.gc();
  Bitmap bm = imbm.copy(Bitmap.Config.valueOf("ARGB_8888"), true);// convert it to a MUTABLE bitmap
  imbm.recycle();
  imbm = null;
  w = bm.getWidth();
  h = bm.getHeight();
  // do transparency stuff
  if (transX1 &gt;= 0 &amp;&amp; transX1 &lt; w &amp;&amp; transY1 &gt;= 0 &amp;&amp; transY1 &lt; h) {
      clr1 = bm.getPixel(transX1, transY1);
      clr2 = bm.getPixel(transX2, transY2);
      for (y = 0; y &lt; h; y++) {
          for (x = 0; x &lt; w; x++) {
              clr = bm.getPixel(x, y);
              // convert any 0x00818181 (middle-gray) pixels to 0x00808080
              // so that 0x00818181 is guaranteed to never be used in customer-created bitmaps
              if (clr1 != 0xFF818181 &amp;&amp; clr == 0xFF818181) bm.setPixel(x, y, 0xFF808080);
              else if (clr == clr1 || clr == clr2) bm.setPixel(x, y, clr &amp; 0x00000000);
          }
      }
  }
  System.gc();    // request garbage-collection to try to avoid out-of-memory when loading/creating bitmap
  return bm;
  </code></pre>
  
  <p>The returned Bitmap was then used as the source from which to draw bits and pieces into a Context using dC.drawBitmap(bm, sRect, dRect, kPaint).  However, changes in Android caused this to slow way down.  The fix turned out to be replacing the final "return bm" above with this code:</p>
  
  <pre><code>Bitmap tBM = Bitmap.createBitmap(w, h, Bitmap.Config.valueOf("ARGB_8888"));
  Rect sRect = new Rect();
  Rect dRect = new Rect();
  sRect.set(0, 0, w, h);
  dRect.set(0, 0, w, h);
  Canvas dC = new Canvas(tBM);
  dC.drawBitmap(bm, sRect, dRect, kPaint);
  dC = null;
  bm = null;
  return tBM;
  </code></pre>
  
  <p>In other words, it just takes the 'bm' Bitmap that resulted from the previous version, creates another Bitmap of the same size, draws 'bm' into the new Bitmap, and returns the new Bitmap instead of the previous version.</p>
  
  <p>SOMETHING about the previous way of constructing the Bitmap appears to leave it in a "bad form" that makes drawing FROM it very slow, while doing a createBitmap() and a drawBitmap() into it results in a Bitmap that you can draw FROM very FAST.</p>
  
  <p>Any ideas why that would be? (And yes, I tried all the usual RGB_565 things, etc.)  THIS works and works well.  But if I understood WHY this happened, that would be good, and like I said, my travails might prove useful to someone in the future.</p>