A riveting mystery: Android, Bitmaps (JPEGs), and the GridView of DEATH?
<p>My app is exhibiting some very strange behavior. I have tried everything to resolve the issues I'm having, but, at this point, I'm at a total loss. </p>

<p>Some background information is in order (some details of the implementation that I'm providing might be overkill, but I want to make sure no stone is left unturned): </p>

<ol>
<li><p>The app makes use of the device's camera, utilizing a SurfaceView with the necessary SurfaceHolder callbacks to open the device's Camera and take photos. That all works just fine. </p></li>
<li><p>The photos are then saved to the devices internal storage, using a FileOutPutStream. I then maintain a reference to the file path of each photo inside a plain old Java object, which is actually serialized and also written to the device's internal storage using an ObjectOutputStream. </p></li>
<li><p>The photos, which are in JPEG format, are later retrieved by grabbing the serialized ArrayList of my objects, grabbing the file path from those objects and passing it to my caching mechanism like so Bitmap bm = ImageCache.getSharedInstance().getBitmap(photoObject.filePath,getResources()); to return a Bitmap which I can use with an ImageView, whatever. I use this to for displaying the JPEGs in ListViews, GridViews, etc. </p></li>
</ol>

<p><strong>Here's the problem:</strong> </p>

<p>I have a View, which I've created programmatically, that has a sort of navigation bar at the top of it. All the navigation bar does is set the "main" part of my custom View class to display whatever other view I pass to it. So, my View class has a method like: setContent(View v) which simply removes all Views from the main part (or the area that I've carved out as the content area) and then adds the View you passed in to this content area. </p>

<p>So, if you click on nav button, it shows the photos along with some other data in a ListView, click another and it shows a GridView using the same photos. Right here is the problem. I like to call it THE GRIDVIEW OF DEATH. The GridView implementation is pretty straightforward and seems to work just fine when it's loaded. </p>

<pre><code>mGalleryAdapter = new GalleryAdapter(MyActivity.this, list);
                        gridView.setAdapter(mGalleryAdapter);
</code></pre>

<p>Fine... but here's the issue. <strong>Once the GridView is loaded and displays the data from the adapter, if you try to start any other activity or navigate to any other are of the app, the activities in question seem to launch, but the Views inside of them never display.</strong> It is the strangest behavior. If you start with the ListView displaying and then navigate to some other tab (yea, I'm using tabs to sort of mimick iPhone style UITabs), everything is fine. The activity loads, the views display... everything is fine. But once you click to display the GridView, the app just seems to melt. Aaaaand, here's the catch. Whatever activity you've navigate to after displaying the GridView, will first display an empty, white activity (with no view). But if, for example, you long-press the home button and switch to some other running app and then come back to my app, the newly launched activities then display the views inside of them just fine and the app resumes normally. Strange indeed. </p>

<p>I must mention that I originally had the app crash several times because of "exceeding the VM budget." This was clearly related to issues with the JPEGs and their memory usage. From the stuff I've read online, the main fix to this is to crank up the BitmapFactory.Options sampleSize. Well, that's exactly what I've done. I've cranked it way up to reduce the image size:</p>

<pre><code>public Bitmap getBitmap(String filepath, Resources resources){
        SoftReference&lt;Bitmap&gt; reference;
        if(resourcesLoaded.containsKey(filepath)){
            reference = resourcesLoaded.get(filepath);
            if(reference.get() == null){
                int width = resources.getDisplayMetrics().widthPixels;
                int height = (int) (42*((float)(((float)width)/320.0)));
                BitmapFactory.Options opts = new BitmapFactory.Options();
                opts.inSampleSize = 28;
                opts.outHeight = height;
                opts.inTempStorage = new byte[16*1024];

                opts.outWidth = width;
                opts.inPurgeable = true;
                Bitmap bit = BitmapFactory.decodeFile(filepath ,opts);
                reference = new SoftReference&lt;Bitmap&gt;(bit);
                resourcesLoaded.put(filepath, reference);
            }
        }else{
            int width = resources.getDisplayMetrics().widthPixels;
            int height = (int) (42*((float)(((float)width)/320.0)));
            BitmapFactory.Options opts = new BitmapFactory.Options();
            opts.outHeight = height;
            opts.outWidth = width;
            opts.inTempStorage = new byte[16*1024];

            opts.inSampleSize = 28;
            opts.inPurgeable = true;
            Bitmap bit = BitmapFactory.decodeFile(filepath ,opts);
            reference = new SoftReference&lt;Bitmap&gt;(bit);
            resourcesLoaded.put(filepath, reference);
        }
        return reference.get();
    }
</code></pre>

<p>And, that's the weird thing, the app doesn't even crash now. Using caching and reducing the image size seems to have eliminated that crash (at least on some of the devices I've tested on), but this strange behavior, WHICH ONLY OCCURS ONCE LOADING THE GRIDVIEW OF DEATH and then navigating away from it, persists. </p>

<p>On a related note, I have used some third party app on my phone to see the current memory usage of my app and, at times, it creeps up to 100MB! Every time I take a photo with the app and save it to the internal storage, the memory usage seems to jump considerably (generally starts around 30-40MB and climbs from there). So clearly, there are memory issues going on. But again, the app won't crash with a "exceeded VM budget" error. On the other hand, it's hard to ignore the obvious memory issues with the app.</p>

<p>I fully realize that some of my implementation is not perfect, not super memory efficient, and that using singletons to hold the ArrayList of my objects, etc might not be the greatest way to go. But even still, this behavior seems inexplicable. </p>

<p><strong>To summarize: the app will load completely blank activities ONCE AND ONLY ONCE you've clicked to display the images (that are stored as JPEGs on the device) in the GridView. If you never click to use the GridView, everything is fine.</strong> </p>

<p>What's with the Gridview of death?</p>

<p>(I'm happy to provide the code for any portions you think are relevant.)</p>

<p>UPDATE:</p>

<p><strong>Thanks @CommonsWare for all your patience and advice.</strong> Really appreciate it and it's always nice to have the unofficial Android developer advocate on the case. Turns out that using Fragments did, in fact, solve all of my problems. For a moment, I thought I had fully implemented the Fragment solution, but quickly realized that I was still "setting the content" of some base View that was loaded in my Fragment to my GridView. By creating a new framgent containing the Grid View and loading it, all problems seem to be solved and the app is now stable!</p>

<p>UPDATE: Well, I spoke too soon :( Apparently this GridView is still causing problems. Now when I switch to a new tab, I can see that the button I'm using for the tab was clicked, but when it calsl <code>setCurrentTab()</code> nothing happens. App remains frozen in the GridView screen. </p>
