BrettYeager
BrettYeager

Reputation: 61

Saved Games Snapshot initialization (null object reference)

I am trying to use the new Saved Games (Snapshot) API

But I keep getting this error:

java.lang.NullPointerException: Attempt to invoke interface method 'boolean com.google.android.gms.games.snapshot.Snapshot.writeBytes(byte[])' on a null object reference


Here's the code for what I'm trying

Snapshot snapshot = new Snapshot();
snapshot.writeBytes(my_app_state);

// Save the snapshot.
SnapshotMetadataChange metadataChange
        = new SnapshotMetadataChange.Builder()
        .setDescription("Completed %" + (levelscompleted/totallevels) + " of levels.")
        .build();
Games.Snapshots.commitAndClose(getApiClient(), snapshot,
        metadataChange);


I'm trying to figure out how to initialize snapshot because = new Snapshot(); does not work.

Upvotes: 1

Views: 2115

Answers (2)

class
class

Reputation: 8681

The Snapshot API is very specific in how you must do things. The following is the high-level procedure for Snapshot save:

  • Open the snapshot
  • Resolve conflicts
  • Save

The following code is from the Google Play Games Snapshot sample which shows you how to use Snapshots cross-platform across Android and iOS.

First, you must open the snapshot and resolve conflicts on open.

/**
 * Prepares saving Snapshot to the user's synchronized storage, conditionally resolves errors,
 * and stores the Snapshot.
 */
void saveSnapshot() {
    AsyncTask<Void, Void, Snapshots.OpenSnapshotResult> task =
            new AsyncTask<Void, Void, Snapshots.OpenSnapshotResult>() {
                @Override
                protected Snapshots.OpenSnapshotResult doInBackground(Void... params) {
                    Snapshots.OpenSnapshotResult result = Games.Snapshots.open(getApiClient(),
                            currentSaveName, true).await();
                    return result;
                }

                @Override
                protected void onPostExecute(Snapshots.OpenSnapshotResult result) {
                    Snapshot toWrite = processSnapshotOpenResult(result, 0);

                    Log.i(TAG, writeSnapshot(toWrite));
                }
            };

    task.execute();
}

Next, you must handle conflict resolution:

/**
 * Conflict resolution for when Snapshots are opened.
 * @param result The open snapshot result to resolve on open.
 * @return The opened Snapshot on success; otherwise, returns null.
 */
Snapshot processSnapshotOpenResult(Snapshots.OpenSnapshotResult result, int retryCount){
    Snapshot mResolvedSnapshot = null;
    retryCount++;
    int status = result.getStatus().getStatusCode();

    Log.i(TAG, "Save Result status: " + status);

    if (status == GamesStatusCodes.STATUS_OK) {
        return result.getSnapshot();
    } else if (status == GamesStatusCodes.STATUS_SNAPSHOT_CONTENTS_UNAVAILABLE) {
        return result.getSnapshot();
    } else if (status == GamesStatusCodes.STATUS_SNAPSHOT_CONFLICT){
        Snapshot snapshot = result.getSnapshot();
        Snapshot conflictSnapshot = result.getConflictingSnapshot();

        // Resolve between conflicts by selecting the newest of the conflicting snapshots.
        mResolvedSnapshot = snapshot;

        if (snapshot.getMetadata().getLastModifiedTimestamp() <
                conflictSnapshot.getMetadata().getLastModifiedTimestamp()){
            mResolvedSnapshot = conflictSnapshot;
        }

        Snapshots.OpenSnapshotResult resolveResult = Games.Snapshots.resolveConflict(
                getApiClient(), result.getConflictId(), mResolvedSnapshot)
                .await();

        if (retryCount < MAX_SNAPSHOT_RESOLVE_RETRIES){
            return processSnapshotOpenResult(resolveResult, retryCount);
        }else{
            String message = "Could not resolve snapshot conflicts";
            Log.e(TAG, message);
            Toast.makeText(getBaseContext(), message, Toast.LENGTH_LONG);
        }

    }
    // Fail, return null.
    return null;
}

The following code is how this is done in the Google Play Games Snapshots sample app:

/**
 * Generates metadata, takes a screenshot, and performs the write operation for saving a
 * snapshot.
 */
private String writeSnapshot(Snapshot snapshot){
    // Set the data payload for the snapshot.
    snapshot.writeBytes(mSaveGame.toBytes());

    // Save the snapshot.
    SnapshotMetadataChange metadataChange = new SnapshotMetadataChange.Builder()
            .setCoverImage(getScreenShot())
            .setDescription("Modified data at: " + Calendar.getInstance().getTime())
            .build();
    Games.Snapshots.commitAndClose(getApiClient(), snapshot, metadataChange);
    return snapshot.toString();
}

Upvotes: 4

VVB
VVB

Reputation: 7641

I think, instead of creating Snapshot object explicitly. It should get generated in onActivityResult. So you need to handle it in onActivityResult. Then your writeBytes() will perform further operations.

Check documentation, In that loadFromSnapshot() contains

 Snapshot snapshot = result.getSnapshot();

So I think, you are getting null/false response on your onActivityResult. If not then follow same steps given in loadFromSnapshot() documentation.

Upvotes: 0

Related Questions