Android 使用内部库接口回调将同步请求转换为异步

Android convert Synchronous request to asynchronous using internal library Interface Callback

我在我的应用程序中使用 .aar 库。 它有一个网络委托接口,我需要覆盖它。

ApiResponse executeApiCall(String url, HTTPMethod method, String params)

我正在使用 Retrofit 进行网络调用。我需要将同步调用转换为异步使用。

@Override
public ApiResponse executeApiCall(String url, HTTPMethod method, String params) {
    ApiResponse apiResponse;

    try {
        // Synchronous Call
        Call<String> call = RestClient.get().getStringResponse(url, method, params);
        Response<String> response = call.execute();
        apiResponse = new ApiResponse(response.code(), response.body());
        
    } catch (Exception e) {
        apiResponse = new ApiResponse();
    }

    return apiResponse;
}

现在我被困在如何在我必须覆盖的网络接口中使用异步调用。

@Override
public ApiResponse executeApiCall(String url, HTTPMethod method, String params) {
    ApiResponse apiResponse;

    // Asynchronous Call
    Call<String> call = RestClient.get().getStringResponse(url, method, params);
    call.enqueue(new Callback<String>() {
        @Override
        public void onResponse(@NotNull Call<String> call, @NotNull Response<String> response) {
            if (response.isSuccessful()) {
                apiResponse = new ApiResponse(response.code(), response.body());
            }
        }

        @Override
        public void onFailure(@NotNull Call<String> call, @NotNull Throwable t) {
            apiResponse = new ApiResponse();
        }
    });

    return apiResponse;
}

我无法更改网络委托界面。我必须覆盖它,我需要使用改造异步。

非常感谢您的反馈。谢谢大家。

我在另一个堆栈溢出线程上找到了一些代码。以下是您可以如何使用代码来实现您正在寻找的东西。

这是class

public abstract class AsyncRunnable<T> {
    protected abstract void run(AtomicReference<T> notifier);

    protected final void finish(AtomicReference<T> notifier, T result) {
        synchronized (notifier) {
            notifier.set(result);
            notifier.notify();
        }
    }

    public static <T> T wait(AsyncRunnable<T> runnable) {
        final AtomicReference<T> notifier = new AtomicReference<>();

        // run the asynchronous code
        runnable.run(notifier);

        // wait for the asynchronous code to finish
        synchronized (notifier) {
            while (notifier.get() == null) {
                try {
                    notifier.wait();
                } catch (InterruptedException ignore) {}
            }
        }

        // return the result of the asynchronous code
        return notifier.get();
    }
}

你可以这样使用它

  ApiResponse result = AsyncRunnable.wait(new AsyncRunnable<ApiResponse>() {
        @Override
        public void run(final AtomicReference<String> notifier) {
            // here goes your async code, e.g.:
            new Thread(new Runnable() {
                @Override
                public void run() {
                     Call<String> call = 
                     RestClient.get().getStringResponse(url, method, params);
                     call.enqueue(new Callback<String>() {
                        @Override
                        public void onResponse(@NotNull Call<String> call, 
                       
                         @NotNull 
                         Response<String> response) {
                          
                             if (response.isSuccessful()) {
                                 apiResponse = new 
                                              ApiResponse(response.code(), 
                                 response.body());
                                 finish(notifier, apiResponse);
        }
    }

    @Override
    public void onFailure(@NotNull Call<String> call, @NotNull Throwable t) {
         apiResponse = new ApiResponse();
         finish(notifier, apiResponse);
    }
});

                }
            }).start();
        }
    });

我们等待来自回调的响应并通知 AsyncRunnable class。

我觉得你,我遇到了一个类似的问题,一个库需要在 UI 线程上做繁重的工作(非 UI)。是的,听起来像是精神病患者的 lib。协程 runBlocking 是你的朋友。我知道您要求的是 rx-java 解决方案,但无法在这方面击败协程。

/**
 * You can edit, run, and share this code. 
 * play.kotlinlang.org 
 */
    import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking


fun main() {
    
    val apiResponse = executeApiCall()    
    
    println(apiResponse) // prints "response"
    println("goodbye, world!!!")
}

/**
 * Synchronous function that waits for coroutine to finish
 */ 
fun executeApiCall():String {
    
    return runBlocking(Dispatchers.IO){
     
        retrofitCall()
    
    }
  
    
}

/**
 * Method that invokes Retrofit call in the background.
 */ 
suspend fun retrofitCall():String{
    
//  RestClient.get() ...
    return "response"
}


请注意,如果您从 UI 线程调用 executeApiCall,您仍然会阻塞 UI 线程。因此,如果您在 activity 或片段(gradle 依赖项 androidx.lifecycle:lifecycle-runtime-ktx:2.1.0)内,则可能需要 lifecycleScope.launch{executeApiCall() } 之类的东西,否则可能需要 CoroutineScope(Dispatchers.IO).launch { executeApiCall() }