code: public void registerDeviceAsync(Device device, RegisterCallback callback) {
          RestCallback<Device> cb;
          if (callback == null) {
              cb = RegisterCallback.getEmptyCallback().getInnerCallback(this);
          } else {
              cb = callback.getInnerCallback(this);
          }
  
          // If device ID is set and not explicitly asking for a different one, return current ID.
          boolean alreadySet = this.deviceId != null;
          if (alreadySet && (device == null || this.deviceId.equals(device.getId()))) {
              cb.completed(device, null);
              return;
          }
  
          // Make sure to unset before attempting, so as not to reuse old ID if it fails.
          this.deviceId = null;
  
          final DeviceService.Add req;
          try {
              req = prepareDeviceRequest(device);
          } catch (ApiException e) {
              IobeamException ie = new IobeamException(e);
              if (callback == null) {
                  throw ie;
              } else {
                  cb.failed(ie, null);
                  return;
              }
          }
          req.executeAsync(cb);
      }
docs: Registers a device asynchronously with parameters of the provided {@link Device}. This will
  not block the calling thread. If successful, the device ID of this client will be set (either
  to the id provided, or if not provided, a randomly generated one). Any provided callback will
  be run on a background thread. If the client already has a device ID set, registration will
  only happen for a non-null device. Otherwise, the callback will be called with a {@link
  Device} with the current ID.
  
  @param device   Desired device parameters to register.
  @param callback Callback for result of the registration.
  @throws ApiException Thrown if the iobeam client is not initialized.