Android Developers Guide - Parse
Android Developers Guide - Parse
Android
Guide Browse
Getting Started
Getting Started
Note that we support Android 4.0 and higher. You can
also check out our API Reference for more detailed
information about our SDK.
Installation
Step 1: Download Parse-SDK-Android
Dependency
Add this in your root build.gradle file (not your
module build.gradle file):
allprojects { 📋
repositories {
...
maven { url
"https://jitpack.io" }
}
}
dependencies { 📋
implementation "com.github.parse-
community.Parse-SDK-
https://docs.parseplatform.org/android/guide/#users 1/171
7/26/22, 5:13 PM Android Developers Guide | Parse
Android:parse:latest.version.here"
}
JitPack 4.0.0
with the latest version being
import com.parse.Parse; 📋
import android.app.Application;
<application 📋
android:name=".App"
...>
...
</application>
Objects
The ParseObject
https://docs.parseplatform.org/android/guide/#users 2/171
7/26/22, 5:13 PM Android Developers Guide | Parse
Saving Objects
Let’s say you want to save the GameScore described
above to your Parse Server. The interface is similar to a
Map , plus the saveInBackground method:
https://docs.parseplatform.org/android/guide/#users 3/171
7/26/22, 5:13 PM Android Developers Guide | Parse
{ 📋
"objectId": "xWMyZ4YEGZ",
"score": 1337,
"playerName": "Sean Plott",
"cheatMode": false,
"createdAt":"2022-01-01T12:23:45.678Z",
"updatedAt":"2022-01-01T12:23:45.678Z"
}
Retrieving Objects
Saving data to the cloud is fun, but it’s even more fun to
get that data out again. If you have the objectId ,
which is available once the ParseObject been
uploaded to the server, you can retrieve the whole
ParseObject using a ParseQuery :
ParseQuery<ParseObject> query = 📋
ParseQuery.getQuery("GameScore");
query.getInBackground("xWMyZ4YEGZ", new
GetCallback<ParseObject>() {
public void done(ParseObject object,
ParseException e) {
if (e == null) {
// object will be your game score
} else {
// something went wrong
}
}
});
https://docs.parseplatform.org/android/guide/#users 4/171
7/26/22, 5:13 PM Android Developers Guide | Parse
myObject.fetchInBackground(new 📋
GetCallback<ParseObject>() {
public void done(ParseObject object,
ParseException e) {
if (e == null) {
// Success!
} else {
// Failure!
}
}
});
https://docs.parseplatform.org/android/guide/#users 5/171
7/26/22, 5:13 PM Android Developers Guide | Parse
ParseQuery<ParseObject> query = 📋
ParseQuery.getQuery("GameScore");
query.fromLocalDatastore();
query.getInBackground("xWMyZ4YEGZ", new
GetCallback<ParseObject>() {
public void done(ParseObject object,
ParseException e) {
if (e == null) {
// object will be your game score
} else {
// something went wrong
}
}
});
ParseObject object = 📋
ParseObject.createWithoutData("GameScore",
"xWMyZ4YEGZ");
object.fetchFromLocalDatastoreInBackground(new
GetCallback<ParseObject>() {
https://docs.parseplatform.org/android/guide/#users 6/171
7/26/22, 5:13 PM Android Developers Guide | Parse
public void done(ParseObject object,
ParseException e) {
if (e == null) {
// object will be your game score
} else {
// something went wrong
}
}
});
Unpinning Objects
When you are done with the object and no longer need
to keep it on the device, you can release it with
unpinInBackground .
gameScore.unpinInBackground(); 📋
Updating Objects
https://docs.parseplatform.org/android/guide/#users 7/171
7/26/22, 5:13 PM Android Developers Guide | Parse
ParseQuery<ParseObject> query = 📋
ParseQuery.getQuery("GameScore");
Counters
The above example contains a common use case. The
“score” field is a counter that we’ll need to continually
update with the player’s latest score. Using the above
method works but it’s cumbersome and can lead to
problems if you have multiple clients trying to update
the same counter.
gameScore.increment("score"); 📋
gameScore.saveInBackground();
https://docs.parseplatform.org/android/guide/#users 8/171
7/26/22, 5:13 PM Android Developers Guide | Parse
Arrays
To help with storing array data, there are three
operations that can be used to atomically change an
array field:
gameScore.addAllUnique("skills", 📋
Arrays.asList("flying", "kungfu"));
gameScore.saveInBackground();
Deleting Objects
To delete an object from your Parse Server:
myObject.deleteInBackground(); 📋
https://docs.parseplatform.org/android/guide/#users 9/171
7/26/22, 5:13 PM Android Developers Guide | Parse
Relational Data
Objects can have relationships with other objects. To
model this behavior, any ParseObject can be used as a
value in other ParseObject s. Internally, the Parse
framework will store the referred-to object in just one
place, to maintain consistency.
You can also link objects using just their objectId s like
so:
https://docs.parseplatform.org/android/guide/#users 10/171
7/26/22, 5:13 PM Android Developers Guide | Parse
fetchedComment.getParseObject("post") 📋
.fetchIfNeededInBackground(new
GetCallback<ParseObject>() {
public void done(ParseObject post,
ParseException e) {
String title =
post.getString("title");
// Do something with your new title
variable
}
});
relation.remove(post); 📋
relation.getQuery().findInBackground(new 📋
FindCallback<ParseObject>() {
void done(List<ParseObject> results,
ParseException e) {
if (e != null) {
// There was an error
} else {
// results have all the Posts the
current user liked.
}
https://docs.parseplatform.org/android/guide/#users 11/171
7/26/22, 5:13 PM Android Developers Guide | Parse
}
});
ParseQuery<ParseObject> query = 📋
relation.getQuery();
// Add other query constraints.
Data Types
So far we’ve used values with type String , Integer ,
boolean , and ParseObject . Parse also supports
float , java.util.Date , and JSONObject.NULL .
https://docs.parseplatform.org/android/guide/#users 12/171
7/26/22, 5:13 PM Android Developers Guide | Parse
Some examples:
Subclasses
Parse is designed to get you up and running as quickly
as possible. You can access all of your data using the
ParseObject class and access any field with get() . In
mature codebases, subclasses have many advantages,
including terseness, extensibility, and support for
autocomplete. Subclassing is completely optional, but
can transform this code:
Into this:
https://docs.parseplatform.org/android/guide/#users 13/171
7/26/22, 5:13 PM Android Developers Guide | Parse
SUBCLASSING PARSEOBJECT
4 Call
ParseObject.registerSubclass(YourClass.cla
ss) in your Application constructor before
calling Parse.initialize() . The following code
successfully implements and registers the Armor
subclass of ParseObject :
// Armor.java 📋
import com.parse.ParseObject;
import com.parse.ParseClassName;
@ParseClassName("Armor")
public class Armor extends ParseObject {
}
// App.java
import com.parse.Parse;
import android.app.Application;
ParseObject.registerSubclass(Armor.class);
Parse.initialize(this);
}
}
https://docs.parseplatform.org/android/guide/#users 14/171
7/26/22, 5:13 PM Android Developers Guide | Parse
// Armor.java 📋
@ParseClassName("Armor")
public class Armor extends ParseObject {
public String getDisplayName() {
return getString("displayName");
}
public void setDisplayName(String value) {
put("displayName", value);
}
}
INITIALIZING SUBCLASSES
Armor armorReference = 📋
ParseObject.createWithoutData(Armor.class,
armor.getObjectId());
QUERIES ON SUBCLASSES
ParseQuery<Armor> query = 📋
ParseQuery.getQuery(Armor.class);
query.whereLessThanOrEqualTo("rupees",
ParseUser.getCurrentUser().get("rupees"));
query.findInBackground(new FindCallback<Armor>
() {
@Override
public void done(List<Armor> results,
ParseException e) {
for (Armor a : results) {
// ...
}
}
});
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 ,
https://docs.parseplatform.org/android/guide/#users 16/171
7/26/22, 5:13 PM Android Developers Guide | Parse
}
@Override
protected void onCreate(@Nullable Bundle
savedInstanceState) {
if (savedInstanceState != null) {
object = (ParseObject)
savedInstanceState.getParcelable("object");
}
}
https://docs.parseplatform.org/android/guide/#users 17/171
7/26/22, 5:13 PM Android Developers Guide | Parse
// 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");
}
}
Queries
We’ve already seen how a ParseQuery with
getInBackground can retrieve a single ParseObject
from Parse. There are many other ways to retrieve data
with ParseQuery - you can retrieve many objects at
once, put conditions on the objects you wish to
retrieve, cache queries automatically to avoid writing
that code yourself, and more.
https://docs.parseplatform.org/android/guide/#users 18/171
7/26/22, 5:13 PM Android Developers Guide | Parse
Basic Queries
In many cases, getInBackground isn’t powerful enough
to specify which objects you want to retrieve. The
ParseQuery offers different ways to retrieve a list of
objects rather than just a single object.
ParseQuery<ParseObject> query = 📋
ParseQuery.getQuery("GameScore");
query.whereEqualTo("playerName", "Dan
Stemkoski");
query.findInBackground(new
FindCallback<ParseObject>() {
public void done(List<ParseObject>
scoreList, ParseException e) {
if (e == null) {
Log.d("score", "Retrieved " +
scoreList.size() + " scores");
} else {
Log.d("score", "Error: " +
e.getMessage());
}
}
});
Query Constraints
There are several ways to put constraints on the
objects found by a ParseQuery . You can filter out
objects with a particular key-value pair with
whereNotEqualTo :
query.whereNotEqualTo("playerName", "Michael 📋
Yabuti");
query.whereNotEqualTo("playerName", "Michael 📋
Yabuti");
query.whereGreaterThan("playerAge", 18);
ParseQuery<ParseObject> query = 📋
ParseQuery.getQuery("GameScore");
query.whereEqualTo("playerEmail",
"[email protected]");
query.getFirstInBackground(new
GetCallback<ParseObject>() {
public void done(ParseObject object,
ParseException e) {
if (object == null) {
Log.d("score", "The getFirst request
failed.");
} else {
Log.d("score", "Retrieved the object.");
}
}
});
You can skip the first results with setSkip . In the old
Parse hosted backend, the maximum skip value was
10,000, but Parse Server removed that constraint. This
can be useful for pagination:
📋
query.setSkip(10); // skip the first 10 results
https://docs.parseplatform.org/android/guide/#users 21/171
7/26/22, 5:14 PM Android Developers Guide | Parse
ParseQuery<ParseObject> teamQuery = 📋
ParseQuery.getQuery("Team");
teamQuery.whereGreaterThan("winPct", 0.5);
ParseQuery<ParseUser> userQuery =
ParseUser.getQuery();
userQuery.whereMatchesKeyInQuery("hometown",
"city", teamQuery);
userQuery.findInBackground(new
FindCallback<ParseUser>() {
void done(List<ParseUser> results,
ParseException e) {
// results has the list of users with a
hometown team with a winning record
}
});
ParseQuery<ParseUser> losingUserQuery = 📋
ParseUser.getQuery();
losingUserQuery.whereDoesNotMatchKeyInQuery("homet
https://docs.parseplatform.org/android/guide/#users 22/171
7/26/22, 5:14 PM Android Developers Guide | Parse
"city", teamQuery);
losingUserQuery.findInBackground(new
FindCallback<ParseUser>() {
void done(List<ParseUser> results,
ParseException e) {
// results has the list of users with a
hometown team with a losing record
}
});
ParseQuery<ParseObject> chartersOfTypeX = 📋
ParseQuery.getQuery("Charter");
charterOfTypeX.equalTo('type', 'x');
ParseQuery<ParseObject> groupsWithoutCharterX =
ParseQuery.getQuery("Group");
groupsWithoutCharterX.doesNotMatchKeyInQuery("obje
"belongsTo.objectId", chartersOfTypeX);
groupsWithoutCharterX.findInBackground(new
FindCallback<ParseObject>() {
void done(List<ParseObject> results,
ParseException e) {
// results has the list of groups without
charter x
});
ParseQuery<ParseObject> query = 📋
ParseQuery.getQuery("GameScore");
query.selectKeys(Arrays.asList("playerName",
"score"));;
List<ParseObject> results = query.find();
https://docs.parseplatform.org/android/guide/#users 23/171
7/26/22, 5:14 PM Android Developers Guide | Parse
You can also search for objects where the key’s array
value contains each of the values 2, 3, and 4 with the
following:
https://docs.parseplatform.org/android/guide/#users 24/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Relational Queries
There are several ways to issue queries for relational
data. If you want to retrieve objects where a field
matches a particular ParseObject , you can use
whereEqualTo just like for other data types. For
example, if each Comment has a Post object in its post
field, you can fetch comments for a particular Post :
https://docs.parseplatform.org/android/guide/#users 25/171
7/26/22, 5:14 PM Android Developers Guide | Parse
query.findInBackground(new
FindCallback<ParseObject>() {
public void done(List<ParseObject>
commentList, ParseException e) {
// commentList now has the comments for
myPost
}
});
ParseQuery<ParseObject> innerQuery = 📋
ParseQuery.getQuery("Post");
innerQuery.whereExists("image");
ParseQuery<ParseObject> query =
ParseQuery.getQuery("Comment");
query.whereMatchesQuery("post", innerQuery);
query.findInBackground(new
FindCallback<ParseObject>() {
public void done(List<ParseObject>
commentList, ParseException e) {
// comments now contains the comments for
posts with images.
}
});
ParseQuery<ParseObject> innerQuery = 📋
ParseQuery.getQuery("Post");
innerQuery.whereExists("image");
ParseQuery<ParseObject> query =
ParseQuery.getQuery("Comment");
query.whereDoesNotMatchQuery("post",
innerQuery);
query.findInBackground(new
FindCallback<ParseObject>() {
public void done(List<ParseObject>
commentList, ParseException e) {
// comments now contains the comments for
posts without images.
}
});
https://docs.parseplatform.org/android/guide/#users 26/171
7/26/22, 5:14 PM Android Developers Guide | Parse
ParseQuery<ParseObject> query = 📋
ParseQuery.getQuery("Comment");
query.findInBackground(new
FindCallback<ParseObject>() {
public void done(List<ParseObject>
commentList, ParseException e) {
// commentList now contains the last ten
comments, and the "post"
// field has been populated. For example:
for (ParseObject comment : commentList) {
// This does not require a network
access.
ParseObject post =
comment.getParseObject("post");
Log.d("post", "retrieved a related
post");
}
}
});
query.include("post.author"); 📋
https://docs.parseplatform.org/android/guide/#users 27/171
7/26/22, 5:14 PM Android Developers Guide | Parse
query.fromLocalDatastore(); 📋
query.findInBackground(new
FindCallback<ParseObject>() {
public void done(final List<ParseObject>
scoreList, ParseException e) {
if (e == null) {
// Results were successfully found from
the local datastore.
} else {
// There was an error.
}
}
});
Caching Queries
WITH LOCAL DATASTORE ENABLED
https://docs.parseplatform.org/android/guide/#users 28/171
7/26/22, 5:14 PM Android Developers Guide | Parse
// Release any objects previously pinned
for this query.
ParseObject.unpinAllInBackground(TOP_SCORES_LABEL
scoreList, new DeleteCallback() {
public void done(ParseException e) {
if (e != null) {
// There was some error.
return;
}
ParseObject.pinAllInBackground(TOP_SCORES_LABEL,
scoreList);
}
});
}
});
https://docs.parseplatform.org/android/guide/#users 29/171
7/26/22, 5:14 PM Android Developers Guide | Parse
return task;
}, Task.UI_EXECUTOR);
If you aren’t using the local datastore, you can use the
per-query cache for ParseQuery instead. The default
query behavior doesn’t use the cache, but you can
enable caching with setCachePolicy . For example, to
try the network and then fall back to cached data if the
network is not available:
📋
query.setCachePolicy(ParseQuery.CachePolicy.NETWOR
query.findInBackground(new
FindCallback<ParseObject>() {
public void done(List<ParseObject> scoreList,
ParseException e) {
if (e == null) {
// Results were successfully found,
looking first on the
// network and then on disk.
} else {
// The network was inaccessible and we
have no cached data
// for this query.
}
https://docs.parseplatform.org/android/guide/#users 30/171
7/26/22, 5:14 PM Android Developers Guide | Parse
}
});
📋
boolean isInCache = query.hasCachedResult();
query.clearCachedResult(); 📋
https://docs.parseplatform.org/android/guide/#users 31/171
7/26/22, 5:14 PM Android Developers Guide | Parse
ParseQuery.clearAllCachedResults(); 📋
Counting Objects
Note: In the old Parse hosted backend, count queries
were rate limited to a maximum of 160 requests per
minute. They also returned inaccurate results for
classes with more than 1,000 objects. But, Parse
Server has removed both constraints and can count
objects well above 1,000.
ParseQuery<ParseObject> query = 📋
ParseQuery.getQuery("GameScore");
query.whereEqualTo("playerName", "Sean Plott");
query.countInBackground(new CountCallback() {
public void done(int count, ParseException e)
{
if (e == null) {
// The count request succeeded. Log the
count
Log.d("score", "Sean has played " + count
+ " games");
} else {
// The request failed
}
}
});
If you want to block the calling thread, you can also use
the synchronous query.count() method.
Compound Queries
If you want to find objects that match one of several
queries, you can use ParseQuery.or method to
construct a query that is an or of the queries passed in.
https://docs.parseplatform.org/android/guide/#users 32/171
7/26/22, 5:14 PM Android Developers Guide | Parse
ParseQuery<ParseObject> lotsOfWins = 📋
ParseQuery.getQuery("Player");
lotsOfWins.whereGreaterThan(150);
ParseQuery<ParseObject> fewWins =
ParseQuery.getQuery("Player");
fewWins.whereLessThan(5);
ParseQuery<ParseObject> mainQuery =
ParseQuery.or(queries);
mainQuery.findInBackground(new
FindCallback<ParseObject>() {
public void done(List<ParseObject> results,
ParseException e) {
// results has the list of players that win
a lot or haven't won much.
}
});
Users
At the core of many apps, there is a notion of user
accounts that lets users access their information in a
secure manner. We provide a specialized user class
called ParseUser that automatically handles much of
the functionality required for user account
management.
https://docs.parseplatform.org/android/guide/#users 33/171
7/26/22, 5:14 PM Android Developers Guide | Parse
ParseUser Properties
ParseUser has several properties that set it apart from
ParseObject :
Signing Up
The first thing your app will do is probably ask the user
to sign up. The following code illustrates a typical sign
up:
user.signUpInBackground(new SignUpCallback() {
public void done(ParseException e) {
if (e == null) {
// Hooray! Let them use the app now.
} else {
// Sign up didn't succeed. Look at the
ParseException
// to figure out what went wrong
}
}
});
https://docs.parseplatform.org/android/guide/#users 34/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Logging In
Of course, after you allow users to sign up, you need be
able to let them log in to their account in the future. To
do this, you can use the class method
logInInBackground .
ParseUser.logInInBackground("Jerry", 📋
"showmethemoney", new LogInCallback() {
public void done(ParseUser user,
ParseException e) {
if (user != null) {
// Hooray! The user is logged in.
} else {
// Signup failed. Look at the
https://docs.parseplatform.org/android/guide/#users 35/171
7/26/22, 5:14 PM Android Developers Guide | Parse
ParseException to see what happened.
}
}
});
Verifying Emails
Enabling email verification in an application’s settings
allows the application to reserve part of its experience
for users with confirmed email addresses. Email
verification adds the emailVerified key to the
ParseUser object. When a ParseUser ’s email is set or
modified, emailVerified is set to false . Parse then
emails the user a link which will set emailVerified to
true .
Current User
It would be bothersome if the user had to log in every
time they open your app. You can avoid this by using
the cached currentUser object.
ParseUser currentUser = 📋
ParseUser.getCurrentUser();
if (currentUser != null) {
// do stuff with the user
} else {
// show the signup or login screen
}
https://docs.parseplatform.org/android/guide/#users 36/171
7/26/22, 5:14 PM Android Developers Guide | Parse
ParseUser.logOut(); 📋
ParseUser currentUser =
ParseUser.getCurrentUser(); // this will now be
null
Anonymous Users
Being able to associate data and objects with individual
users is highly valuable, but sometimes you want to be
able to do this without forcing a user to specify a
username and password.
ParseAnonymousUtils.logIn(new LogInCallback() 📋
{
@Override
public void done(ParseUser user,
ParseException e) {
if (e != null) {
Log.d("MyApp", "Anonymous login
failed.");
} else {
Log.d("MyApp", "Anonymous user logged
in.");
}
}
});
if 📋
(ParseAnonymousUtils.isLinked(ParseUser.getCurrent
{
enableSignUpButton();
} else {
https://docs.parseplatform.org/android/guide/#users 37/171
7/26/22, 5:14 PM Android Developers Guide | Parse
enableLogOutButton();
}
ParseUser.enableAutomaticUser(); 📋
ParseUser.getCurrentUser().increment("RunCount");
ParseUser.getCurrentUser().saveInBackground();
ParseUser.becomeInBackground("session-token- 📋
here", new LogInCallback() {
public void done(ParseUser user,
ParseException e) {
if (user != null) {
// The current user is now set to user.
} else {
// The token could not be validated.
}
}
});
📋
ParseUser user = ParseUser.logIn("my_username",
"my_password");
user.setUsername("my_new_username"); // attempt
to change username
user.saveInBackground(); // This succeeds,
since the user was authenticated on the device
https://docs.parseplatform.org/android/guide/#users 39/171
7/26/22, 5:14 PM Android Developers Guide | Parse
groupMessage.setACL(groupACL);
groupMessage.saveInBackground();
https://docs.parseplatform.org/android/guide/#users 40/171
7/26/22, 5:14 PM Android Developers Guide | Parse
ParseACL.setDefaultACL(defaultACL, true); 📋
https://docs.parseplatform.org/android/guide/#users 41/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Resetting Passwords
It’s a fact that as soon as you introduce passwords into
a system, users will forget them. In such cases, our
library provides a way to let them securely reset their
password.
To kick off the password reset flow, ask the user for
their email address, and call:
📋
ParseUser.requestPasswordResetInBackground("myemai
new RequestPasswordResetCallback() {
public void done(ParseException e) {
if (e == null) {
// An email was successfully sent with
reset instructions.
} else {
// Something went wrong. Look at the
ParseException to see what's up.
}
}
});
https://docs.parseplatform.org/android/guide/#users 42/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Querying
To query for users, you need to use the special user
query:
ParseQuery<ParseUser> query = 📋
ParseUser.getQuery();
query.whereEqualTo("gender", "female");
query.findInBackground(new
FindCallback<ParseUser>() {
public void done(List<ParseUser> objects,
ParseException e) {
if (e == null) {
// The query was successful.
} else {
// Something went wrong.
}
}
});
Associations
Associations involving a ParseUser work right of the
box. For example, let’s say you’re making a blogging app.
To store a new post for a user and retrieve all their
posts:
Facebook Users
Parse provides an easy way to integrate Facebook with
your application. The Facebook SDK can be used with
our SDK, and is integrated with the ParseUser class to
make linking your users to their Facebook identities
easy.
SETTING UP FACEBOOK
4 Add 'com.github.parse-
community:ParseFacebookUtils-
Android:latest.version.here' to your Gradle
dependencies (X.X.X should be JitPack 4.0.0 )
ParseFacebookUtils.initialize(context); 📋
@Override 📋
protected void onActivityResult(int
requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode,
resultCode, data);
ParseFacebookUtils.onActivityResult(requestCode,
resultCode, data);
}
https://docs.parseplatform.org/android/guide/#users 45/171
7/26/22, 5:14 PM Android Developers Guide | Parse
LOGIN & SIGNUP
📋
ParseFacebookUtils.logInWithReadPermissionsInBackg
permissions, new LogInCallback() {
@Override
public void done(ParseUser user,
ParseException err) {
if (user == null) {
Log.d("MyApp", "Uh oh. The user cancelled
the Facebook login.");
} else if (user.isNew()) {
Log.d("MyApp", "User signed up and logged
in through Facebook!");
} else {
Log.d("MyApp", "User logged in through
Facebook!");
}
}
});
FACEBOOK LINKING
if (!ParseFacebookUtils.isLinked(user)) { 📋
ParseFacebookUtils.linkWithReadPermissionsInBackgr
this, permissions, new SaveCallback() {
@Override
public void done(ParseException ex) {
if (ParseFacebookUtils.isLinked(user)) {
Log.d("MyApp", "Woohoo, user logged in
with Facebook!");
}
}
});
}
📋
ParseFacebookUtils.unlinkInBackground(user, new
SaveCallback() {
@Override
public void done(ParseException ex) {
if (ex == null) {
Log.d("MyApp", "The user is no longer
associated with their Facebook account.");
}
}
});
REQUESTING PERMISSIONS
https://docs.parseplatform.org/android/guide/#users 47/171
7/26/22, 5:14 PM Android Developers Guide | Parse
ParseFacebookUtils.linkWithPublishPermissionsInB
ackground() . For more information about requesting
new permissions, please see Facebook’s API
documentation for these functions.
Twitter Users
As with Facebook, Parse also provides an easy way to
integrate Twitter authentication into your application.
The Parse SDK provides a straightforward way to
authorize and link a Twitter account to your
ParseUser s. With just a few lines of code, you’ll be able
to provide a “log in with Twitter” option in your app, and
be able to save their data to Parse.
SETTING UP TWITTER
https://docs.parseplatform.org/android/guide/#users 48/171
7/26/22, 5:14 PM Android Developers Guide | Parse
4 Add 'com.github.parse-
community:ParseTwitterUtils-
Android:latest.version.here' to your Gradle
dependencies.
ParseTwitterUtils.initialize("YOUR CONSUMER 📋
KEY", "YOUR CONSUMER SECRET");
ParseTwitterUtils.logIn(this, new 📋
LogInCallback() {
@Override
public void done(ParseUser user,
ParseException err) {
if (user == null) {
Log.d("MyApp", "Uh oh. The user cancelled
the Twitter login.");
} else if (user.isNew()) {
Log.d("MyApp", "User signed up and logged
in through Twitter!");
} else {
Log.d("MyApp", "User logged in through
Twitter!");
}
}
});
https://docs.parseplatform.org/android/guide/#users 49/171
7/26/22, 5:14 PM Android Developers Guide | Parse
TWITTER LINKING
if (!ParseTwitterUtils.isLinked(user)) { 📋
ParseTwitterUtils.link(user, this, new
SaveCallback() {
@Override
public void done(ParseException ex) {
if (ParseTwitterUtils.isLinked(user)) {
Log.d("MyApp", "Woohoo, user logged in
with Twitter!");
}
}
});
}
ParseTwitterUtils.unlinkInBackground(user, new📋
SaveCallback() {
@Override
public void done(ParseException ex) {
if (ex == null) {
Log.d("MyApp", "The user is no longer
associated with their Twitter account.");
}
}
});
https://docs.parseplatform.org/android/guide/#users 50/171
7/26/22, 5:14 PM Android Developers Guide | Parse
.url("https://api.twitter.com/1.1/account/verify_c
.build();
Sessions
Sessions represent an instance of a user logged into a
device. Sessions are automatically created when users
log in or sign up. They are automatically deleted when
users log out. There is one distinct Session object for
each user-installation pair; if a user issues a login
request from a device they’re already logged into, that
user’s previous Session object for that Installation is
automatically deleted. Session objects are stored on
Parse in the Session class, and you can view them on
the Parse Dashboard Data Browser. We provide a set of
APIs to manage Session objects in your app.
https://docs.parseplatform.org/android/guide/#users 51/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Session Properties
The Session object has these special fields:
https://docs.parseplatform.org/android/guide/#users 52/171
7/26/22, 5:14 PM Android Developers Guide | Parse
https://docs.parseplatform.org/android/guide/#users 53/171
7/26/22, 5:14 PM Android Developers Guide | Parse
//--------------------------------------
// Option #2: Show login screen so user can
re-authenticate.
//--------------------------------------
// You may want this if the logout button
could be inaccessible in the UI.
//
// startActivityForResult(new
ParseLoginBuilder(getActivity()).build(), 0);
}
}
Session Security
Session objects can only be accessed by the user
specified in the user field. All Session objects have an
ACL that is read and write by that user only. You cannot
change this ACL. This means querying for sessions will
only return objects that match the current logged-in
user.
https://docs.parseplatform.org/android/guide/#users 54/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Roles
As your app grows in scope and user-base, you may find
yourself needing more coarse-grained control over
access to pieces of your data than user-linked ACLs can
provide. To address this requirement, Parse supports a
form of Role-based Access Control. Roles provide a
logical way of grouping users with common access
privileges to your Parse data. Roles are named objects
that contain users and other roles. Any permission
granted to a role is implicitly granted to its users as well
as to the users of any roles that it contains.
https://docs.parseplatform.org/android/guide/#users 55/171
7/26/22, 5:14 PM Android Developers Guide | Parse
ParseRole Properties
ParseRole has several properties that set it apart from
ParseObject :
https://docs.parseplatform.org/android/guide/#users 56/171
7/26/22, 5:14 PM Android Developers Guide | Parse
You can add users and roles that should inherit your
new role’s permissions through the “users” and “roles”
relations on ParseRole :
https://docs.parseplatform.org/android/guide/#users 57/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Role Hierarchy
As described above, one role can contain another,
establishing a parent-child relationship between the
two roles. The consequence of this relationship is that
any permission granted to the parent role is implicitly
granted to all of its child roles.
https://docs.parseplatform.org/android/guide/#users 58/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Files
The ParseFile
ParseFile lets you store application files in the cloud
that would otherwise be too large or cumbersome to fit
into a regular ParseObject . The most common use
case is storing images but you can also use it for
documents, videos, music, and any other binary data.
file.saveInBackground(); 📋
https://docs.parseplatform.org/android/guide/#users 59/171
7/26/22, 5:14 PM Android Developers Guide | Parse
ParseFile applicantResume = 📋
(ParseFile)anotherApplication.get("applicantResume
applicantResume.getDataInBackground(new
GetDataCallback() {
public void done(byte[] data, ParseException
e) {
if (e == null) {
// data has the bytes for the resume
} else {
// something went wrong
}
}
});
Progress
It’s easy to get the progress of both uploads and
downloads using ParseFile by passing a
ProgressCallback to saveInBackground and
getDataInBackground . For example:
file.saveInBackground(new SaveCallback() {
public void done(ParseException e) {
// Handle success or failure here ...
}
}, new ProgressCallback() {
public void done(Integer percentDone) {
https://docs.parseplatform.org/android/guide/#users 60/171
7/26/22, 5:14 PM Android Developers Guide | Parse
// Update your progress spinner here.
percentDone will be between 0 and 100.
}
});
Using 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,
@Override
protected void onCreate(@Nullable Bundle
savedInstanceState) {
if (savedInstanceState != null) {
file = (ParseFile)
savedInstanceState.getParcelable("file");
}
}
https://docs.parseplatform.org/android/guide/#users 61/171
7/26/22, 5:14 PM Android Developers Guide | Parse
GeoPoints
Parse allows you to associate real-world latitude and
longitude coordinates with an object. Adding a
ParseGeoPoint to a ParseObject allows queries to
take into account the proximity of an object to a
reference point. This allows you to easily do things like
find out what user is closest to another user or which
places are closest to a user.
ParseGeoPoint
To associate a point with an object you first need to
create a ParseGeoPoint . For example, to create a point
with latitude of 40.0 degrees and -30.0 degrees
longitude:
placeObject.put("location", point); 📋
placeObject.getParseGeoPoint("location"); 📋
ParsePolygon
https://docs.parseplatform.org/android/guide/#users 62/171
7/26/22, 5:14 PM Android Developers Guide | Parse
placeObject.put("bounds", polygon); 📋
placeObject.getParsePolygon("bounds"); 📋
Geo Queries
Now that you have a bunch of objects with spatial
coordinates, it would be nice to find out which objects
are closest to a point. This can be done by adding
another restriction to ParseQuery using whereNear .
Getting a list of ten places that are closest to a user
may look something like:
It’s also possible to query for the set of objects that are
contained within a particular area. To find the objects in
a rectangular bounding box, add the
whereWithinGeoBox restriction to your ParseQuery .
https://docs.parseplatform.org/android/guide/#users 64/171
7/26/22, 5:14 PM Android Developers Guide | Parse
// Returns True
polygon.containsPoint(inside);
// Returns False
polygon.containsPoint(outside);
Utilizing Parcelable
As most public facing components of the SDK,
ParseGeoPoint and ParsePolygon implements the
Parcelable interface. This means you can retain a
ParseGeoPoint and ParsePolygon 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,
@Override
protected void onCreate(@Nullable Bundle
savedInstanceState) {
if (savedInstanceState != null) {
point = (ParseGeoPoint)
savedInstanceState.getParcelable("point");
}
}
https://docs.parseplatform.org/android/guide/#users 65/171
7/26/22, 5:14 PM Android Developers Guide | Parse
@Override
protected void onCreate(@Nullable Bundle
savedInstanceState) {
if (savedInstanceState != null) {
polygon = (ParsePolygon)
savedInstanceState.getParcelable("polygon");
}
}
Caveats
At the moment there are a couple of things to watch
out for:
Local Datastore
The Parse Android SDK provides a local datastore
which can be used to store and retrieve ParseObject s,
even when the network is unavailable. To enable this
functionality, simply call
Parse.enableLocalDatastore() before your call to
initialize .
import com.parse.Parse; 📋
import android.app.Application;
Parse.enableLocalDatastore(this);
Parse.initialize(this);
}
}
Parse.initialize(new 📋
Parse.Configuration.Builder(context)
.server(...)
.applicationId(...)
.enableLocalDataStore()
.build());
Pinning
You can store a ParseObject in the local datastore by
pinning it. Pinning a ParseObject is recursive, just like
saving, so any objects that are pointed to by the one
https://docs.parseplatform.org/android/guide/#users 67/171
7/26/22, 5:14 PM Android Developers Guide | Parse
gameScore.pinInBackground();
ParseObject.pinAllInBackground(listOfObjects);📋
Retrieving
Storing objects is great, but it’s only useful if you can
then get the objects back out later. To retrieve an
object from the local datastore, call the
fromLocalDatastore method to tell the ParseQuery
where to look for its results.
ParseQuery<ParseObject> query = 📋
ParseQuery.getQuery("GameScore");
query.fromLocalDatastore();
https://docs.parseplatform.org/android/guide/#users 68/171
7/26/22, 5:14 PM Android Developers Guide | Parse
query.getInBackground("xWMyZ4YE", new 📋
GetCallback<ParseObject>() {
public void done(ParseObject object,
ParseException e) {
if (e == null) {
// object will be your game score
} else {
// something went wrong
}
}
});
ParseQuery<ParseObject> query = 📋
ParseQuery.getQuery("GameScore");
query.whereEqualTo("playerName", "Joe Bob");
query.fromLocalDatastore();
// If data is protected by Role based ACLs:
query.ignoreAcls();
query.findInBackground(new
FindCallback<ParseObject>() {
public void done(List<ParseObject>
scoreList,
ParseException e) {
if (e == null) {
Log.d("score", "Retrieved " +
scoreList.size());
} else {
Log.d("score", "Error: " +
e.getMessage());
}
}
});
Unpinning
When you are done with an object and no longer need
it to be in the local datastore, you can simply unpin it.
This will free up disk space on the device and keep your
queries on the local datastore running quickly.
https://docs.parseplatform.org/android/guide/#users 69/171
7/26/22, 5:14 PM Android Developers Guide | Parse
gameScore.unpinInBackground(); 📋
📋
ParseObject.unpinAllInBackground(listOfObjects);
ParseObject.unpinAllInBackground("MyScores"); 📋
https://docs.parseplatform.org/android/guide/#users 70/171
7/26/22, 5:14 PM Android Developers Guide | Parse
ParseQuery<ParseObject> query = 📋
ParseQuery.getQuery(“GameScore");
query.orderByDescending(“score”);
ParseObject.unpinAllInBackground(“highScores”,
new DeleteCallback() {
public void done(ParseException e) {
// Cache the new results.
ParseObject.pinAllInBackground(“highScores”,
scores);
}
});
}
});
When you want to get the cached results for the query,
you can then run the same query against the local
datastore.
ParseQuery<ParseObject> query = 📋
ParseQuery.getQuery(“GameScore");
query.orderByDescending(“score”);
query.fromLocalDatastore();
query.findInBackground(new
FindCallback<ParseObject>() {
public void done(List<ParseObject> scores,
ParseException e) {
// Yay! Cached scores!
}
});
https://docs.parseplatform.org/android/guide/#users 71/171
7/26/22, 5:14 PM Android Developers Guide | Parse
The SDK will make sure to save the object the next time
the network is available.
gameScore.saveEventually(); 📋
ParseQuery<ParseObject> query = 📋
ParseQuery.getQuery(“GameScore");
query.fromPin(“MyChanges”);
query.findInBackground(new
FindCallback<ParseObject>() {
public void done(List<ParseObject> scores,
ParseException e) {
for (ParseObject score in scores) {
score.saveInBackground();
score.unpinInBackground(“MyChanges”);
}
}
});
Push Notifications
Push notifications are a great way to keep your users
engaged and informed about your app. You can reach
your entire user base quickly and effectively. This guide
will help you through the setup process and the general
usage of Parse to send push notifications.
Setting Up Push
https://docs.parseplatform.org/android/guide/#users 72/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Installations
Every Parse application installed on a device registered
for push notifications has an associated Installation
object. The Installation object is where you store all
the data needed to target push notifications. For
example, in a baseball app, you could store the teams a
user is interested in to send updates about their
performance. Saving the Installation object is also
required for tracking push-related app open events.
https://docs.parseplatform.org/android/guide/#users 73/171
7/26/22, 5:14 PM Android Developers Guide | Parse
https://docs.parseplatform.org/android/guide/#users 74/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Sending Pushes
There are two ways to send push notifications using
Parse: channels and advanced targeting. Channels
offer a simple and easy to use model for sending
pushes, while advanced targeting offers a more
powerful and flexible model. Both are fully compatible
with each other and will be covered in this section.
https://docs.parseplatform.org/android/guide/#users 75/171
7/26/22, 5:14 PM Android Developers Guide | Parse
USING CHANNELS
SUBSCRIBING TO CHANNELS
📋
// When users indicate they are Giants fans, we
subscribe them to that channel.
ParsePush.subscribeInBackground("Giants");
You can also get the set of channels that the current
device is subscribed to using:
List<String> subscribedChannels = 📋
ParseInstallation.getCurrentInstallation().getList
https://docs.parseplatform.org/android/guide/#users 76/171
7/26/22, 5:14 PM Android Developers Guide | Parse
https://docs.parseplatform.org/android/guide/#users 77/171
7/26/22, 5:14 PM Android Developers Guide | Parse
installation.saveInBackground();
https://docs.parseplatform.org/android/guide/#users 78/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Sending Options
https://docs.parseplatform.org/android/guide/#users 79/171
7/26/22, 5:14 PM Android Developers Guide | Parse
https://docs.parseplatform.org/android/guide/#users 80/171
7/26/22, 5:14 PM Android Developers Guide | Parse
https://docs.parseplatform.org/android/guide/#users 81/171
7/26/22, 5:14 PM Android Developers Guide | Parse
ParsePush push = new ParsePush();
push.setExpirationTimeInterval(weekInterval);
push.setQuery(everyoneQuery);
push.setMessage("Season tickets on sale until
next week!");
push.sendPushInBackground();
TARGETING BY PLATFORM
ParseQuery query = 📋
ParseInstallation.getQuery();
query.whereEqualTo("channels",
"suitcaseOwners");
Scheduling Pushes
You can schedule a push in advance by specifying a
push time with ParsePush.setPushTime(long) . For
example, if a user schedules a game reminder for a
https://docs.parseplatform.org/android/guide/#users 82/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Receiving Pushes
Make sure you’ve gone through the Android Push
QuickStart to set up your app to receive pushes.
CUSTOMIZING NOTIFICATIONS
https://docs.parseplatform.org/android/guide/#users 83/171
7/26/22, 5:14 PM Android Developers Guide | Parse
CUSTOMIZING NOTIFICATION ICONS
<meta-data 📋
android:name="com.parse.push.notification_icon"
android:resource="@drawable/push_icon"/>
https://docs.parseplatform.org/android/guide/#users 84/171
7/26/22, 5:14 PM Android Developers Guide | Parse
MANAGING THE PUSH LIFECYCLE
ParseAnalytics.trackAppOpened(getIntent()); 📋
Push Experiments
You can A/B test your push notifications to figure out
the best way to keep your users engaged. With A/B
testing, you can simultaneously send two versions of
your push notification to different devices, and use each
version’s push open rates to figure out which one is
better. You can test by either message or send time.
A/B TESTING
https://docs.parseplatform.org/android/guide/#users 86/171
7/26/22, 5:14 PM Android Developers Guide | Parse
After you send the push, you can come back to the
push console to see in real time which version resulted
in more push opens, along with other metrics such as
statistical confidence interval. It’s normal for the
number of recipients in each group to be slightly
different because some devices that we had originally
allocated to that experiment group may have
uninstalled the app. It’s also possible for the random
group assignment to be slightly uneven when the test
audience size is small. Since we calculate open rate
separately for each group based on recipient count, this
should not significantly affect your experiment results.
EXPERIMENT STATISTICS
https://docs.parseplatform.org/android/guide/#users 87/171
7/26/22, 5:14 PM Android Developers Guide | Parse
CONFIDENCE INTERVAL
https://docs.parseplatform.org/android/guide/#users 88/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Push Localization
Localizing your app’s content is a proven way to drive
greater engagement. We’ve made it easy to localize
your push messages with Push Localization. The latest
version of the Parse Android SDK will detect and store
the user’s language in the installation object, and via the
web push console you’ll be able to send localized push
messages to your users in a single broadcast.
Troubleshooting
Setting up Push Notifications is often a source of
frustration for developers. The process is complicated
and invites problems to happen along the way. If you
run into issues, try some of these troubleshooting tips.
https://docs.parseplatform.org/android/guide/#users 89/171
7/26/22, 5:14 PM Android Developers Guide | Parse
push.sendPushInBackground(new SendCallback() {📋
public void done(ParseException e) {
if (e == null) {
Log.d("push", "The push campaign has been
created.");
} else {
Log.d("push", "Error sending push:" +
e.getMessage());
}
}
});
Please note that SDKs that use a Client Key, such as the
Android SDK, can only send push notifications if Client
Push is enabled in your Parse app’s Push Notification
settings. Otherwise, you’ll only be able to send pushes
from the web console, the REST API, or by using the
JavaScript SDK from Cloud Code. We strongly
encourage developers to turn off Client Push before
releasing their app publicly unless your use case allows
https://docs.parseplatform.org/android/guide/#users 90/171
7/26/22, 5:14 PM Android Developers Guide | Parse
You can check the Push Delivery Report for the cause
of failed deliveries: Mismatch Sender ID happens when
the registered sender is not the same as the one
currently sending the notifications, Not Registered is
returned when the registration key is deemed invalid,
https://docs.parseplatform.org/android/guide/#users 92/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Config
Parse Config
ParseConfig is a way to configure your applications
remotely by storing a single configuration object on
Parse. It enables you to add things like feature gating or
a simple “Message of the Day”. To start using
ParseConfig you need to add a few key/value pairs
(parameters) to your app on the Parse Config
Dashboard.
ParseConfig.getInBackground(new 📋
ConfigCallback() {
@Override
public void done(ParseConfig config,
ParseException e) {
int number =
config.getInt("winningNumber");
https://docs.parseplatform.org/android/guide/#users 94/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Log.d("TAG", String.format("Yay! The number
is %d!", number));
}
});
Retrieving Config
ParseConfig is built to be as robust and reliable as
possible, even in the face of poor internet connections.
Caching is used by default to ensure that the latest
successfully fetched config is always available. In the
below example we use getInBackground to retrieve
the latest version of config from the server, and if the
fetch fails we can simply fall back to the version that we
successfully fetched before via getCurrentConfig .
Current Config
Every ParseConfig instance that you get is always
immutable. When you retrieve a new ParseConfig in
the future from the network, it will not modify any
existing ParseConfig instance, but will instead create a
new one and make it available via
ParseConfig.getCurrentConfig() . Therefore, you can
safely pass around any ParseConfig object and safely
assume that it will not automatically change.
https://docs.parseplatform.org/android/guide/#users 95/171
7/26/22, 5:14 PM Android Developers Guide | Parse
class Helper { 📋
private static final long
configRefreshInterval = 12 * 60 * 60 * 1000;
private static long lastFetchedTime;
Parameters
ParseConfig supports most of the data types
supported by ParseObject :
String
Numbers (boolean/int/double/long)
Date
ParseFile
ParseGeoPoint
List
Map
Analytics
Parse provides a number of hooks for you to get a
glimpse into the ticking heart of your app. We
https://docs.parseplatform.org/android/guide/#users 96/171
7/26/22, 5:14 PM Android Developers Guide | Parse
📋
ParseAnalytics.trackAppOpenedInBackground(getInten
Custom Analytics
ParseAnalytics also allows you to track free-form
events, with a handful of String keys and values.
These extra dimensions allow segmentation of your
custom events via your app’s Dashboard.
https://docs.parseplatform.org/android/guide/#users 97/171
7/26/22, 5:14 PM Android Developers Guide | Parse
User Interface
At the end of the day, users of your application will be
interacting with Android UI components. We provide
several UI widgets to make working with Parse data
easier.
ParseLoginUI
https://docs.parseplatform.org/android/guide/#users 98/171
7/26/22, 5:14 PM Android Developers Guide | Parse
<activity 📋
android:name="com.parse.ui.ParseLoginActivity"
android:label="@string/app_name"
android:launchMode="singleTop">
<meta-data
https://docs.parseplatform.org/android/guide/#users 99/171
7/26/22, 5:14 PM Android Developers Guide | Parse
android:name="com.parse.ui.ParseLoginActivity.PARS
android:value="true"/>
</activity>
ADVANCED INTEGRATION
https://docs.parseplatform.org/android/guide/#users 100/171
7/26/22, 5:14 PM Android Developers Guide | Parse
https://docs.parseplatform.org/android/guide/#users 101/171
7/26/22, 5:14 PM Android Developers Guide | Parse
PARSE_LOGIN_INVALID_CREDENTIALS_TEXT :
String to show on the toast when the user login
fails (default = “The username and password you
entered don’t match”)
https://docs.parseplatform.org/android/guide/#users 102/171
7/26/22, 5:14 PM Android Developers Guide | Parse
PARSE_SIGNUP_MIN_PASSWORD_LENGTH : Integer
for the minimum required password length on the
signup form (default = 6)
PARSE_SIGNUP_SUBMIT_BUTTON_TEXT : String to
display on the submit button on the signup
screen (default = “Submit”)
FACEBOOK_LOGIN_BUTTON_TEXT : String to
display on the Facebook login button (default =
“Log in with Facebook”)
Example configuration:
<activity 📋
android:name="com.parse.ui.ParseLoginActivity"
android:label="@string/my_app_name"
android:launchMode="singleTop">
<!-- We reference a drawable resource here,
so we must use android:resource -->
<meta-data
android:name="com.parse.ui.ParseLoginActivity.APP_
android:resource="@drawable/my_app_logo"/>
<!-- For these non-resource options, use
android:value -->
<meta-data
android:name="com.parse.ui.ParseLoginActivity.PARS
android:value="true"/>
<meta-data
https://docs.parseplatform.org/android/guide/#users 103/171
7/26/22, 5:14 PM Android Developers Guide | Parse
android:name="com.parse.ui.ParseLoginActivity.PARS
android:value="true"/>
<meta-data
android:name="com.parse.ui.ParseLoginActivity.PARS
android:value="@string/password_reset_text"/>
<meta-data
android:name="com.parse.ui.ParseLoginActivity.MIN_
android:value="8"/>
<meta-data
android:name="com.parse.ui.ParseLoginActivity.FACE
android:value="true"/>
<!-- We reference a string-array resource
here, so we must use android:resource -->
<meta-data
android:name="com.parse.ui.ParseLoginActivity.FACE
android:resource="@array/my_facebook_permissions"/
</activity>
<resources> 📋
<string-array
name="my_facebook_permissions">
<item>public_profile</item>
<item>user_friends</item>
</string-array>
</resources>
CONFIGURE BY CODE
https://docs.parseplatform.org/android/guide/#users 104/171
7/26/22, 5:14 PM Android Developers Guide | Parse
.setParseLoginInvalidCredentialsToastText("You
email and/or password is not correct")
.setParseLoginEmailAsUsername(true)
.setParseSignupSubmitButtonText("Submit
registration")
.setFacebookLoginEnabled(true)
.setFacebookLoginButtonText("Facebook")
.setFacebookLoginPermissions(Arrays.asList("public
"user_friends"))
.setTwitterLoginEnabled(true)
.setTwitterLoginButtontext("Twitter")
.build();
startActivityForResult(parseLoginIntent, 0);
com_parse_ui_parse_login_fragment.xml : If
you do not use certain login methods
(username/password, Facebook, or Twitter), you
can remove the corresponding UI elements from
this layout.
com_parse_ui_parse_signup_fragment.xml : You
can add additional input fields in the signup form
here. If you do, you also need add code to
ParseSignupFragment to copy that data into the
ParseUser object.
com_parse_ui_parse_login_help_fragment.xml :
You can change the message for password reset.
https://docs.parseplatform.org/android/guide/#users 105/171
7/26/22, 5:14 PM Android Developers Guide | Parse
1 Instantiate a ParseQueryAdapter .
https://docs.parseplatform.org/android/guide/#users 106/171
7/26/22, 5:14 PM Android Developers Guide | Parse
// Inside an Activity 📋
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Uses a layout with a ListView (id:
"listview"), which uses our Adapter.
setContentView(R.layout.main);
into the constructor, and the adapter will then use that
query to determine which objects to fetch and display.
ParseQueryAdapter<ParseObject> adapter = 📋
new ParseQueryAdapter<ParseObject>(this, new
ParseQueryAdapter.QueryFactory<ParseObject>() {
public ParseQuery<ParseObject> create() {
// Here we can configure a ParseQuery to
our heart's desire.
ParseQuery query = new
ParseQuery("Band");
query.whereContainedIn("genre",
Arrays.asList({ "Punk", "Metal" }));
query.whereGreaterThanOrEqualTo("memberCount",
4);
query.orderByDescending("albumsSoldCount");
return query;
}
});
https://docs.parseplatform.org/android/guide/#users 108/171
7/26/22, 5:14 PM Android Developers Guide | Parse
@Override 📋
public View getItemView(ParseObject object,
View v, ViewGroup parent) {
if (v == null) {
v = View.inflate(getContext(),
R.layout.adapter_item, null);
}
descriptionView.setText(object.getString("descript
return v;
}
@Override 📋
public View getItemView(ParseObject object,
View v, ViewGroup parent) {
if (v == null) {
v = View.inflate(getContext(),
R.layout.adapter_item, null);
}
v.setBackgroundColor(object.getInt("color"));
return v;
}
@Override
public View getNextPageView(View v, ViewGroup
parent) {
if (v == null) {
// R.layout.adapter_next_page contains an
ImageView with a custom graphic
// and a TextView.
https://docs.parseplatform.org/android/guide/#users 109/171
7/26/22, 5:14 PM Android Developers Guide | Parse
v = View.inflate(getContext(),
R.layout.adapter_next_page, null);
}
TextView textView = (TextView)
v.findViewById(R.id.nextPageTextViewId);
textView.setText("Loaded " + getCount() + "
rows. Get more!");
return v;
}
Lifecycle Methods
We expose two hooks in the data lifecycle of the
Adapter for you to execute custom logic — right before
we query Parse for your data and right after the
fetched objects have been loaded from the query.
These methods are particularly useful for toggling
some loading UI.
https://docs.parseplatform.org/android/guide/#users 110/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Pagination
Pagination ensures that the table only gets one page of
objects at a time. You can set the number of objects are
in a page by calling setObjectsPerPage(int) .
Auto-loading of Data
When the AdapterView that your ParseQueryAdapter
is set on is attached to a window, the
ParseQueryAdapter ’s loadObjects() method is
automatically called, triggering the fetching of the first
page of results. To disable this behavior (perhaps to
delay the fetching of data, or run some custom logic
ahead of time), just call setAutoload(false) and call
loadObjects() manually if autoload is disabled.
Data
We’ve designed the Parse SDKs so that you typically
don’t need to worry about how data is saved while
using the client SDKs. Simply add data to the Parse
Object , and it’ll be saved correctly.
Data Storage
https://docs.parseplatform.org/android/guide/#users 111/171
7/26/22, 5:14 PM Android Developers Guide | Parse
https://docs.parseplatform.org/android/guide/#users 112/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Importing Data
You may import data into your Parse app by using CSV
or JSON files. To create a new class with data from a
CSV or JSON file, go to the Data Browser and click the
“Import” button on the left hand column.
{ "results": [ 📋
{
"score": 1337,
"playerName": "Sean Plott",
"cheatMode": false,
"createdAt": "2022-01-01T12:23:45.678Z",
"updatedAt": "2022-01-01T12:23:45.678Z",
"objectId": "fchpZwSuGG"
}]
}
https://docs.parseplatform.org/android/guide/#users 113/171
7/26/22, 5:14 PM Android Developers Guide | Parse
{ "results": 📋
[{
"username": "cooldude",
"createdAt": "1983-09-13T22:42:30.548Z",
"updatedAt": "2015-09-04T10:12:42.137Z",
"objectId": "ttttSEpfXm",
"sessionToken":
"dfwfq3dh0zwe5y2sqv514p4ib",
"bcryptPassword":
"$2a$10$ICV5UeEf3lICfnE9W9pN9.O9Ved/ozNo7G83Qbdk5r
}]
}
EXPORT FORMATS
OFFLINE ANALYSIS
https://docs.parseplatform.org/android/guide/#users 115/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Relations
There are three kinds of relationships. One-to-one
relationships enable one object to be associated with
another object. One-to-many relationships enable one
object to have many related objects. Finally, many-to-
many relationships enable complex relationships among
many objects.
One-to-Many
When you’re thinking about one-to-many relationships
and whether to implement Pointers or Arrays, there are
several factors to consider. First, how many objects are
involved in this relationship? If the “many” side of the
relationship could contain a very large number (greater
than 100 or so) of objects, then you have to use
Pointers. If the number of objects is small (fewer than
100 or so), then Arrays may be more convenient,
especially if you typically need to get all of the related
objects (the “many” in the “one-to-many relationship”)
at the same time as the parent object.
USING POINTERS
https://docs.parseplatform.org/android/guide/#users 116/171
7/26/22, 5:14 PM Android Developers Guide | Parse
ParseQuery<ParseObject> gameQuery = 📋
ParseQuery.getQuery("Game");
gameQuery.whereEqualTo("createdBy",
ParseUser.getCurrentUser());
USING ARRAYS
https://docs.parseplatform.org/android/guide/#users 117/171
7/26/22, 5:14 PM Android Developers Guide | Parse
ArrayList<ParseObject> weapons = 📋
ParseUser.getCurrentUser().get("weaponsList");
https://docs.parseplatform.org/android/guide/#users 118/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Many-to-Many
Now let’s tackle many-to-many relationships. Suppose
we had a book reading app and we wanted to model
Book objects and Author objects. As we know, a given
author can write many books, and a given book can
have multiple authors. This is a many-to-many
relationship scenario where you have to choose
between Arrays, Parse Relations, or creating your own
Join Table.
https://docs.parseplatform.org/android/guide/#users 119/171
7/26/22, 5:14 PM Android Developers Guide | Parse
📋
// let’s say we have a few objects representing
Author objects
ParseObject authorOne =
ParseObject authorTwo =
ParseObject authorThree =
https://docs.parseplatform.org/android/guide/#users 120/171
7/26/22, 5:14 PM Android Developers Guide | Parse
// create a relation based on the authors key
ParseRelation relation =
book.getRelation("authors");
https://docs.parseplatform.org/android/guide/#users 121/171
7/26/22, 5:14 PM Android Developers Guide | Parse
}
});
It’s also pretty easy to find all the users that are
following the current user by querying on the to key:
}
});
USING AN ARRAY
https://docs.parseplatform.org/android/guide/#users 122/171
7/26/22, 5:14 PM Android Developers Guide | Parse
ArrayList<ParseObject> authorList = 📋
book.getList("authors");
https://docs.parseplatform.org/android/guide/#users 123/171
7/26/22, 5:14 PM Android Developers Guide | Parse
}
});
One-to-One
In Parse, a one-to-one relationship is great for
situations where you need to split one object into two
objects. These situations should be rare, but two
examples include:
https://docs.parseplatform.org/android/guide/#users 124/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Want to contribute to this doc? Edit this section.
Handling Errors
Many of the methods on ParseObject , including
save() , delete() , and get() will throw a
ParseException on an invalid request, such as deleting
or editing an object that no longer exists in the
database, or when there is a network failure preventing
communication with your Parse Server. You will need to
catch and deal with these exceptions.
Security
As your app development progresses, you will want to
use Parse’s security features in order to safeguard data.
This document explains the ways in which you can
secure your apps.
https://docs.parseplatform.org/android/guide/#users 125/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Class-Level Permissions
The second level of security is at the schema and data
level. Enforcing security measures at this level will
restrict how and when client applications can access
and create data on Parse. When you first begin
developing your Parse application, all of the defaults are
set so that you can be a more productive developer. For
example:
https://docs.parseplatform.org/android/guide/#users 126/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Once you are confident that you have the right classes
and relationships between classes in your app, you
should begin to lock it down by doing the following:
https://docs.parseplatform.org/android/guide/#users 127/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Read:
Write:
https://docs.parseplatform.org/android/guide/#users 128/171
7/26/22, 5:14 PM Android Developers Guide | Parse
https://docs.parseplatform.org/android/guide/#users 129/171
7/26/22, 5:14 PM Android Developers Guide | Parse
ParseUser.getCurrentUser().put("privateData",
privateData);
https://docs.parseplatform.org/android/guide/#users 130/171
7/26/22, 5:14 PM Android Developers Guide | Parse
https://docs.parseplatform.org/android/guide/#users 131/171
7/26/22, 5:14 PM Android Developers Guide | Parse
{ 📋
"*": { "read":true },
"aSaMpLeUsErId": { "read" :true, "write":
true }
}
{ 📋
"role:RoleName": { "read": true },
"aSaMpLeUsErId": { "read": true, "write":
true }
}
POINTER PERMISSIONS
https://docs.parseplatform.org/android/guide/#users 132/171
7/26/22, 5:14 PM Android Developers Guide | Parse
{ 📋
"<SENDER_USER_ID>": {
"read": true,
"write": true
},
"<RECEIVER_USER_ID>": {
"read": true
}
}
https://docs.parseplatform.org/android/guide/#users 133/171
7/26/22, 5:14 PM Android Developers Guide | Parse
// POST http://my-parse- 📋
server.com/schemas/Announcement
// Set the X-Parse-Application-Id and X-Parse-
Master-Key header
// body:
{
classLevelPermissions:
{
"find": {
"requiresAuthentication": true,
"role:admin": true
},
"get": {
"requiresAuthentication": true,
"role:admin": true
},
"create": { "role:admin": true },
"update": { "role:admin": true },
"delete": { "role:admin": true }
}
}
Effects:
You may expect this will allow both user1 and user2
to Get photoObject , but because the CLP layer of
authentication and the ACL layer are both in effect at
all times, it actually makes it so neither user1 nor
user2 can Get photoObject . If user1 tries to Get
photoObject , it will get through the CLP layer of
authentication, but then will be rejected because it
does not pass the ACL layer. In the same way, if user2
tries to Get photoObject , it will also be rejected at the
CLP layer of authentication.
https://docs.parseplatform.org/android/guide/#users 135/171
7/26/22, 5:14 PM Android Developers Guide | Parse
_User _Installation
normal ignores CLP, but
Get behaviour [1, not ACL
2, 3]
Find normal master key only
behavior [3] [6]
Create normal ignores CLP
behavior [4]
Update normal ignores CLP, but
behavior [5] not ACL [7]
Delete normal master key only
behavior [5] [7]
Add normal normal behavior
Field behavior
https://docs.parseplatform.org/android/guide/#users 136/171
7/26/22, 5:14 PM Android Developers Guide | Parse
https://docs.parseplatform.org/android/guide/#users 137/171
7/26/22, 5:14 PM Android Developers Guide | Parse
https://docs.parseplatform.org/android/guide/#users 138/171
7/26/22, 5:14 PM Android Developers Guide | Parse
https://docs.parseplatform.org/android/guide/#users 139/171
7/26/22, 5:14 PM Android Developers Guide | Parse
https://docs.parseplatform.org/android/guide/#users 140/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Performance
As your app scales, you will want to ensure that it
performs well under increased load and usage. This
document provides guidelines on how you can optimize
your app’s performance. While you can use Parse
Server for quick prototyping and not worry about
performance, you will want to keep our performance
guidelines in mind when you’re initially designing your
app. We strongly advise that you make sure you’ve
followed all suggestions before releasing your app.
https://docs.parseplatform.org/android/guide/#users 141/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Indexing
You are responsible for managing your database and
maintaining indexes when using Parse Server. If your
data is not indexed, every query will have to go through
the the entire data for a class to return a query result.
On the other hand, if your data is indexed appropriately,
the number of documents scanned to return a correct
query result should be low.
Equal to
Contained In
Not equal to
Not contained in
Everything else
ParseQuery<ParseObject> query = 📋
ParseQuery.getQuery("GameScore");
query.whereEqualTo("score", 50);
query.whereContainedIn("playerName",
Arrays.asList("Jonathan Walsh", "Dario Wunsch",
"Shawn Simon"));
query.whereEqualTo("cheatMode", false); 📋
</div>
https://docs.parseplatform.org/android/guide/#users 142/171
7/26/22, 5:14 PM Android Developers Guide | Parse
GeoPoints
Array
Pointer
Date
String
Number
Other
Not Equal To
Not Contained In
Regular Expressions
Ordered By
NOT EQUAL TO
https://docs.parseplatform.org/android/guide/#users 143/171
7/26/22, 5:14 PM Android Developers Guide | Parse
ParseQuery<ParseObject> query = 📋
ParseQuery.getQuery("GameScore");
query.whereNotEqualTo("playerName", "Michael
Yabuti");
query.findInBackground(new
FindCallback<ParseObject>() {
@Override
public void done(List<ParseObject> list,
ParseException e) {
if ( e == null) {
// Retrieved scores successfully
}
}
});
ParseQuery<ParseUser> query = 📋
ParseQuery.getQuery(ParseUser.class);
query.whereNotEqualTo("state", "Invited");
query.whereContainedIn("state", 📋
Arrays.asList("SignedUp", "Verified"));
https://docs.parseplatform.org/android/guide/#users 144/171
7/26/22, 5:14 PM Android Developers Guide | Parse
ParseQuery<ParseObject> query = 📋
ParseQuery.getQuery("GameScore");
// Previously retrieved highScore for Michael
Yabuti
query.whereGreaterThan("score", highScore);
query.findInBackground(new
FindCallback<ParseObject>() {
@Override
public void done(List<ParseObject> list,
ParseException e) {
if (e == null) {
// Retrieved scores successfully
}
}
});
The new query you use depends on your use case. This
may sometimes mean a redesign of your data model.
NOT CONTAINED IN
ParseQuery<ParseUser> query = 📋
ParseQuery.getQuery(ParseUser.class);
query.whereNotContainedIn("state",
Arrays.asList("Invited", "Blocked"));
</div>
query.whereContainedIn("state", 📋
Arrays.asList("SignedUp", "Verified"));
REGULAR EXPRESSIONS
https://docs.parseplatform.org/android/guide/#users 145/171
7/26/22, 5:14 PM Android Developers Guide | Parse
query.whereMatches("playerName", "Michael", 📋
"i");
query.whereContains("playerName", "Michael"); 📋
📋
query.whereStartsWith("playerName", "Michael");
This looks for data that starts with the given string. This
query will use the backend index, so it will be faster
even for large datasets.
https://docs.parseplatform.org/android/guide/#users 146/171
7/26/22, 5:14 PM Android Developers Guide | Parse
query.whereMatches("playerName", "^Michael"); 📋
You can use skip and limit to page through results and
load the data as is needed. The query limit is 100 by
default:
ParseQuery<ParseObject> query = 📋
ParseQuery.getQuery("Place");
query.whereWithinMiles("location",
userGeoPoint, 10.0);
query.findInBackground(new
FindCallback<ParseObject>() {
@Override
public void done(List<ParseObject> list,
ParseException e) {
if (e == null) {
// List of places within 10 miles of a
user's location
}
https://docs.parseplatform.org/android/guide/#users 147/171
7/26/22, 5:14 PM Android Developers Guide | Parse
}
});
ParseQuery<ParseObject> query = 📋
ParseQuery.getQuery("GameScore");
query.selectKeys(Arrays.asList("score",
"playerName"));
query.findInBackground(new
FindCallback<ParseObject>() {
@Override
public void done(List<ParseObject> list,
ParseException e) {
if (e == null) {
// each of results will only have the
selected fields available.
}
}
});
Client-side Caching
For queries run from iOS and Android, you can turn on
query caching. See the iOS and Android guides for
more details. Caching queries will increase your mobile
app’s performance especially in cases where you want
to display cached data while fetching the latest data
from Parse.
https://docs.parseplatform.org/android/guide/#users 148/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Parse.Cloud.define("averageStars", async 📋
(request) => {
const query = new Parse.Query("Review");
query.equalTo("movie",
request.params.movie);
const results = await query.find();
let sum = 0;
for (let i = 0; i < results.length; ++i) {
sum += results[i].get("stars");
}
return sum / results.length;
});
📋
HashMap<String, String> params = new HashMap();
params.put("movie", "The Matrix");
ParseCloud.callFunctionInBackground("averageStars"
params, new FunctionCallback<Float>() {
@Override
public void done(Float aFloat, ParseException
e) {
if (e == null) {
// ratings is 4.5
}
}
});
https://docs.parseplatform.org/android/guide/#users 149/171
7/26/22, 5:14 PM Android Developers Guide | Parse
ParseQuery<ParseObject> query = 📋
ParseQuery.getQuery("Review");
// movieId corresponds to a given movie's id
query.whereEqualTo("movie", movieId);
query.countInBackground(new CountCallback() {
@Override
public void done(int i, ParseException e) {
if ( e == null) {
// Request succeeded
}
}
});
Parse.Cloud.afterSave("Review", 📋
function(request) {
// Get the movie id for the Review
var movieId =
request.object.get("movie").id;
// Query the Movie represented by this review
https://docs.parseplatform.org/android/guide/#users 150/171
7/26/22, 5:14 PM Android Developers Guide | Parse
ParseQuery<ParseObject> query = 📋
ParseQuery.getQuery("Movie");
query.findInBackground(new
FindCallback<ParseObject>() {
@Override
public void done(List<ParseObject> list,
ParseException e) {
if (e == null) {
// Results include the reviews count
field
}
}
});
https://docs.parseplatform.org/android/guide/#users 151/171
7/26/22, 5:14 PM Android Developers Guide | Parse
var _ = require("underscore"); 📋
Parse.Cloud.beforeSave("Post", request => {
var post = request.object;
var toLowerCase = function(w) { return
w.toLowerCase(); };
var words = post.get("text").split(/\b/);
words = _.map(words, toLowerCase);
var stopWords = ["the", "in", "and"]
words = _.filter(words, function(w) {
return w.match(/^\w+$/) && !
_.contains(stopWords, w);
});
var hashtags = post.get("text").match(/#.+?
\b/g);
hashtags = _.map(hashtags, toLowerCase);
post.set("words", words);
post.set("hashtags", hashtags);
});
https://docs.parseplatform.org/android/guide/#users 152/171
7/26/22, 5:14 PM Android Developers Guide | Parse
ParseQuery<ParseObject> query = 📋
ParseQuery.getQuery("Post");
query.whereContainsAll("hashtags",
Arrays.asList("#parse", "#ftw"));
query.findInBackground(new
FindCallback<ParseObject>() {
@Override
public void done(List<ParseObject> list,
ParseException e) {
if (e == null) {
// Request succeeded
}
}
});
Objects
Queries
https://docs.parseplatform.org/android/guide/#users 153/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Push Notifications
Cloud Code
Error Codes
The following is a list of all the error codes that can be
returned by the Parse API. You may also refer to
RFC2616 for a list of http error codes. Make sure to
check the error message for more details.
API Issues
https://docs.parseplatform.org/android/guide/#users 154/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Invalid login
parameters.
UserInvalidLoginParams 101 Check error
message for
more details.
The specified
object or
session
doesn’t exist
or could not
be found. Can
also indicate
that you do
ObjectNotFound 101 not have the
necessary
permissions
to read or
write this
object. Check
error
message for
more details.
There is a
problem with
the
parameters
used to
construct this
query. This
could be an
InvalidQuery 102 invalid field
name or an
invalid field
type for a
specific
constraint.
Check error
message for
more details.
Missing or
invalid
classname.
Classnames
are case-
sensitive.
InvalidClassName 103
They must
start with a
letter, and a-
zA-Z0-9_ are
the only valid
characters.
https://docs.parseplatform.org/android/guide/#users 155/171
7/26/22, 5:14 PM Android Developers Guide | Parse
An
MissingObjectId 104 unspecified
object id.
An invalid
field name.
Keys are
case-
sensitive.
They must
start with a
letter, and a-
InvalidFieldName 105 zA-Z0-9_ are
the only valid
characters.
Some field
names may
be reserved.
Check error
message for
more details.
A malformed
pointer was
used. You
would
InvalidPointer 106
typically only
see this if you
have modified
a client SDK.
Badly formed
JSON was
received
upstream.
This either
indicates you
have done
something
unusual with
modifying
how things
encode to
InvalidJSON 107 JSON, or the
network is
failing badly.
Can also
indicate an
invalid utf-8
string or use
of multiple
form encoded
values. Check
error
message for
more details.
https://docs.parseplatform.org/android/guide/#users 156/171
7/26/22, 5:14 PM Android Developers Guide | Parse
The feature
you tried to
access is only
CommandUnavailable 108 available
internally for
testing
purposes.
The object is
ObjectTooLarge 116
too large.
You have
reached the
ExceededConfigParamsError 116 limit of 100
config
parameters.
An invalid
value was set
for the limit.
InvalidLimitError 117
Check error
message for
more details.
An invalid
value was set
for skip.
InvalidSkipError 118
Check error
message for
more details.
The operation
isn’t allowed
for clients
due to class-
OperationForbidden 119 level
permissions.
Check error
message for
more details.
The result
CacheMiss 120 was not found
in the cache.
https://docs.parseplatform.org/android/guide/#users 157/171
7/26/22, 5:14 PM Android Developers Guide | Parse
An invalid key
was used in a
nested
InvalidNestedKey 121 JSONObject.
Check error
message for
more details.
An invalid
InvalidACL 123 ACL was
provided.
The email
InvalidEmailAddress 125 address was
invalid.
Unique field
was given a
DuplicateValue 137
value that is
already taken.
Role’s name is
InvalidRoleName 139
invalid.
Field value is
ReservedValue 139
reserved.
You have
reached the
quota on the
number of
classes in
ExceededCollectionQuota 140 your app.
Please delete
some classes
if you need to
add a new
class.
Cloud Code
script failed.
Usually points
to a
ScriptFailed 141 JavaScript
error. Check
error
message for
more details.
https://docs.parseplatform.org/android/guide/#users 158/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Cloud
function not
found. Check
that the
specified
Cloud
FunctionNotFound 141
function is
present in
your Cloud
Code script
and has been
deployed.
Background
job not found.
Check that
the specified
JobNotFound 141 job is present
in your Cloud
Code script
and has been
deployed.
Cloud Code
ValidationFailed 142 validation
failed.
Webhook
WebhookError 143
error.
Invalid image
InvalidImageData 150
data.
An unsaved
UnsavedFileError 151
file.
An invalid
InvalidPushTimeError 152 push time
was specified.
The provided
analytics
InvalidEventName 160
event name is
invalid.
Class is not
empty and
ClassNotEmpty 255
cannot be
dropped.
https://docs.parseplatform.org/android/guide/#users 159/171
7/26/22, 5:14 PM Android Developers Guide | Parse
App name is
AppNameInvalid 256
invalid.
The request is
MissingAPIKeyError 902 missing an
API key.
The request is
using an
InvalidAPIKeyError 903
invalid API
key.
A field was
set to an
inconsistent
IncorrectType 111 type. Check
error
message for
more details.
Invalid
channel
name. A
channel name
is either an
empty string
(the
InvalidChannelName 112
broadcast
channel) or
contains only
a-zA-Z0-9_
characters
and starts
with a letter.
Bad
subscription
type. Check
InvalidSubscriptionType 113
error
message for
more details.
The provided
InvalidDeviceToken 114 device token
is invalid.
https://docs.parseplatform.org/android/guide/#users 160/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Push is
misconfigured
in your app.
PushMisconfigured 115
Check error
message for
more details.
Can’t set
channels for a
query-
targeted
push. You can
PushWhereAndChannels 115 fix this by
moving the
channels into
your push
query
constraints.
Can’t set
device type
for a query-
targeted
push. You can
fix this by
PushWhereAndType 115
incorporating
the device
type
constraints
into your
push query.
Push is
PushMissingData 115 missing a
‘data’ field.
Non-query
push is
missing a
‘channels’
PushMissingChannels 115
field. Fix by
passing a
‘channels’ or
‘query’ field.
Client-
initiated push
is not
enabled.
ClientPushDisabled 115 Check your
Parse app’s
push
notification
settings.
https://docs.parseplatform.org/android/guide/#users 161/171
7/26/22, 5:14 PM Android Developers Guide | Parse
REST-
initiated push
is not
enabled.
RestPushDisabled 115 Check your
Parse app’s
push
notification
settings.
Client-
initiated push
ClientPushWithURI 115 cannot use
the “uri”
option.
Your push
query or data
payload is too
PushQueryOrPayloadTooLarge 115 large. Check
error
message for
more details.
Invalid
InvalidExpirationError 138 expiration
value.
A push id is
MissingPushIdError 156 missing.
Deprecated.
The device
type field is
MissingDeviceTypeError 157
missing.
Deprecated.
An invalid
filename was
used for Parse
File. A valid file
name contains
InvalidFileName 122
only a-zA-Z0-
9_. characters
and is between
1 and 128
characters.
https://docs.parseplatform.org/android/guide/#users 162/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Missing content
MissingContentType 126
type.
Missing content
MissingContentLength 127
length.
Invalid content
InvalidContentLength 128
length.
File size
exceeds
FileTooLarge 129
maximum
allowed.
Error saving a
FileSaveError 130
file.
Unnamed file
FileDeleteUnnamedError 161 could not be
deleted.
Invalid
InvalidInstallationIdError 132 installation
id.
Invalid
InvalidDeviceTypeError 133 device
type.
Invalid
InvalidChannelsArrayError 134 channels
array value.
Required
MissingRequiredFieldError 135 field is
missing.
An
immutable
ChangedImmutableFieldError 136
field was
changed.
https://docs.parseplatform.org/android/guide/#users 163/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Product
purchase
ReceiptMissing 143
receipt is
missing.
Product
purchase
InvalidPurchaseReceipt 144
receipt is
invalid.
Payment is
PaymentDisabled 145 disabled on
this device.
The
product
InvalidProductIdentifier 146
identifier is
invalid.
The
product is
ProductNotFoundInAppStore 147 not found
in the App
Store.
The Apple
server
InvalidServerResponse 148
response is
not valid.
The
product
fails to
ProductDownloadFilesystemError 149 download
due to file
system
error.
The
username
UsernameMissing 200
is missing
or empty.
https://docs.parseplatform.org/android/guide/#users 164/171
7/26/22, 5:14 PM Android Developers Guide | Parse
The
password
PasswordMissing 201
is missing
or empty.
The
username
UsernameTaken 202 has already
been
taken.
Email has
UserEmailTaken 203 already
been used.
The email
is missing,
UserEmailMissing 204 and must
be
specified.
A user with
the
UserWithEmailNotFound 205 specified
email was
not found.
A user
object
without a
SessionMissing 206 valid
session
could not
be altered.
A user can
only be
MustCreateUserThroughSignup 207 created
through
signup.
An account
being
linked is
AccountAlreadyLinked 208 already
linked to
another
user.
https://docs.parseplatform.org/android/guide/#users 165/171
7/26/22, 5:14 PM Android Developers Guide | Parse
The
device’s
session
token is no
longer
InvalidSessionToken 209 valid. The
application
should ask
the user to
log in
again.
A user cannot
be linked to an
account
LinkedIdMissing 250 because that
account’s id
could not be
found.
A user with a
linked (e.g.
Facebook or
Twitter)
InvalidLinkedSession 251 account has an
invalid session.
Check error
message for
more details.
Anonymous id is
BadAnonymousID 251 not a valid
lowercase UUID.
The supplied
Facebook
FacebookBadToken 251 session token is
expired or
invalid.
A user with a
linked Facebook
FacebookBadID 251
account has an
invalid session.
https://docs.parseplatform.org/android/guide/#users 166/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Unacceptable
FacebookWrongAppID 251 Facebook
application id.
Twitter
credential
TwitterVerificationFailed 251
verification
failed.
Submitted
Twitter id does
not match the id
TwitterWrongID 251
associated with
the submitted
access token.
Submitted
Twitter handle
does not match
TwitterWrongScreenName 251 the handle
associated with
the submitted
access token.
Twitter
credentials
could not be
TwitterConnectFailure 251 verified due to
problems
accessing the
Twitter API.
A service being
linked (e.g.
Facebook or
Twitter) is
UnsupportedService 252
unsupported.
Check error
message for
more details.
Authentication
by username
and password is
not supported
for this
UsernameSigninDisabled 252
application.
Check your
Parse app’s
authentication
settings.
https://docs.parseplatform.org/android/guide/#users 167/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Anonymous
users are not
supported for
this application.
AnonymousSigninDisabled 252
Check your
Parse app’s
authentication
settings.
Authentication
by Facebook is
not supported
for this
FacebookSigninDisabled 252 application.
Check your
Parse app’s
authentication
settings.
Authentication
by Twitter is not
supported for
this application.
TwitterSigninDisabled 252
Check your
Parse app’s
authentication
settings.
An invalid
authData value
was passed.
InvalidAuthDataError 253
Check error
message for
more details.
Linking to an
external
account not
supported yet
LinkingNotSupportedError 999
with
signup_or_login.
Use update
instead.
Client-only errors
https://docs.parseplatform.org/android/guide/#users 168/171
7/26/22, 5:14 PM Android Developers Guide | Parse
Operational issues
Other issues
https://docs.parseplatform.org/android/guide/#users 169/171
7/26/22, 5:14 PM Android Developers Guide | Parse
An unknown error
or an error
OtherCause -1
unrelated to Parse
occurred.
Internal server
error. No
InternalServerError 1
information
available.
The service is
ServiceUnavailable 2 currently
unavailable.
https://docs.parseplatform.org/android/guide/#users 170/171
7/26/22, 5:14 PM Android Developers Guide | Parse
https://docs.parseplatform.org/android/guide/#users 171/171