首页 > 解决方案 > 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)

标签: javaandroidretrofit2response

解决方案


我认为问题在于您的 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 个字段的对象 -statusdata. 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()在这个例子中。


推荐阅读