Java
Java projects call the SDK through its built-in Java API (called the "facade" below), with no KSP setup needed. Business types are mostly in the com.deeprespond.im package, and the Java facade is in com.deeprespond.im.java. Java and Kotlin share the same data, sessions, send queue and permission rules; this page only covers how to write it in Java.
| You want to | See |
|---|---|
| Initialize and get the Java facade | Initialization and restore |
| Call async methods (callbacks or CompletableFuture) | Callbacks and futures |
| Subscribe to sign-in, connection and other state | State subscriptions |
| Pass options and duration parameters | Parameters and Duration |
| Translate the Kotlin docs to Java | Java and Kotlin side by side |
Initialization and restore
import android.content.Context;
import com.deeprespond.im.*;
import com.deeprespond.im.java.*;
DRClientOptions options = DRClientOptions.builder("org#app", "https://api.example.com").build();
DRJavaClient im = DRClient.initialize(context, options).java();
im.auth().awaitRestored(new DRCallback<Void>() {
public void onSuccess(Void ignored) {
// 恢复后再根据 im.auth().getCurrentUser() 决定是否登录。
}
public void onError(DRException error) { /* 处理恢复失败 */ }
});Initialize in the app's main process after the user agrees to your privacy policy. Afterward, DRClient.getInstance().java() gets the Java facade for the same client; before initialization, getInstance() throws IllegalStateException.
Callbacks and futures
import com.deeprespond.im.*;
import com.deeprespond.im.java.*;
DRCancellable pending = im.auth().loginWithTicket(ticket, new DRCallback<LoginResult>() {
public void onSuccess(LoginResult result) { /* 默认回调在主线程 */ }
public void onError(DRException error) { /* 按 code 和 reason 判断 */ }
});
// 页面不再需要等待时:pending.cancel();- Every async method can be called two ways: with a callback (returning
DRCancellable), or as...Async()returning aCompletableFuture. - Methods with no return value use
DRCallback<Void>, and the success value isnull. - Callbacks run on the main thread by default;
withExecutorsets whichExecutorruns callbacks and listeners. - Kotlin's optional parameters map to overloads or
Paramsclasses in Java (see below). Go by what your editor suggests rather than guessing from Kotlin's parameter positions. - A
CompletableFuturecompletes on an SDK thread, so switch to the main thread before updating the UI (withExecutoronly affects callbacks and listeners, not futures). Cancel a future withcancel(true).
import com.deeprespond.im.*;
import java.util.concurrent.CompletableFuture;
CompletableFuture<LoginResult> future = im.auth().loginWithTicketAsync(ticket);
future.whenComplete((result, error) -> {
if (error != null) {
// 处理异常;这里不能直接修改 Android View。
} else {
System.out.println(result.getSessionId());
}
});With several optional parameters, use the facade's Params.builder(); for example, querying public groups:
import com.deeprespond.im.java.*;
DRGroupsModule.PublicGroupsParams params = DRGroupsModule.PublicGroupsParams.builder()
.namePrefix("项目")
.limit(20)
.build();
im.groups().publicGroupsAsync(params);DRCancellable.cancel() only stops waiting: messages already in the queue and writes already sent continue under the SDK's rules. To really cancel an upload or download, call the task's own cancel.
State subscriptions
import com.deeprespond.im.java.*;
DRSubscription subscription = im.auth().observeState(state -> {
// 更新登录界面。
});
subscription.close(); // 实际在页面退出时关闭。The facade offers a synchronous getXxx() and a continuous observeXxx() for each piece of state. getXxx() only returns the value at that moment and doesn't update by itself; close subscriptions with close() when you're done. The Java screen in the example app demonstrates restore, subscriptions, diagnostics and async calls.
Parameters and Duration
DRClientOptionsusesbuilder(appKey, apiUrl),DRPushOptionsusesbuilder(credentials), andDRCallOptionsandMediaOptionsusebuilder().- Where Kotlin takes a
Duration, Java uses a milliseconds version, such asuserCacheTtlMillis,retryAfterMillis,OutgoingContent.voice(file, durationMs)andDndChange.On.ofMillis(durationMs).
import com.deeprespond.im.*;
MediaOptions media = MediaOptions.builder()
.preprocess((file, kind, callback) -> callback.onSuccess(file))
.build();preprocessreplaces the SDK's default media processing, and you become responsible for the file being readable and metadata being stripped. The example only shows the syntax; returning the file unchanged doesn't strip any metadata.- In Java,
ticketProvideruses theJavaTicketProvidercallback to pass back the ticket your backend issued.
For what each module does, see its chapter; for full Kotlin signatures, see the API reference.
Java and Kotlin side by side
| Kotlin | Java facade or rule |
|---|---|
| DRClient | DRJavaClient, from client.java() |
| AuthModule, MessagesModule, GroupsModule and so on | DRAuthModule, DRMessagesModule, DRGroupsModule, from im.auth() / messages() / groups() |
| MessageList, LiveList, CallHandle, ChatroomHandle | DRMessageList, DRLiveList, DRCallHandle, DRChatroomHandle |
| StateFlow.value | getXXX() reads synchronously, observeXXX(DRListener) subscribes |
| suspend methods | Callback methods return DRCancellable; Async methods return CompletableFuture |
| Duration parameters | The Java method of the same name takes a Long in milliseconds, such as waitUntilReadyAsync(15000L) |
| CallHandle device extensions | DRJavaCalls static methods, such as switchCameraAsync(handle) and observeAudioEndpoints(handle, listener) |
| Native push controller | DRPush.of(client) returns DRPushController; its suspend calls still go through Kotlin coroutines |
The push controller has no Java callback version. A Java app can add a small piece of Kotlin to handle push permissions and registration (which are suspend functions) and expose its own callbacks to your Java code. The controller has no Async methods, so don't call it as if it did.
Standalone channels
The channel Java facade is DRChannelsModule and DRChannelHandle, again with callback and Async methods; the DRSubscriptions returned by observeCurrent, observeSnapshot and observeTracks must be closed when you're done.
android.os.Handler mainHandler = new android.os.Handler(android.os.Looper.getMainLooper());
java.util.concurrent.Executor mainExecutor = task -> mainHandler.post(task);
DRChannelsModule channels = new DRChannelsModule(
DRClient.getInstance().getChannels(), mainExecutor);
ChannelJoinOptions options = new ChannelJoinOptions(ticket, null, false, false);
channels.join("meeting-demo", options, new DRCallback<DRChannelHandle>() {
public void onSuccess(DRChannelHandle channel) {
// 保存句柄;用户授权后手动启用采集;页面离开时 leave。
}
public void onError(DRException error) { /* 展示错误并允许用户决定下一步 */ }
});In Java, ChannelJoinOptions takes ticket, clientSessionId, microphoneEnabled and cameraEnabled, in that order. API and permission limits are the same as for channels in Kotlin.
