-
问题分析
- 当在 Activity 中使用
OkHttpClient.newCall(request).enqueue()
进行网络请求时,由于这是一个异步请求,它不会阻塞当前线程,所以如果在请求还未完成时就尝试获取返回值,就会得到null
。
- 当在 Activity 中使用
-
解决方案 - 使用回调接口
- 定义接口:
- 首先,在 Activity 类中定义一个接口来处理网络请求的结果。例如:
- 定义接口:
public interface NetworkCallback {
void onSuccess(String response);
void onFailure(Exception e);
}
- 在 Activity 中进行网络请求并使用接口处理结果:
- 假设在
MainActivity
中进行网络请求,示例代码如下:
- 假设在
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://example.com/api/data")
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
// 在主线程中更新UI,需要使用runOnUiThread方法
runOnUiThread(() -> {
// 假设存在一个TextView来显示错误信息
// TextView errorTextView = findViewById(R.id.error_text_view);
// errorTextView.setText("网络请求失败:" + e.getMessage());
((NetworkCallback) MainActivity.this).onFailure(e);
});
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
final String responseData = response.body().string();
// 在主线程中更新UI,需要使用runOnUiThread方法
runOnUiThread(() -> {
// 假设存在一个TextView来显示返回的数据
// TextView resultTextView = findViewById(R.id.result_text_view);
// resultTextView.setText("网络请求成功,返回数据:" + responseData);
((NetworkCallback) MainActivity.this).onSuccess(responseData);
});
} else {
final String errorMessage = "网络请求失败,状态码:" + response.code();
// 在主线程中更新UI,需要使用runOnUiThread方法
runOnUiThread(() -> {
// 假设存在一个TextView来显示错误信息
// TextView errorTextView = findViewById(R.id.error_text_view);
// errorTextView.setText(errorMessage);
((NetworkCallback) MainActivity.this).onFailure(new IOException(errorMessage));
});
}
}
});
}
}
在上述代码中:
- 首先创建了
OkHttpClient
和Request
对象,然后使用client.newCall(request).enqueue()
进行异步网络请求。 - 在
onFailure
方法中,当网络请求失败时,通过runOnUiThread
方法在主线程中更新 UI 或者调用定义的接口方法onFailure
来通知调用者请求失败。 - 在
onResponse
方法中,当网络请求成功且响应状态码为成功时,获取响应体数据并转换为字符串,然后同样通过runOnUiThread
方法在主线程中更新 UI 或者调用接口方法onSuccess
来通知调用者请求成功并传递返回的数据。如果响应状态码不是成功状态,则按照请求失败的方式处理,传递相应的错误信息。
- 更好的实践 - 抽象网络请求层
- 为了使代码更加模块化和易于维护,可以将网络请求部分封装到一个单独的类中。例如,创建一个
NetworkManager
类:
- 为了使代码更加模块化和易于维护,可以将网络请求部分封装到一个单独的类中。例如,创建一个
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;
public class NetworkManager {
private OkHttpClient client;
public NetworkManager() {
client = new OkHttpClient();
}
public void sendRequest(Request request, final NetworkCallback callback) {
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
callback.onFailure(e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
final String responseData = response.body().string();
callback.onSuccess(responseData);
} else {
final String errorMessage = "网络请求失败,状态码:" + response.code();
callback.onFailure(new IOException(errorMessage));
}
}
});
}
}
- 然后在
MainActivity
中使用这个NetworkManager
类:
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import okhttp3.Request;
import okhttp3.Request.Builder;
public class MainActivity extends AppCompatActivity implements NetworkCallback {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
NetworkManager networkManager = new NetworkManager();
Request request = new Builder()
.url("https://example.com/api/data")
.build();
networkManager.sendRequest(request, this);
}
@Override
public void onSuccess(String response) {
// 在这里处理网络请求成功后的逻辑,如更新UI
// 假设存在一个TextView来显示返回的数据
// TextView resultTextView = findViewById(R.id.result_text_view);
// resultTextView.setText("网络请求成功,返回数据:" + response);
}
@Override
public void onFailure(Exception e) {
// 在这里处理网络请求失败后的逻辑,如显示错误信息
// 假设存在一个TextView来显示错误信息
// TextView errorTextView = findViewById(R.id.error_text_view);
// errorTextView.setText("网络请求失败:" + e.getMessage());
}
}
通过这种方式,将网络请求的逻辑封装在NetworkManager
类中,MainActivity
只需要实现NetworkCallback
接口并处理请求成功和失败的情况,使代码结构更加清晰,易于维护和扩展。同时,避免了在 Activity 中直接处理异步请求带来的返回值获取问题,通过接口回调的方式在请求完成后接收结果。