【问题标题】:Getting null pointer exception when trying to parse JSON in Retrofit in kotlin with Android studio尝试使用 Android Studio 在 kotlin 的 Retrofit 中解析 JSON 时出现空指针异常
【发布时间】:2019-11-23 07:59:48
【问题描述】:

我正在尝试从 Github API 获取用户。 API 运行良好并接收响应,但在尝试解析 JSON 时出现问题。请指导我。我对 kotlin 和 Retrofit 很陌生。因此,请指导我如何获得适当的解决方案。 这是我的 JSON 响应。

    {
    "login": "photoionized",
    "id": 597302,
    "node_id": "MDQ6VXNlcjU5NzMwMg==",
    "avatar_url": "https://avatars0.githubusercontent.com/u/597302?v=4",
    "gravatar_id": "",
    "url": "https://api.github.com/users/photoionized",
    "html_url": "https://github.com/photoionized",
    "followers_url": "https://api.github.com/users/photoionized/followers",
    "following_url": "https://api.github.com/users/photoionized/following{/other_user}",
    "gists_url": "https://api.github.com/users/photoionized/gists{/gist_id}",
    "starred_url": "https://api.github.com/users/photoionized/starred{/owner}{/repo}",
    "subscriptions_url": "https://api.github.com/users/photoionized/subscriptions",
    "organizations_url": "https://api.github.com/users/photoionized/orgs",
    "repos_url": "https://api.github.com/users/photoionized/repos",
    "events_url": "https://api.github.com/users/photoionized/events{/privacy}",
    "received_events_url": "https://api.github.com/users/photoionized/received_events",
    "type": "User",
    "site_admin": false,
    "name": "Andrew Stucki",
    "company": "Aspera, Inc.",
    "blog": "",
    "location": "Alameda, CA",
    "email": null,
    "hireable": null,
    "bio": null,
    "public_repos": 4,
    "public_gists": 1,
    "followers": 2,
    "following": 0,
    "created_at": "2011-02-02T18:44:31Z",
    "updated_at": "2016-05-12T04:40:54Z"
}

这里是 MyApi 代码

    interface MyApi {
    @GET("users/{username}")
    suspend fun userLogin(
        @Path("username") username: String

    ) : Response<AuthResponse>

    companion object{
        operator fun invoke() : MyApi {
            return Retrofit.Builder()
                .baseUrl("https://api.github.com")
                .addConverterFactory(GsonConverterFactory.create())
                .build()
                .create(MyApi :: class.java)
        }
    }
}

这是我的 POKO 课

const val CURRENT_USER_ID = 0

@Entity
data class User (
    var id: Int? = null,
    var name: String? = null,
    var email: String? = null,
    var login: String? = null,
    var avatar_url: String? = null,
    var gravatar_id: String? = null,
    var url: String? = null,
    var html_url: String? = null,
    var company: String? = null,
    var followers_url: String? = null,
    var created_at: String? = null,
    var updated_at: String? = null
){
    @PrimaryKey(autoGenerate = false)
    var uid: Int = CURRENT_USER_ID
}

这是用户存储库类代码

   class UserRepository {

    suspend fun userLogin(username: String) : Response<AuthResponse>{
    return MyApi().userLogin(username)

    }
}

这里是验证响应

data class AuthResponse (
    val isSuccessful : Boolean?,
    val message: String?,
    val user: User?
)

here is AuthViewModel

    class AuthViewModel : ViewModel() {
    var username: String? = null

    var authListener : AuthListener? = null

    fun onLoginButtonClick(view: View){
        authListener?.onStarted()
        if (username.isNullOrEmpty()){
            authListener?.onFailure("Invalid email or password")
            //
            return
        }
        Coroutines.main{
            val response = UserRepository().userLogin(username!!)
            if (response.isSuccessful){
                authListener?.onSuccess(response.body()?.user!!)

            }else{
                authListener?.onFailure("Error Code: ${response.code()}")
            }
        }

    }
}

这里是登录活动

class LoginActivity : AppCompatActivity(), AuthListener {


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding : ActivityLoginBinding = DataBindingUtil.setContentView(this, R.layout.activity_login)
        val viewModel = ViewModelProviders.of(this).get(AuthViewModel :: class.java)
        binding.viewmodel= viewModel
        viewModel.authListener = this
    }
    override fun onStarted() {
        toast("Login Started")
        progress_bar.show()
    }

    override fun onSuccess(user: User) {
        progress_bar.hide()
        toast("${user.login} is found")
    }
    override fun onFailure(message: String) {
        progress_bar.hide()
        toast(message)
    }
}

这是我的 Logcat 错误

PID:15204

kotlin.KotlinNullPointerExceptionat com.isofttechpro.myapplication.ui.auth.AuthViewModel$onLoginButtonClick$1.invokeSuspend(AuthViewModel.kt:23)

【问题讨论】:

  • 我无法在此处查明任何具体问题。尝试放置断点并确定 response、response.body() 或 response.body().user 是否为空。如果 respon.body() 不为 null,请检查其中包含的值,它可能会将您指向实际问题。

标签: android json kotlin retrofit retrofit2


【解决方案1】:

当您使用 !! 强制展开空值时,会发生 KotlinNullPointerException。 错误可能在于以下几行,

val response = UserRepository().userLogin(username!!)
if (response.isSuccessful){
  authListener?.onSuccess(response.body()?.user!!)

尽量不要使用!!,而是尽量使用let、apply、run等。例如,

//rather than
//authListener?.onSuccess(response.body()?.user!!)
//use
response.body()?.user?.let {
  authListener?.onSuccess(it)
}

另一种替代方法是使用 elvis 运算符并提供默认值。例如,

authListener?.onSuccess(response.body()?.user?:"default value")

【讨论】:

  • 是的,错误在第 3 行。但是如何解决这个问题?
  • 是的,我试过让然后得到响应为空,这就是为什么我得到空的问题?
  • 您从 UserRepository 获取响应的方式可能存在问题。
  • class UserRepository { 暂停乐趣 userLogin(username: String) : Response{ return MyApi().userLogin(username) } }
  • @CrisvinJem 请指导我现在我已经更新了我的问题。
【解决方案2】:

首先,不要使用 null 来启动您的数据类属性。

其次,您的响应是原始 JSON,因此它不需要任何父类来解析。 例如,您的数据类 AuthResponse 不是必需的。

使用以下代码将其解析为您的数据模型。

val gson:Gson = Gson()
var user = gson?.fromJson(response.body(), Users::class.java)

【讨论】:

    猜你喜欢
    • 2023-03-31
    • 2020-11-13
    • 2012-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-30
    • 1970-01-01
    相关资源
    最近更新 更多