Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HashMap De-Serialization

I have a server/client app where I retrieve data from the server via Hessian/hessdroid. The data is very complex with HashMaps containing other HashMaps and images stored in byte arrays. I can display the data perfectly.

To not always query the server, I´m using a data structure as a cache. This data object I save to SD card using ObjectOutputStream when closing the app. When I restart it, I read it back to memory with an ObjectInputStream.

I´m having problems with the app only after reading the data from SD card. LogCat gives me the following output (100 times):

DEBUG/dalvikvm(4150): GetFieldID: unable to find field Ljava/util/HashMap;.loadFactor:F

and this in between the other messages:

INFO/dalvikvm-heap(4150): Grow heap (frag case) to 10.775MB for 281173-byte allocation

When the heap grows upon ~17 MB the app crashes.

I read several threads about HashMap Serialization and that there seems to be a bug when serializing between architectures, but for me the data transfer via Hessian works perfectly and I´m having the described problems only when reading the HashMaps from disk.

Any ideas?

like image 615
Konsumierer Avatar asked Nov 05 '22 00:11

Konsumierer


1 Answers

The problem is not directly related to the HashMap Deserialization, as cyber-monk commented. There is indeed some kind of bug in Android or it´s HashMap implementation, but I don´t think it´s why the app crashes.

By now I solved the problem, using less images in the app. I had a gallery for example in which you could swipe from one image to the next in a flipper and loaded all the images at once. At a certain amount of images, there is not enough heap space.

My solution to this is, to not keep all the decoded images at once.

It´s done like this:

1) Hold the binary image data in memory (not a problem as long as the images are not that big)

2) Don´t load the binary image data into the ImageViews when creating the views of the flipper.

3) Set the binary image data into the ImageView that is displayed.

4) Keep the binary image data of the next and the last ImageView for better user experience)

5) "Unload" the ImageViews that are not displayed by setting its resource to the transparent color.

Here´s some code:

// initialize the viewFlipper by creating blank views
for (ComponentImageDto listElement : images) {
    LinearLayout view = renderView();
    flipper.addView(view);
}
showImage(flipper.getCurrentView());

renderView() just returns a LinearLayout containing an ImageView

Then I wrote some methods to show the next/previous image in which I set the binary data to the ImageView:

private void showNextElement() {
    // show next flipper view
    flipper.showNext();

    // get current view
    int displayedChild = flipper.getDisplayedChild();
    View currentView = flipper.getCurrentView();

    // load the binary data
    showImage(currentView);

    // get the next to last view index (if keeping max. 3 images at a time in memory)
    int otherChild = (displayedChild - 2);
    if (otherChild < 0) {
        otherChild = otherChild + flipper.getChildCount();
    }

    // .. and remove it
    removeImage(flipper.getChildAt(otherChild));
}

private void showPreviousElement() {
    flipper.showPrevious();
    int displayedChild = flipper.getDisplayedChild();
    View currentView = flipper.getCurrentView();
    showImage(currentView);
    setTitle((CharSequence) currentView.getTag());
    int otherChild = (displayedChild + 2) % flipper.getChildCount();
    removeImage(flipper.getChildAt(otherChild));
}

private void removeImage(View view) {
    ImageView imageView = (ImageView) view.findViewById(R.id.gallery_image);
    if (imageView != null) {
        imageView.setImageResource(R.color.transparent);
        System.gc();
    }
}

private void showImage(View view) {
    ImageView imageView = (ImageView) view.findViewById(R.id.gallery_image);
    if (imageView != null) {
        bm = BitmapHelper.decodeByteArray(images.get(flipper.getDisplayedChild()).getImage().getBinaryObject());
        imageView.setImageBitmap(bm);
    }
}

To furtherly improve memory handling I´m using some code in BitmapHelper class that I found on stackoverflow, that helps to save memory for images by reducing their size.

like image 143
Konsumierer Avatar answered Nov 09 '22 08:11

Konsumierer