Android Retrofit 响应中出现 NullPointerException
Android NullPointerException in Retrofit response
在我的 activity 中,我有多个 Retrofit 服务操作,这些服务依赖于相同的 Retrofit Callback 方法。当一个服务试图在同一时间回调被其他服务使用时,这些会导致空指针,如何解决这个问题?
我一直在为我的网络服务调用使用改造。它在模拟器中运行良好,但当我使用真实设备时它崩溃并得到错误日志:
java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.Object java.util.List.get(int)' on a null object reference
at com.itmam.info.jadara.Notifications.Notifications_Items_Adapter.onResponse(Notifications_Items_Adapter.java:309)
at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall.run(ExecutorCallAdapterFactory.java:70)
at android.os.Handler.handleCallback(Handler.java:888)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:213)
at android.app.ActivityThread.main(ActivityThread.java:8147)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1101)
这是我的 Retrofit 客户端 class:
public class RetrofitGeneral {
private static Retrofit retrofit;
private static final String BASE_URL = "My_URL";
public static Retrofit getRetrofitInstance() {
if (retrofit == null) {
retrofit = new retrofit2.Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
这是我的改造服务界面:
public interface getClientDetails {
@FormUrlEncoded
@POST("WebService.asmx/SelectClientById")
Call<List<ClientDetails>> getClientdetails(
@Field("ClientID") int ClientID,
@Field("Token") String Token,
@Field("CurrentEmployeeID") int CurrentEmployeeID
);
}
这样我就从我的适配器 onBindViewHolder 调用 Retrofit 服务,多次调用改造:
@Override
public void onBindViewHolder(Notifications_Items_Adapter.Notifications_Holder holder, int position) {
myHolder = holder;
holderList.add(holder);
getTaskId(position);
getTaskDetails(taskID);
}
这是我改造后的回调方法:
private void getTaskDetails(int taskID){
getTaskDetails getTaskDetails=RetrofitGeneral.getRetrofitInstance().create(getTaskDetails.class);
Call<List<Task>> listCall=getTaskDetails.getDetails(taskID,Log_in.getToken(),Log_in.CurrentEmployeeID);
listCall.enqueue(new Callback<List<Task>>(){
@Override
public void onResponse(Call<List<Task>> call, Response<List<Task>> response) {
task = response.body().get(0); // Error here after the second call.
tasksList.add(task);
}
@Override
public void onFailure(Call<List<Task>> call, Throwable t) {
}
});
}
请帮忙:)
错误是因为这一行
Toast.makeText(context, "Something went wrong...Please try later!", Toast.LENGTH_SHORT).show();
listCall.enqueue 在后台线程上进行网络调用,您无法从后台线程显示 toast,您必须使用主线程来显示 toast。
你可以使用
runOnUiThread(new Runnable() {
Toast.makeText(context, "Something went wrong...Please try later!",Toast.LENGTH_SHORT).show();
}
修复错误。
要了解您的呼叫失败的原因,您可以打印堆栈跟踪来弄清楚
@Override
public void onFailure(Call<List<Task>> call, Throwable t) {
t.printStackTrace();
runOnUiThread(new Runnable() {
Toast.makeText(context, "Something went wrong...Please try later!",Toast.LENGTH_SHORT).show();
}
}
public void onResponse(Call<SalaryListModel> call, Response<SalaryListModel>
response) {
if (response.isSuccessful()) {
Log.e(TAG, "onResponse: calling");
if (response.body().getStatus_code() == 200) {
Log.e(TAG, "onResponse: calling 200");
}
} else {
Log.e(TAG, "onResponse: else--");
if (response.code() == 500) {
Log.e(TAG, "onResponse: 500");
//and if you want to parse your error body try this
/*
try {
Gson gson = new Gson();
YourErrorClass error = gson.fromJson(response.errorBody().charStream(), YourErrorClass.class);
} catch (Exception e) {
Log.e(TAG, "onResponse error: " + e.getMessage());
}*/
} else if (response.code() == 406) {
Log.e(TAG, "onResponse: 406");
} else {
Log.e(TAG, "onResponse: esle");
}
}
}
问题已通过使用 Retrofit Synchronous 解决:
UserService service = ServiceGenerator.createService(UserService.class);
// 1. Calling '/api/users/2' - synchronously
Call<UserApiResponse> callSync = service.getUser(2);
try
{
Response<UserApiResponse> response = callSync.execute();
UserApiResponse apiResponse = response.body();
//API response
System.out.println(apiResponse);
}
catch (Exception ex)
{
ex.printStackTrace();
}
在我的 activity 中,我有多个 Retrofit 服务操作,这些服务依赖于相同的 Retrofit Callback 方法。当一个服务试图在同一时间回调被其他服务使用时,这些会导致空指针,如何解决这个问题?
我一直在为我的网络服务调用使用改造。它在模拟器中运行良好,但当我使用真实设备时它崩溃并得到错误日志:
java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.Object java.util.List.get(int)' on a null object reference
at com.itmam.info.jadara.Notifications.Notifications_Items_Adapter.onResponse(Notifications_Items_Adapter.java:309)
at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall.run(ExecutorCallAdapterFactory.java:70)
at android.os.Handler.handleCallback(Handler.java:888)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:213)
at android.app.ActivityThread.main(ActivityThread.java:8147)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1101)
这是我的 Retrofit 客户端 class:
public class RetrofitGeneral {
private static Retrofit retrofit;
private static final String BASE_URL = "My_URL";
public static Retrofit getRetrofitInstance() {
if (retrofit == null) {
retrofit = new retrofit2.Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
这是我的改造服务界面:
public interface getClientDetails {
@FormUrlEncoded
@POST("WebService.asmx/SelectClientById")
Call<List<ClientDetails>> getClientdetails(
@Field("ClientID") int ClientID,
@Field("Token") String Token,
@Field("CurrentEmployeeID") int CurrentEmployeeID
);
}
这样我就从我的适配器 onBindViewHolder 调用 Retrofit 服务,多次调用改造:
@Override
public void onBindViewHolder(Notifications_Items_Adapter.Notifications_Holder holder, int position) {
myHolder = holder;
holderList.add(holder);
getTaskId(position);
getTaskDetails(taskID);
}
这是我改造后的回调方法:
private void getTaskDetails(int taskID){
getTaskDetails getTaskDetails=RetrofitGeneral.getRetrofitInstance().create(getTaskDetails.class);
Call<List<Task>> listCall=getTaskDetails.getDetails(taskID,Log_in.getToken(),Log_in.CurrentEmployeeID);
listCall.enqueue(new Callback<List<Task>>(){
@Override
public void onResponse(Call<List<Task>> call, Response<List<Task>> response) {
task = response.body().get(0); // Error here after the second call.
tasksList.add(task);
}
@Override
public void onFailure(Call<List<Task>> call, Throwable t) {
}
});
}
请帮忙:)
错误是因为这一行
Toast.makeText(context, "Something went wrong...Please try later!", Toast.LENGTH_SHORT).show();
listCall.enqueue 在后台线程上进行网络调用,您无法从后台线程显示 toast,您必须使用主线程来显示 toast。
你可以使用
runOnUiThread(new Runnable() {
Toast.makeText(context, "Something went wrong...Please try later!",Toast.LENGTH_SHORT).show();
}
修复错误。
要了解您的呼叫失败的原因,您可以打印堆栈跟踪来弄清楚
@Override
public void onFailure(Call<List<Task>> call, Throwable t) {
t.printStackTrace();
runOnUiThread(new Runnable() {
Toast.makeText(context, "Something went wrong...Please try later!",Toast.LENGTH_SHORT).show();
}
}
public void onResponse(Call<SalaryListModel> call, Response<SalaryListModel>
response) {
if (response.isSuccessful()) {
Log.e(TAG, "onResponse: calling");
if (response.body().getStatus_code() == 200) {
Log.e(TAG, "onResponse: calling 200");
}
} else {
Log.e(TAG, "onResponse: else--");
if (response.code() == 500) {
Log.e(TAG, "onResponse: 500");
//and if you want to parse your error body try this
/*
try {
Gson gson = new Gson();
YourErrorClass error = gson.fromJson(response.errorBody().charStream(), YourErrorClass.class);
} catch (Exception e) {
Log.e(TAG, "onResponse error: " + e.getMessage());
}*/
} else if (response.code() == 406) {
Log.e(TAG, "onResponse: 406");
} else {
Log.e(TAG, "onResponse: esle");
}
}
}
问题已通过使用 Retrofit Synchronous 解决:
UserService service = ServiceGenerator.createService(UserService.class);
// 1. Calling '/api/users/2' - synchronously
Call<UserApiResponse> callSync = service.getUser(2);
try
{
Response<UserApiResponse> response = callSync.execute();
UserApiResponse apiResponse = response.body();
//API response
System.out.println(apiResponse);
}
catch (Exception ex)
{
ex.printStackTrace();
}