I have saved a persistent anchor (for 365 days) on the cloud. Now, I want to retrieve it. I can do it just fine using the code Google provided in one of its sample projects. However, I want to use Sceneform since I want to do some manipulations afterwards (drawing 3D shapes), that are much easier to do in Sceneform. However, I can't seem to resolve the persistent cloud anchors. All the examples I find online, don't deal with persistent cloud anchors and they only deal with the normal 24 hour cloud anchors.
@RequiresApi(api = VERSION_CODES.N)
protected void onUpdateFrame(FrameTime frameTime) {
Frame frame = arFragment.getArSceneView().getArFrame();
// If there is no frame, just return.
if (frame == null) {
return;
}
if (session == null) {
Log.d(TAG, "setup a session once");
session = arFragment.getArSceneView().getSession();
cloudAnchorManager = new CloudAnchorManager(session);
}
if (resolveListener == null && session != null) {
Log.d(TAG, "setup a resolveListener once");
resolveListener = new MemexViewingActivity.ResolveListener();
// Encourage the user to look at a previously mapped area.
if (cloudAnchorId != null && !gotGoodAnchor && cloudAnchorManager != null) {
Log.d(TAG, "put resolveListener on cloud manager once");
userMessageText.setText(R.string.resolving_processing);
cloudAnchorManager.resolveCloudAnchor(cloudAnchorId, resolveListener);
}
}
if (cloudAnchorManager != null && session != null) {
try {
Frame dummy = session.update();
cloudAnchorManager.onUpdate();
} catch (CameraNotAvailableException e) {
e.printStackTrace();
}
}
}
Is there anything wrong in the above update function that I have written? The CloudAnchorManager class is the same one Google uses in its Persistent Cloud Anchor example. Here, I will put its code too:
package com.memex.eu.helpers;
import android.util.Log;
import com.google.ar.core.Anchor;
import com.google.ar.core.Anchor.CloudAnchorState;
import com.google.ar.core.Session;
import com.google.common.base.Preconditions;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* A helper class to handle all the Cloud Anchors logic, and add a callback-like mechanism on top of
* the existing ARCore API.
*/
public class CloudAnchorManager {
/** Listener for the results of a host operation. */
public interface CloudAnchorListener {
/** This method is invoked when the results of a Cloud Anchor operation are available. */
void onComplete(Anchor anchor);
}
private final Session session;
private final Map<Anchor, CloudAnchorListener> pendingAnchors = new HashMap<>();
public CloudAnchorManager(Session session) {
this.session = Preconditions.checkNotNull(session);
}
/** Hosts an anchor. The {@code listener} will be invoked when the results are available. */
public synchronized void hostCloudAnchor(Anchor anchor, CloudAnchorListener listener) {
Preconditions.checkNotNull(listener, "The listener cannot be null.");
// This is configurable up to 365 days.
Anchor newAnchor = session.hostCloudAnchorWithTtl(anchor, /* ttlDays= */ 365);
pendingAnchors.put(newAnchor, listener);
}
/** Resolves an anchor. The {@code listener} will be invoked when the results are available. */
public synchronized void resolveCloudAnchor(String anchorId, CloudAnchorListener listener) {
Preconditions.checkNotNull(listener, "The listener cannot be null.");
Anchor newAnchor = session.resolveCloudAnchor(anchorId);
pendingAnchors.put(newAnchor, listener);
}
/** Should be called after a {@link Session#update()} call. */
public synchronized void onUpdate() {
Preconditions.checkNotNull(session, "The session cannot be null.");
for (Iterator<Map.Entry<Anchor, CloudAnchorListener>> it = pendingAnchors.entrySet().iterator();
it.hasNext(); ) {
Map.Entry<Anchor, CloudAnchorListener> entry = it.next();
Anchor anchor = entry.getKey();
if (isReturnableState(anchor.getCloudAnchorState())) {
CloudAnchorListener listener = entry.getValue();
listener.onComplete(anchor);
it.remove();
}
}
}
/** Clears any currently registered listeners, so they won't be called again. */
synchronized void clearListeners() {
pendingAnchors.clear();
}
private static boolean isReturnableState(CloudAnchorState cloudState) {
switch (cloudState) {
case NONE:
case TASK_IN_PROGRESS:
return false;
default:
return true;
}
}
}
Also, here is another class I am using (this is also from the Google example project):
/* Listens for a resolved anchor. */
private final class ResolveListener implements CloudAnchorManager.CloudAnchorListener {
@Override
public void onComplete(Anchor resolvedAnchor) {
runOnUiThread(
() -> {
Anchor.CloudAnchorState state = resolvedAnchor.getCloudAnchorState();
if (state.isError()) {
Log.e(TAG, "Error resolving a cloud anchor, state " + state);
userMessageText.setText(getString(R.string.resolving_error, state));
return;
}
Log.e(TAG, "cloud anchor successfully resolved, state " + state);
anchor = resolvedAnchor;
userMessageText.setText(getString(R.string.resolving_success));
gotGoodAnchor = true;
});
}
}
when I run my app, I point the phone's camera at the physical space where I previously put an object but the anchor is never resolved. I think the problem might be in the update function but I can't seem to figure out what.
I guess I wasn't looking at the object properly. Now, it's working. This code is correct.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.