From c481a2764939ca07ce113444ea5bf478a5a6bf26 Mon Sep 17 00:00:00 2001 From: Mattia Date: Tue, 18 Apr 2017 18:25:48 +0200 Subject: [PATCH 1/3] Parcelable reference for ParseObjects --- _includes/android/objects.md | 61 ++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/_includes/android/objects.md b/_includes/android/objects.md index 66f68d9a0..efe10cc85 100644 --- a/_includes/android/objects.md +++ b/_includes/android/objects.md @@ -470,3 +470,64 @@ query.findInBackground(new FindCallback() { } }); ``` + +## Parcelable + +As most public facing components of the SDK, `ParseObject` implements the `Parcelable` interface. This means you can retain a `ParseObject` during configuration changes, or pass objects to other components through `Bundle`s. To achieve this, depending on the context, use either `Parcel#writeParcelable(Parcelable, int)` or `Bundle#putParcelable(String, Parcelable)`. +For instance, in an `Activity`, + +```java +private ParseObject object; + +@Override +protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putParcelable("object", object); +} + +@Override +protected void onCreate(@Nullable Bundle savedInstanceState) { + if (savedInstanceState != null) { + object = (ParseObject) savedInstanceState.getParcelable("object"); + } +} +``` + +That's it. `ParseObject` will parcel its internal state, along with unsaved childs and dirty changes. There are, however, a few things to be aware of when parceling objects that have ongoing operations, like save or delete. The SDK behavior differs depending on whether you have enabled the Local Datastore. + +### Parceling with Local Datastore enabled + +When the Local Datastore is enabled, parceling a `ParseObject` is a safe operation even if there are ongoing save or delete operations. Thanks to LDS, the same instance is returned when unparceling (unless something happens in the middle, in which case the SDK behaves as if LDS was disabled, see below). + +This means that the `ParseObject` is internally notified about the operation results, whether it's successful or not. There is, however, no way to register external callbacks (`SaveCallback` or `DeleteCallback`) for these tasks, other than the ones you have already registered at the moment of saving / deleting the source instance. + +### Parceling with Local Datastore disabled + +When the Local Datastore is disabled, and the parceled `ParseObject` has ongoing operations that haven't finished yet, the unparceled object will end up in a stale state. The unparceled object, being a different instance than the source object, + +- assumes that ongoing operations at the moment of parceling never took place +- will not update its internal state when the operations triggered by the source object + +The unfortunate consequence is that keys that were dirty before saving will still be marked as dirty for the unparceled object. This means, for instance, that any future call to `saveInBackground()` will send these dirty operations to the server again. This can lead to inconsistencies for operations like `increment`, since it might be performed twice. + +### Parceling ParseObject subclasses + +By default, `ParseObject` implementation parcels everything that is needed. If your subclasses have stateful information that you would like to keep when parceling, you can simply override `onSaveInstanceState(Bundle)` and `onRestoreInstanceState(Bundle)`: + +```java +// Armor.java +@ParseClassName("Armor") +public class Armor extends ParseObject { + private int member; + + @Override + protected void onSaveInstanceState(Bundle outState) { + outState.putInt("member", member); + } + + @Override + protected void onRestoreInstanceState(Bundle savedInstanceState) { + member = savedInstanceState.getInt("member"); + } +} +``` From 6acee610f2a2bad176ed711ea7e686b342d3870d Mon Sep 17 00:00:00 2001 From: Mattia Date: Tue, 18 Apr 2017 20:26:35 +0200 Subject: [PATCH 2/3] Parcelable referecence for ParseFiles --- _includes/android/files.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/_includes/android/files.md b/_includes/android/files.md index 283e07584..ec7320601 100644 --- a/_includes/android/files.md +++ b/_includes/android/files.md @@ -70,3 +70,28 @@ file.saveInBackground(new SaveCallback() { You can delete files that are referenced by objects using the [REST API]({{ site.baseUrl }}/rest/guide/#deleting-files). You will need to provide the master key in order to be allowed to delete a file. If your files are not referenced by any object in your app, it is not possible to delete them through the REST API. You may request a cleanup of unused files in your app's Settings page. Keep in mind that doing so may break functionality which depended on accessing unreferenced files through their URL property. Files that are currently associated with an object will not be affected. + +## Parcelable + +As most public facing components of the SDK, `ParseFile` implements the `Parcelable` interface. This means you can retain a `ParseFile` during configuration changes, or pass it to other components of the app through `Bundles`. To achieve this, depending on the context, use either `Parcel#writeParcelable(Parcelable, int)` or `Bundle#putParcelable(String, Parcelable)`. For instance, in an Activity, + +```java +private ParseFile file; + +@Override +protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + if (!file.isDirty()) { + outState.putParcelable("file", file); + } +} + +@Override +protected void onCreate(@Nullable Bundle savedInstanceState) { + if (savedInstanceState != null) { + file = (ParseFile) savedInstanceState.getParcelable("file"); + } +} +``` + +Note, however, that files can't be parceled if they are not saved on the server. If you try to do so, an exception will be thrown. If you are not sure if your file has been saved, plaese check for `!isDirty()` to be true before writing it to a parcel. From c6fd48ebe8172261af62ff4ae0ee9882d303951a Mon Sep 17 00:00:00 2001 From: Mattia Date: Tue, 18 Apr 2017 20:28:27 +0200 Subject: [PATCH 3/3] Parcelable reference for ParseGeoPoint --- _includes/android/geopoints.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/_includes/android/geopoints.md b/_includes/android/geopoints.md index 9efc0ff21..d6ff6ea33 100644 --- a/_includes/android/geopoints.md +++ b/_includes/android/geopoints.md @@ -42,6 +42,27 @@ query.whereWithinGeoBox("location", southwestOfSF, northeastOfSF); query.findInBackground(new FindCallback() { ... }); ``` +## Parcelable + +As most public facing components of the SDK, `ParseGeoPoint` implements the `Parcelable` interface. This means you can retain a `ParseGeoPoint` during configuration changes, or pass it to other components of the app through `Bundles`. To achieve this, depending on the context, use either `Parcel#writeParcelable(Parcelable, int)` or `Bundle#putParcelable(String, Parcelable)`. For instance, in an Activity, + +```java +private ParseGeoPoint point; + +@Override +protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putParcelable("point", point); +} + +@Override +protected void onCreate(@Nullable Bundle savedInstanceState) { + if (savedInstanceState != null) { + point = (ParseGeoPoint) savedInstanceState.getParcelable("point"); + } +} +``` + ## Caveats At the moment there are a couple of things to watch out for: