简体   繁体   中英

Synchronize object serialization(Android)

tl;dr: I have two threads, one of them serealizes object, and another tries to read object. How do I avoid collisions, ie synchronize access to file?

More info: I have Service which uses AsyncTask to fetch data and then serializes object:

  @Override
  protected Boolean doInBackground(Void... params) {
      FeedItem currentItem = mParser.parseFeed();
      Util.saveItem(UpdateService.this, currentItem);       
  }

Object serialization:

public class Util {

    private static final String sFileName = "feedobject";

    public static FeedItem loadItem(Context context) {
        FeedItem result = null;
        try {
            FileInputStream fis = context.openFileInput(sFileName);
            ObjectInputStream is = new ObjectInputStream(fis);
            result = (FeedItem) is.readObject();
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return result;
    }

    public static void saveItem(Context context, FeedItem item) {
        FileOutputStream fos;
        try {
            fos = context.openFileOutput(sFileName, Context.MODE_PRIVATE);
            ObjectOutputStream os = new ObjectOutputStream(fos);
            os.writeObject(item);
            os.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

I also try to read object from Activity, ie from UI thread.

mTextView.setText(Html.fromHtml(Util.loadItem(this).message));

If you can rename files under Android, then you could write the object to a temporary file "feedobject.t" and then rename it to be "feedobject" which should be atomic.

private static final String sFileName = "feedobject";
private static final String tempFileName = "feedobject.t";
...

File tempFile = new File(tempFileName);
... // write the file
tempFile.renameTo(new File(sFileName));

If this doesn't work then you will be forced to have a synchronized lock. The consumer should lock and wait for the producer to finish writing. The producer needs to lock to make sure it is writing only when the consumer is not reading.

You could just make the saveItem and loadItem methods be synchronized which would lock the class:

public static synchronized FeedItem loadItem(Context context) {
    ...

public static synchronized void saveItem(Context context, FeedItem item) {
    ...

Better would be to create a lock object and lock on that:

private static final Object itemLock = new Object();

Then in the loadItem and saveItem methods you'd lock on that object:

public static FeedItem loadItem(Context context) {
    synchronized (itemLock) {
        // do the reading...
    }

Hope this helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM