使用 Retrofit 的 API 响应为某些非 null 的参数返回 null

Posted

技术标签:

【中文标题】使用 Retrofit 的 API 响应为某些非 null 的参数返回 null【英文标题】:API response using Retrofit returns null for certain parameters which aren't null 【发布时间】:2021-12-29 10:26:44 【问题描述】:

我正在为我的 android 应用程序使用 Retrofit,但很少有参数返回为 null,而其他参数有值,它在 POSTMAN 上运行良好。

我用于 Api 调用的函数:

private fun apiCall(search: String): List<SortedApiData> 

    var recyclerDataList: List<SortedApiData> = ArrayList<SortedApiData>()

    val consumer = OkHttpOAuthConsumer("9c6c751a78db41b9a8bec92ef28c7656", "3f302d7930a74c1db0304ce675d4d41b")
    consumer.setTokenWithSecret("","")

    val client1 = OkHttpClient.Builder()
        .addInterceptor(SigningInterceptor(consumer))
        .build()

    var retrofit : Retrofit = Retrofit.Builder()
        .baseUrl(BaseUrl)
        .client(client1)
        .addConverterFactory(GsonConverterFactory.create())
        .build()

    val api: Client = retrofit.create(Client::class.java)
    val call: retrofit2.Call<ApiData?>? = api.getResponse(search, 5, 0, 0)

    call?.enqueue(object : Callback<ApiData?> 
        override fun onFailure(call: retrofit2.Call<ApiData?>, t: Throwable?) 
            Log.v("retrofit", t.toString())
        

        override fun onResponse(call: retrofit2.Call<ApiData?>, response: Response<ApiData?>) 
            val data: ApiData? = response.body()
            popUprecycler.visibility = View.VISIBLE

            Log.v("retrofit", data.toString())

            recyclerDataList = createList(data)
            adapter = PopUpAdapter(this@PopPage, recyclerDataList)
            popUprecycler.layoutManager = GridLayoutManager(applicationContext, 2)
            popUprecycler.itemAnimator = DefaultItemAnimator()
            popUprecycler.setHasFixedSize(true)
            popUprecycler.adapter = adapter
            Log.i("Shrey", "shit")
        
)
    return recyclerDataList

@GET请求函数:

interface Client 

    @GET("id/icons")
    fun getResponse(@Path("id") id: String?,@Query("limit") limit: Int?,@Query("offset") offset: Int?,@Query("page") page: Int?): Call<ApiData?>?

模型类:

public class ApiData
    private int total;
    private String generatedAt;
    private Collection collection;
    private List<IconsItem> icons;

    public int getTotal()
        return total;
    

    public String getGeneratedAt()
        return generatedAt;
    

    public Collection getCollection()
        return collection;
    

    public List<IconsItem> getIcons()
        return icons;
    

图标模型类:

public class IconsItem
    private Sponsor sponsor;
    private String uploaderId;
    private String isActive;
    private String nounjiFree;
    private int year;
    private String dateUploaded;
    private Object sponsorCampaignLink;
    private int termId;
    private String sponsorId;
    private String termSlug;
    private String licenseDescription;
    private List<TagsItem> tags;
    private String attributionPreviewUrl;
    private String updatedAt;
    private String previewUrl;
    private Uploader uploader;
    private String attribution;
    private String previewUrl42;
    private String freemium;
    private String term;
    private String id;
    private String permalink;
    private String isExplicit;
    private String previewUrl84;

    public Sponsor getSponsor()
        return sponsor;
    

    public String getUploaderId()
        return uploaderId;
    

    public String getIsActive()
        return isActive;
    

    public String getNounjiFree()
        return nounjiFree;
    

    public int getYear()
        return year;
    

    public String getDateUploaded()
        return dateUploaded;
    

    public Object getSponsorCampaignLink()
        return sponsorCampaignLink;
    

    public int getTermId()
        return termId;
    

    public String getSponsorId()
        return sponsorId;
    

    public String getTermSlug()
        return termSlug;
    

    public String getLicenseDescription()
        return licenseDescription;
    

    public List<TagsItem> getTags()
        return tags;
    

    public String getAttributionPreviewUrl()
        return attributionPreviewUrl;
    

    public String getUpdatedAt()
        return updatedAt;
    

    public String getPreviewUrl()
        return previewUrl;
    

    public Uploader getUploader()
        return uploader;
    

    public String getAttribution()
        return attribution;
    

    public String getPreviewUrl42()
        return previewUrl42;
    

    public String getFreemium()
        return freemium;
    

    public String getTerm()
        return term;
    

    public String getId()
        return id;
    

    public String getPermalink()
        return permalink;
    

    public String getIsExplicit()
        return isExplicit;
    

    public String getPreviewUrl84()
        return previewUrl84;
    

API 响应注意突出显示的值不应为空:

正确的 API 响应:

【问题讨论】:

【参考方案1】:

请注意,未读取的变量是带有驼峰命名法(中间大写字母)的变量,同时在 JSON 中,您使用下划线标记 _ 分隔单词。正确读取的值只有在 JSON 中具有完全相同的键和在模型中具有完全相同的名称的值(所以没有下划线,两个地方都没有大字母)。您应该为这些字段使用@SerializedName 注释,例如

@SerializedName("attribution_preview_url") // real key in JSON
private String attributionPreviewUrl;

还值得检查setFieldNamingPolicy 方法,也许这可能会以某种方式自动化,而无需为模型中的每个驼峰式名称编写注释(JSON 中带下划线的键)

【讨论】:

以上是关于使用 Retrofit 的 API 响应为某些非 null 的参数返回 null的主要内容,如果未能解决你的问题,请参考以下文章

如何使用Retrofit请求非Restful API

使用 JSend 格式通过 Retrofit 将 JSON 响应转换为 POJO?

如何使用Retrofit请求非Restful API

Retrofit/OkHttp API接口加固技术实践(下)

RxJava Retrofit2 api 使用 subscribe 或 flatmap 多次调用

使用 Retrofit Android 对多个 API 进行常见成功/失败/错误处理的良好设计