Skip to content

Parcelable documentation for Android #428

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 6, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions _includes/android/files.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
21 changes: 21 additions & 0 deletions _includes/android/geopoints.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,27 @@ query.whereWithinGeoBox("location", southwestOfSF, northeastOfSF);
query.findInBackground(new FindCallback<ParseObject>() { ... });
```

## 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:
Expand Down
61 changes: 61 additions & 0 deletions _includes/android/objects.md
Original file line number Diff line number Diff line change
Expand Up @@ -470,3 +470,64 @@ query.findInBackground(new FindCallback<Armor>() {
}
});
```

## 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");
}
}
```