0

I have tried to use this question's answer to get a functioning implementation, but I get various errors and am now down to an EOFException and on debugging, it appears the file does not get written.

The goal is to download an image from a URL, save it to internal cache, then later fetch it from that cache for displaying. Where have I gone wrong? The EOFException is thrown in CachedImage.java on the line which reads byte[] data = (byte[]) ois.readObject();

CachedImage.java

package com.example.droid;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;

import android.graphics.Bitmap;

public class CachedImage implements Serializable {
  private static final long serialVersionUID = -12345678987654321L;
  private transient Bitmap _bmp;

  public CachedImage(Bitmap bmp) {
    this._bmp = bmp;
  }

  public void writeObject(ObjectOutputStream oos) throws IOException {
    oos.defaultWriteObject();

    if (this._bmp != null) {
      int bytes = this._bmp.getWidth() * this._bmp.getHeight() * 4;

      ByteBuffer buffer = ByteBuffer.allocate(bytes);
      this._bmp.copyPixelsToBuffer(buffer);

      if (buffer.hasArray()) {
        try {
          String configName = this._bmp.getConfig().name();

          byte[] array = buffer.array();

          oos.writeObject(array);
          oos.writeInt(this._bmp.getWidth());
          oos.writeInt(this._bmp.getHeight());
          oos.writeObject(configName);
        } catch (BufferUnderflowException e) {
        }
      }
    } else {
      oos.writeObject(null);
    }
  }

  private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
    ois.defaultReadObject();

    byte[] data = (byte[]) ois.readObject();
    if (data != null) {
      int w = ois.readInt();
      int h = ois.readInt();
      String configName = (String) ois.readObject();

      Bitmap.Config configBmp = Bitmap.Config.valueOf(configName);
      Bitmap bitmap_tmp = Bitmap.createBitmap(w, h, configBmp);
      ByteBuffer buffer = ByteBuffer.wrap(data);

      bitmap_tmp.copyPixelsFromBuffer(buffer);

      this._bmp = bitmap_tmp.copy(configBmp, true);

      bitmap_tmp.recycle();
    } else {
      this._bmp = null;
    }
  }
  public Bitmap getBitmap() {
    return this._bmp;
  }
}

And here are the code segments which trigger the calls:

Async callback function for when the image is fetched from the URL to write the image to internal:

@Override
protected void onPostExecute(Bitmap result) {
  if (result != null) {
      FileOutputStream output = null;
      ObjectOutputStream oos = null;
      try {
        output = ICEApplication.getAppContext().openFileOutput(filename, Context.MODE_PRIVATE);
        oos = new ObjectOutputStream(output);
        CachedImage cachedImage = new CachedImage(result);
        oos.writeObject(cachedImage);
      } catch (Exception e) {
        Log.d("DEBUG", "Exception: " + e.getMessage());
      } finally {
        if (output != null) {
          try {
            oos.close();
            output.close();
          } catch (IOException e) {
          }
        }
      }
    }
  }

The code to read the image from disk after downloaded and saved:

Bitmap image = null;
FileInputStream input = null;
ObjectInputStream ois = null;
try {
  input = ICEApplication.getAppContext().openFileInput(urldisplay);
  ois = new ObjectInputStream(input);
  CachedImage cachedImage = (CachedImage)ois.readObject();

  image = cachedImage.getBitmap();
} catch (Exception e) {
  Log.d("DEBUG", "Exception: " + e.getMessage());
  return null;
} finally {
  if (input != null) {
    try {
      ois.close();
      input.close();
    } catch (IOException e) {

    }
  }
}
Community
  • 1
  • 1
  • are you sure your `CachedImage.writeObject` is called? – njzk2 Jul 17 '14 at 15:54
  • and are you sure that `filename` and `urldisplay` are the same? – njzk2 Jul 17 '14 at 15:55
  • @njzk2 Yes to both questions. I did a debug and stepped through comparing values and ensuring that in the write stage, the data is also in the array. –  Jul 17 '14 at 16:19
  • In your onPostExecute method, instead of using oos.writeObject(cachedImage); Try using cachedImage.writeObject(oos); – rickz Jul 17 '14 at 17:21
  • @rickz That causes a `NotActiveException` when `oos.defaultWriteObject();` is called. I found that somewhere while working out my issues (but tested again just now in case other changes would have made it work). –  Jul 17 '14 at 17:34
  • 1
    What happens when you make CachedImage's writeObject method private instead of public (like you posted) ? – rickz Jul 17 '14 at 18:17
  • OMG! That was it. Thank you! I knew that, too... just too buried in the code and couldn't see the big picture. If you'll post as an answer, I will accept. Code above worked once I made the change of scope. –  Jul 17 '14 at 18:46

1 Answers1

1

I read from http://www.javablogging.com/what-are-writeobject-and-readobject-customizing-the-serialization-process/

ObjectOutputStream uses reflection to find out if those methods are declared. It uses getPrivateMethod so those methods have to be declared private in order to be used by the ObjectOutputStream

So, change CachedImage's method writeObject to private(because you posted it as public).

rickz
  • 4,324
  • 2
  • 19
  • 30