0

I am trying to get a user from Github API. API is working well and receiving the response but getting a problem when trying to parse JSON. kindly guide me. I am Fresh with kotlin and Retrofit. So, please guide me on how to get a proper solution. Here is my JSON Respons.

    {
    "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"
}

Here is MyApi code

    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)
        }
    }
}

Here is My POKO class

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
}

here is User Repository class code

   class UserRepository {

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

    }
}

here is Auth Response

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()}")
            }
        }

    }
}

Here is Login Activity

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)
    }
}

Here is my Logcat error

PID: 15204

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

1
  • I'm unable to pinpoint any specific issue here. Try placing break points and determine whether response, response.body() or response.body().user is null. And if respone.body() is not null, inspect the values contained within, it'll probably point you towards the actual issue. Commented Jul 14, 2019 at 9:48

2 Answers 2

4

KotlinNullPointerException occurs when you force unwrap a null value using !!. The error probably lies in the following lines,

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

Try to not use !! as much as possible, rather try to use let, apply, run, etc. For example,

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

Another alternative to that is to use the elvis operator and provide default values. For example,

authListener?.onSuccess(response.body()?.user?:"default value")
Sign up to request clarification or add additional context in comments.

7 Comments

yeah error is on the 3rd line. but how to resolve this one?
Yeah I have tried let and then get response null, that is the problem why I am getting null?
There's probably an issue in how you're getting the response from the UserRepository.
class UserRepository { suspend fun userLogin(username: String) : Response<AuthResponse>{ return MyApi().userLogin(username) } }
@CrisvinJem Please guide me now I have updated my question.
|
1

Firstly, Don't use null to initiate your data class properties.

Secondly, your response is in raw JSON so it doesn't need any parent class to parse. e.g your data class AuthResponse is not required.

Use the below code to parse it to your data model.

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.