从后台线程上的 OkHttp3 API 调用获取空指针
Getting null pointers from OkHttp3 API call on background thread
我正在开发一个使用网络服务的移动应用程序。我正在使用 MVP 模式。
有时,我在调试时得到响应,有时我得到一个空指针,表明在我尝试访问调用结果之前后台线程尚未完成调用处理。
我该如何解决这个问题?调用 API 的代码运行良好,但看起来时间是这里的问题。
Login Interactor Class code
public class LoginInteractorImpl implements LoginInteractor {
private static final String TAG = LoginInteractorImpl.class.getName();
private Handler mHandler;
private HttpResponseResult httpResponseResult = null;
private Gson mGson;
private OkHttpRequestUtil okHttpRequestUtil = null;
@Override
public void login(final String username, final String password, final OnLoginFinishedListener listener, final LoginView mLoginView) {
mGson = new Gson();
mHandler = new Handler(Looper.getMainLooper());
mHandler.post(new Runnable() {
@Override
public void run() {
if (TextUtils.isEmpty(username)) {
listener.onUsernameError();
return;
}
if (TextUtils.isEmpty(password)) {
listener.onPasswordError();
return;
}
}
});
String postBody = mGson.toJson(new LoginRequestDTO(username, password));
okHttpRequestUtil = new OkHttpRequestUtil();
String url = Configuration.BASE_URL.concat(Configuration.FEED_LOGIN_URL);
MediaType jsonMediaType = Configuration.JSON_MEDIA_TYPE;
httpResponseResult = okHttpRequestUtil.DoPost(null, postBody, (Activity) mLoginView, listener, url, jsonMediaType);
try {
TransformJsonResponseToPojo(httpResponseResult, (Activity)mLoginView);
} catch (IOException e) {
e.printStackTrace();
}
}
}
The DoPost Method of the OkHttpRequestUtil Class.
public class OkHttpRequestUtil {
public static final String TAG = OkHttpRequestUtil.class.getName();
OkHttpClient mClient = null;
HttpResponseResult httpResponseResult = null;
private Handler mHandler;
public HttpResponseResult DoPost(final Map<String, String> headers, String postBody, Context context, final LoginInteractor.OnLoginFinishedListener listener, String url, MediaType jsonMediaType) {
HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();
Request request = null;
String processedUrl = urlBuilder.build().toString();
RequestBody body = RequestBody.create(jsonMediaType, postBody);
mHandler = new Handler(Looper.getMainLooper());
if (headers != null) {
Headers headerBuild = Headers.of(headers);
request = new Request.Builder()
.headers(headerBuild)
.url(processedUrl)
.post(body)
.build();
}
else
{
request = new Request.Builder()
.url(processedUrl)
.post(body)
.build();
}
try {
mClient = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.sslSocketFactory(CustomTrust.getPinnedCertSslSocketFactory(context), (X509TrustManager) CustomTrust.getTrustManagerFactory(context).getTrustManagers()[0])
.build();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
}
mClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
call.cancel();
e.printStackTrace();
}
@Override
public void onResponse(Call call, final Response response) throws IOException {
// ... check for failure using `isSuccessful` before proceeding
if (!response.isSuccessful()) {
Log.i(TAG, response.toString());
mHandler.post(new Runnable() {
@Override
public void run() {
listener.onPasswordError();
try {
throw new IOException("Unexpected code " + response);
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
// Populate the HttpResponseResult
httpResponseResult = new HttpResponseResult();
httpResponseResult.setCode(String.valueOf(response.code()));
httpResponseResult.setMessage(response.message());
httpResponseResult.setBodyString(response.body().string());
Headers okHttpResponseHeaders = response.headers();
Map<String, String> responseHeadersTemp = new HashMap<String, String>();
for(int i = 0; i < okHttpResponseHeaders.size(); i++)
{
responseHeadersTemp.put(okHttpResponseHeaders.name(i), okHttpResponseHeaders.value(i));
}
httpResponseResult.setHeaders(responseHeadersTemp);
listener.onSuccess();
}
});
return httpResponseResult;
}
}
基本上,您的代码就像您的 return 语句发生在此入队回调完成之前一样
mClient.newCall(request).enqueue
使 HTTP 响应为空,是的。
一个解决方案是让 DoPost
return 什么都没有(请不要将您的方法名称大写)。让方法类型为 void
。
通过参数将 onResponse
的结果传回给 listener.onSuccess(responseData);
并且您可以立即解析响应,无需复制回包含 headers 和所有
的整个 HTTP 响应
我正在开发一个使用网络服务的移动应用程序。我正在使用 MVP 模式。
有时,我在调试时得到响应,有时我得到一个空指针,表明在我尝试访问调用结果之前后台线程尚未完成调用处理。
我该如何解决这个问题?调用 API 的代码运行良好,但看起来时间是这里的问题。
Login Interactor Class code
public class LoginInteractorImpl implements LoginInteractor {
private static final String TAG = LoginInteractorImpl.class.getName();
private Handler mHandler;
private HttpResponseResult httpResponseResult = null;
private Gson mGson;
private OkHttpRequestUtil okHttpRequestUtil = null;
@Override
public void login(final String username, final String password, final OnLoginFinishedListener listener, final LoginView mLoginView) {
mGson = new Gson();
mHandler = new Handler(Looper.getMainLooper());
mHandler.post(new Runnable() {
@Override
public void run() {
if (TextUtils.isEmpty(username)) {
listener.onUsernameError();
return;
}
if (TextUtils.isEmpty(password)) {
listener.onPasswordError();
return;
}
}
});
String postBody = mGson.toJson(new LoginRequestDTO(username, password));
okHttpRequestUtil = new OkHttpRequestUtil();
String url = Configuration.BASE_URL.concat(Configuration.FEED_LOGIN_URL);
MediaType jsonMediaType = Configuration.JSON_MEDIA_TYPE;
httpResponseResult = okHttpRequestUtil.DoPost(null, postBody, (Activity) mLoginView, listener, url, jsonMediaType);
try {
TransformJsonResponseToPojo(httpResponseResult, (Activity)mLoginView);
} catch (IOException e) {
e.printStackTrace();
}
}
}
The DoPost Method of the OkHttpRequestUtil Class.
public class OkHttpRequestUtil {
public static final String TAG = OkHttpRequestUtil.class.getName();
OkHttpClient mClient = null;
HttpResponseResult httpResponseResult = null;
private Handler mHandler;
public HttpResponseResult DoPost(final Map<String, String> headers, String postBody, Context context, final LoginInteractor.OnLoginFinishedListener listener, String url, MediaType jsonMediaType) {
HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();
Request request = null;
String processedUrl = urlBuilder.build().toString();
RequestBody body = RequestBody.create(jsonMediaType, postBody);
mHandler = new Handler(Looper.getMainLooper());
if (headers != null) {
Headers headerBuild = Headers.of(headers);
request = new Request.Builder()
.headers(headerBuild)
.url(processedUrl)
.post(body)
.build();
}
else
{
request = new Request.Builder()
.url(processedUrl)
.post(body)
.build();
}
try {
mClient = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.sslSocketFactory(CustomTrust.getPinnedCertSslSocketFactory(context), (X509TrustManager) CustomTrust.getTrustManagerFactory(context).getTrustManagers()[0])
.build();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
}
mClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
call.cancel();
e.printStackTrace();
}
@Override
public void onResponse(Call call, final Response response) throws IOException {
// ... check for failure using `isSuccessful` before proceeding
if (!response.isSuccessful()) {
Log.i(TAG, response.toString());
mHandler.post(new Runnable() {
@Override
public void run() {
listener.onPasswordError();
try {
throw new IOException("Unexpected code " + response);
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
// Populate the HttpResponseResult
httpResponseResult = new HttpResponseResult();
httpResponseResult.setCode(String.valueOf(response.code()));
httpResponseResult.setMessage(response.message());
httpResponseResult.setBodyString(response.body().string());
Headers okHttpResponseHeaders = response.headers();
Map<String, String> responseHeadersTemp = new HashMap<String, String>();
for(int i = 0; i < okHttpResponseHeaders.size(); i++)
{
responseHeadersTemp.put(okHttpResponseHeaders.name(i), okHttpResponseHeaders.value(i));
}
httpResponseResult.setHeaders(responseHeadersTemp);
listener.onSuccess();
}
});
return httpResponseResult;
}
}
基本上,您的代码就像您的 return 语句发生在此入队回调完成之前一样
mClient.newCall(request).enqueue
使 HTTP 响应为空,是的。
一个解决方案是让 DoPost
return 什么都没有(请不要将您的方法名称大写)。让方法类型为 void
。
通过参数将 onResponse
的结果传回给 listener.onSuccess(responseData);
并且您可以立即解析响应,无需复制回包含 headers 和所有
的整个 HTTP 响应