java - Retrofit2 的 onResponse() 工作不正常
问题描述
我正在尝试从服务器获取数据。我写了网络模型,但有些人建议使用http://www.jsonschema2pojo.org/或http://pojo.sodhanalibrary.com/。我都使用了它们,但问题没有解决。我有授权活动,我可以获得令牌以访问其他数据。因此,在授权后,我会转到 AddressActivity,在那里我应该获取用户数据(姓名、邮政编码等),并且这些数据应该出现在我的活动 recyclerview 上。但它不会发生。不过,我正在获取数据。我在OkHttp 上检查了它。外观问题。我在每个方法和if&else 语句之后都放了 Toast 消息,以检查哪个部分不起作用。所以,我发现问题onResponse(..),因为我在onFailure(..)中收到Log和我的Toast 消息。但是,如果我不授权并尝试获取地址,则 onResponse(..) 的 else 部分将起作用。
IService.kt:
package com.example.ganz.afex.net
import com.example.ganz.afex.models.Address_Network_Model
import com.example.ganz.afex.net.pojo.me.ResponseMe
import com.example.ganz.afex.net.pojo.re_and_log.*
import com.example.ganz.afex.net.pojo.update_password.RequestUpdatePass
import com.example.ganz.afex.net.pojo.update_password.ResponseUpdatePassword
import com.example.ganz.afex.net.pojo.update_profile.RequestUpdateProfile
import com.example.ganz.afex.net.pojo.update_profile.ResponseUpdateProfile
import retrofit2.Call
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.PUT
interface IService {
@POST("authorize")
fun login(@Body login: RequestLogin): Call<ResponseLogin>
@POST("accesstoken")
fun getToken(@Body request: GetAccessTokenRequest): Call<GetAccessTokenResponse>
@GET("me")
fun getMe(): Call<ResponseMe>
@GET("addresses/all")
fun getAllAddresses(): Call<List<Address_Network_Model>>
}
Recyc_Adapter_Addresses:
package com.example.ganz.afex.adapters;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.example.ganz.afex.R;
import com.example.ganz.afex.models.Address_Network_Model;
import java.util.ArrayList;
import java.util.List;
public class Recyc_Adapter_Addresses extends RecyclerView.Adapter<Recyc_Adapter_Addresses.MyViewHolder> {
private Context mContext;
private static final String TAG = Recyc_Adapter_Addresses.class.getSimpleName();
private List<Address_Network_Model> mAddrNetwork;
public Recyc_Adapter_Addresses(Context mContext, List<Address_Network_Model> mAddrNetwork) {
this.mContext = mContext;
this.mAddrNetwork = mAddrNetwork;
}
public Recyc_Adapter_Addresses() {
mAddrNetwork = new ArrayList<>();
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view;
LayoutInflater mInflater = LayoutInflater.from(mContext);
view = mInflater.inflate(R.layout.cardview_addresses, parent, false);
return new MyViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
holder.tv_cust_city_id.setText(mAddrNetwork.get(position).getCityId());
holder.tv_cust_address.setText(mAddrNetwork.get(position).getAddress());
holder.tv_cust_zipcode.setText(mAddrNetwork.get(position).getZipCode());
holder.tv_cust_phone_1.setText(mAddrNetwork.get(position).getPhone());
holder.tv_cust_phone_2.setText(mAddrNetwork.get(position).getPhone2());
holder.tv_cust_map_lat.setText(mAddrNetwork.get(position).getMapLat());
holder.tv_cust_map_lng.setText(mAddrNetwork.get(position).getMapLng());
}
@Override
public int getItemCount() {
return mAddrNetwork.size();
}
public void addAddress(Address_Network_Model addrNetwork) {
Log.d(TAG, addrNetwork.getAddress());
mAddrNetwork.add(addrNetwork);
notifyDataSetChanged();
}
public static class MyViewHolder extends RecyclerView.ViewHolder {
TextView tv_cust_city_id;
TextView tv_cust_address;
TextView tv_cust_zipcode;
TextView tv_cust_phone_1;
TextView tv_cust_phone_2;
TextView tv_cust_map_lat;
TextView tv_cust_map_lng;
public MyViewHolder(View itemView) {
super(itemView);
tv_cust_city_id = itemView.findViewById(R.id.tv_customer_city_id);
tv_cust_address = itemView.findViewById(R.id.tv_customer_address);
tv_cust_zipcode = itemView.findViewById(R.id.tv_customer_zipcode);
tv_cust_phone_1 = itemView.findViewById(R.id.tv_customer_phone);
tv_cust_phone_2 = itemView.findViewById(R.id.tv_customer_phone2);
tv_cust_map_lat = itemView.findViewById(R.id.tv_customer_map_lat);
tv_cust_map_lng = itemView.findViewById(R.id.tv_customer_map_lng);
}
}
}
地址_网络_型号:
package com.example.ganz.afex.models;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Address_Network_Model {
@SerializedName("city_id")
@Expose
private Integer cityId;
@SerializedName("address")
@Expose
private String address;
@SerializedName("zip_code")
@Expose
private String zipCode;
@SerializedName("phone")
@Expose
private String phone;
@SerializedName("phone2")
@Expose
private String phone2;
@SerializedName("map_lat")
@Expose
private Integer mapLat;
@SerializedName("map_lng")
@Expose
private Integer mapLng;
public Integer getCityId() {
return cityId;
}
public void setCityId(Integer cityId) {
this.cityId = cityId;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getZipCode() {
return zipCode;
}
public void setZipCode(String zipCode) {
this.zipCode = zipCode;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getPhone2() {
return phone2;
}
public void setPhone2(String phone2) {
this.phone2 = phone2;
}
public Integer getMapLat() {
return mapLat;
}
public void setMapLat(Integer mapLat) {
this.mapLat = mapLat;
}
public Integer getMapLng() {
return mapLng;
}
public void setMapLng(Integer mapLng) {
this.mapLng = mapLng;
}
}
地址活动:
package com.example.ganz.afex.activities;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import com.example.ganz.afex.R;
import com.example.ganz.afex.adapters.Recyc_Adapter_Addresses;
import com.example.ganz.afex.models.Address_Network_Model;
import com.example.ganz.afex.net.NetworkManager;
import java.util.ArrayList;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import static android.util.Config.LOGD;
public class AddressActivity extends AppCompatActivity {
private List<Address_Network_Model> addressList;
private Recyc_Adapter_Addresses myAdapterAddress;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_address);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
NetworkManager mNetworkManager = new NetworkManager(this);
// if (mNetworkManager != null) {
Toast.makeText(AddressActivity.this, "I guess NetworkManager is Not Null..", Toast.LENGTH_SHORT).show();
Call<List<Address_Network_Model>> listCall = mNetworkManager.getService().getAllAddresses();
listCall.enqueue(new Callback<List<Address_Network_Model>>()
{
@Override
public void onResponse(Call<List<Address_Network_Model>> call,
Response<List<Address_Network_Model>> response) {
Toast.makeText(AddressActivity.this, "I guess onResponce is working..", Toast.LENGTH_SHORT).show();
if (response.isSuccessful()) {
Toast.makeText(AddressActivity.this, "I guess IF STATEMENT is working..", Toast.LENGTH_SHORT).show();
addressList = response.body();
for (int i = 0; i < addressList.size(); i++) {
Address_Network_Model addrNetwork = addressList.get(i);
myAdapterAddress.addAddress(addrNetwork);
myAdapterAddress.notifyDataSetChanged();
Toast.makeText(AddressActivity.this, "I guess the circle is working..", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(AddressActivity.this, "I guess the circle is NOT working..1", Toast.LENGTH_SHORT).show();
int sc = response.code();
switch (sc) {
}
Toast.makeText(AddressActivity.this, "I guess the circle is NOT working..2", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call<List<Address_Network_Model>> call, Throwable t) {
Log.e("MyTag", "This is NOT running");
Toast.makeText(AddressActivity.this, "I guess here is Failure..", Toast.LENGTH_SHORT).show();
}
});
/* } else {
Toast.makeText(AddressActivity.this, "Here is NullPointerException!", Toast.LENGTH_SHORT).show();
}
RecyclerView myRecyc_Addresses = findViewById(R.id.rv_customer_address);
myAdapterAddress = new Recyc_Adapter_Addresses(this, new ArrayList<Address_Network_Model>());
myRecyc_Addresses.setLayoutManager(new LinearLayoutManager(this));
myRecyc_Addresses.setAdapter(myAdapterAddress);
}
public void gotoAddingAddress (View v) {
Intent intentAddingAdd = new Intent (this, AddressAddingActivity.class);
startActivity(intentAddingAdd);
finish();
}
}
网络管理器:
package com.example.ganz.afex.net;
import android.content.Context;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import com.example.ganz.afex.Config;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.readystatesoftware.chuck.ChuckInterceptor;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class NetworkManager {
private static NetworkManager instance = null;
private IService service;
private ConnectivityManager connectionService;
public NetworkManager() {
}
public NetworkManager(final Context context) {
connectionService = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
Interceptor interceptor = new Interceptor() {
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
SharedPreferences preferences = context.getSharedPreferences(Config.TOKEN, Context.MODE_PRIVATE);
String value = preferences.getString(Config.TOKEN, "");
Request newRequest = chain.request().newBuilder().addHeader(Config.HEADER_KEY, value).addHeader("Content-Type", "application/json").build();
return chain.proceed(newRequest);
}
};
Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
.create();
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(20, TimeUnit.SECONDS)
.writeTimeout(20, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS)
.addInterceptor(logging)
.addInterceptor(new ChuckInterceptor(context))
.addInterceptor(interceptor)
.build();
Retrofit retrofit = new Retrofit.Builder()
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.baseUrl("http://api.site.com/v1/")
.build();
service = retrofit.create(IService.class);
}
public static NetworkManager getInstance(Context context) {
if (instance == null) {
instance = new NetworkManager(context);
}
return instance;
}
public boolean isOnline() {
NetworkInfo info = connectionService.getActiveNetworkInfo();
return info != null;
}
public IService getService() {
return service;
}
}
更新: 日志:
Date: Mon, 27 Aug 2018 04:43:58 GMT
Server: Apache/2.4.7 (Ubuntu)
Set-Cookie: advanced-backend=e0c8fjbdmnh4fgt8r21jomvk99; path=/; HttpOnly
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
X-Powered-By: Your Company <www.mywebsite.com>
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers:
Set-Cookie: _identity-backend=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/; HttpOnly
Set-Cookie: _csrf=X7bdxzchUN3XG4UWYEIdTx7931_y_TL_; path=/; HttpOnly
08-27 09:44:03.985 6259-6850/com.example.ganz.afex_with_default_navigation D/OkHttp: Content-Length: 552
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: application/json; charset=UTF-8
08-27 09:44:03.990 6259-6850/com.example.ganz.afex_with_default_navigation D/OkHttp: {
"status": 1,
"data": [
{
"city_id": 1,
"address": "some address",
"zip_code": "zip_code",
"phone": "99891981651",
"phone2": "99866518413",
"map_lat": 654654,
"map_lng": 65465500
},
{
"city_id": 2,
"address": "some address2",
"zip_code": "zip_code2",
"phone": "31213",
"phone2": "321321",
"map_lat": 32165500,
"map_lng": 165850000000
}
]
}
<-- END HTTP (552-byte body)
08-27 09:44:03.993 6259-6259/com.example.ganz.afex_with_default_navigation E/MyTag: This is NOT running
08-27 09:44:04.428 6259-6259/com.example.ganz.afex_with_default_navigation D/ViewRootImpl@9529ad8[MainActivity]: Relayout returned: old=[0,0][720,1280] new=[0,0][720,1280] result=0x1 surface={valid=false 0} changed=false
08-27 09:44:05.758 6259-6259/com.example.ganz.afex_with_default_navigation D/ViewRootImpl@691b290[Toast]: dispatchDetachedFromWindow
08-27 09:44:05.759 6259-6259/com.example.ganz.afex_with_default_navigation D/InputEventReceiver: channel 'e2defff Toast (client)' ~ Disposing input event receiver.
channel 'e2defff Toast (client)' ~NativeInputEventReceiver.
08-27 09:44:05.811 6259-6259/com.example.ganz.afex_with_default_navigation D/ViewRootImpl@fbaf254[Toast]: setView = android.widget.LinearLayout{966f5fd V.E...... ......I. 0,0-0,0} TM=true MM=false
08-27 09:44:05.812 6259-6259/com.example.ganz.afex_with_default_navigation V/Toast: Text: J gu in android.widget.Toast$TN@e7802f2
08-27 09:44:05.816 6259-6259/com.example.ganz.afex_with_default_navigation D/ViewRootImpl@fbaf254[Toast]: dispatchAttachedToWindow
08-27 09:44:05.841 6259-6259/com.example.ganz.afex_with_default_navigation V/Surface: sf_framedrop debug : 0x4f4c, game : false, logging : 0
08-27 09:44:05.842 6259-6259/com.example.ganz.afex_with_default_navigation D/ViewRootImpl@fbaf254[Toast]: Relayout returned: old=[0,0][0,0] new=[166,1064][554,1152] result=0x7 surface={valid=true 3348453376} changed=true
08-27 09:44:05.849 6259-6259/com.example.ganz.afex_with_default_navigation D/ViewRootImpl@fbaf254[Toast]: MSG_RESIZED_REPORT: frame=Rect(166, 1064 - 554, 1152) ci=Rect(0, 0 - 0, 0) vi=Rect(0, 0 - 0, 0) or=1
08-27 09:44:07.780 6259-6259/com.example.ganz.afex_with_default_navigation D/ViewRootImpl@fbaf254[Toast]: dispatchDetachedFromWindow
08-27 09:44:07.780 6259-6259/com.example.ganz.afex_with_default_navigation D/InputEventReceiver: channel '53bdff7 Toast (client)' ~ Disposing input event receiver.
channel '53bdff7 Toast (client)' ~NativeInputEventReceiver.
更新#2: 新日志:
Date: Thu, 30 Aug 2018 13:03:27 GMT
Server: Apache/2.4.7 (Ubuntu)
Set-Cookie: advanced-backend=r2cg25r0sojqsiubadta7019gj; path=/; HttpOnly
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
X-Powered-By: Your Company <www.mywebsite.com>
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers:
D/OkHttp: Set-Cookie: _identity-backend=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/; HttpOnly
Set-Cookie: _csrf=FDDU3VHxYtx5PAbCLMwbyvAmYZpkE_9E; path=/; HttpOnly
Content-Length: 35
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: application/json; charset=UTF-8
D/OkHttp: {
"status": 1,
"data": []
}
<-- END HTTP (35-byte body)
解决方案
我认为问题在于您的 pojo 与您收到的 Json 不匹配。在这次通话中
@GET("addresses/all")
fun getAllAddresses(): Call<List<Address_Network_Model>>
您返回地址列表,但 Json 不同。如果要反序列化给定的 Json,则需要创建另一个 pojo,其中包括状态(实际上是可选的)和地址列表。就像是:
data class ResponseAddresses(
@SerializedName("data")
@Expose
val data: List<Address_Network_Model>
)
如您所见,pojo 应该与 Json 层次结构相匹配。现在,只需更改您的改造电话:
@GET("addresses/all")
fun getAllAddresses(): Call<ResponseAddresses>
编辑
在评论中的一些要求之后,这里有一个更详细的解释。
日志中显示的 json 如下:
{
"status": 1,
"data": [
{
"city_id": 1,
"address": "some address",
"zip_code": "zip_code",
"phone": "99891981651",
"phone2": "99866518413",
"map_lat": 654654,
"map_lng": 65465500
},
...
]
}
此 json 不是地址列表。它是一个包含 2 个字段的对象 -status
和data
. status
是一个整数,data
是您感兴趣的地址列表。
获得正确解析的最简单方法是使用 POJO 复制 json 结构并使用它。现在我知道我第一次使用 kotlin,但让我们在这里使用 java。我只写字段。
class ResponseAddresses {
@SerializedName("data")
@Expose
private List<Address_Network_Model> data;
// ...
}
(您可以添加状态字段,但如果您只想要地址则不需要)
那么这里有什么不同呢?现在您有一个具有 1 个字段的对象 - data
- 这是地址列表。现在,这更容易映射到您收到的 json 并且改造没有问题。唯一缺少的更改是对改造的调用,正如我上面所说,您需要将返回类型更改为Call<ResponseAddresses>
:
@GET("addresses/all")
fun getAllAddresses(): Call<ResponseAddresses>
你将如何获得地址列表?好吧,只需在以下位置正常访问它onResponse
:
@Override
public void onResponse(Call<ResponseAddresses> call,
Response<ResponseAddresses> response) {
if (response.isSuccessful()) {
addressList = response.body().getData();
// ...
}
}
主要的变化是你现在必须调用一个getter——getData()
在这个例子中。
推荐阅读
- javascript - 具有缩放/比例内容的文档
- loops - 需要帮助摆脱 mips 代码中的无限循环
- r - 从条件创建一个新列
- javascript - 具有特定内容的 Vue 每日日历 (Vuetify)
- javascript - 如何相对于它们所在的列而不是页面来定位我的幻灯片的下一个/上一个按钮?(奖励:让他们圈起来?)
- sql-server - 如何减少 SQL Server 中的高页面读取/秒?
- cypress - 如何将 HTML 标记与 Cypress 中的符号进行比较
- java - 是否可以有特定于端点的自定义 JSON 序列化器?
- reactjs - 我可以在前端使用 JSDom 来解析 html
- python - 打印多行字符串,水平堆叠和对齐