0

So, I have two recyclerview with their different adapter. I want to display one of them if I click a button. The other adapter works well. But not with the second adapter.

body

09-07 21:41:37.000 11177-11219/com.example.android.footballmatchschedule I/System.out: {"events":[{"idEvent":"576511","idSoccerXML":"389896","strEvent":"Huddersfield Town vs Crystal Palace","strFilename":"English Premier League 2018-09-15 Huddersfield Town vs Crystal Palace","strSport":"Soccer","idLeague":"4328","strLeague":"English Premier League","strSeason":"1819","strDescriptionEN":null,"strHomeTeam":"Huddersfield Town","strAwayTeam":"Crystal Palace","intHomeScore":null,"intRound":"5","intAwayScore":null,"intSpectators":null,"strHomeGoalDetails":null,"strHomeRedCards":null,"strHomeYellowCards":null,"strHomeLineupGoalkeeper":null,"strHomeLineupDefense":null,"strHomeLineupMidfield":null,"strHomeLineupForward":null,"strHomeLineupSubstitutes":null,"strHomeFormation":null,"strAwayRedCards":null,"strAwayYellowCards":null,"strAwayGoalDetails":null,"strAwayLineupGoalkeeper":null,"strAwayLineupDefense":null,"strAwayLineupMidfield":null,"strAwayLineupForward":null,"strAwayLineupSubstitutes":null,"strAwayFormation":null,"intHomeShots":null,"intAwayShots":null,"dateEvent":"2018-09-15","strDate":"15\/09\/18","strTime":"14:00:00+00:00","strTVStation":null,"idHomeTeam":"133932","idAwayTeam":"133632","strResult":null,"strCircuit":null,"strCountry":null,"strCity":null,"strPoster":null,"strFanart":null,"strThumb":null,"strBanner":null,"strMap":null,"strLocked":"unlocked"},{"idEvent":"576512","idSoccerXML":"389897","strEvent":"Man City vs Fulham","strFilename":"English Premier League 2018-09-15 Man City vs Fulham","strSport":"Soccer","idLeague":"4328","strLeague":"English Premier League","strSeason":"1819","strDescriptionEN":null,"strHomeTeam":"Man City","strAwayTeam":"Fulham","intHomeScore":null,"intRound":"5","intAwayScore":null,"intSpectators":null,"strHomeGoalDetails":null,"strHomeRedCards":null,"strHomeYellowCards":null,"strHomeLineupGoalkeeper":null,"strHomeLineupDefense":null,"strHomeLineupMidfield":null,"strHomeLineupForward":null,"strHomeLineupSubstitutes":null,"strHomeFormation":null,"strAwayRedCards":null,"strAwayYellowCards":null,"strAwayGoalDetails":null,"strAwayLineupGoalkeeper":null,"strAwayLineupDefense":null,"strAwayLineupMidfield":null,"strAwayLineupForward":null,"strAwayLineupSubstitutes":null,"strAwayFormation":null,"intHomeShots":null,"intAwayShots":null,"dateEvent":"2018-09-15","strDate":"15\/09\/18","strTime":"14:00:00+00:00","strTVStation":null,"idHomeTeam":"133613","idAwayTeam":"133600","strResult":null,"strCircuit":null,"strCountry":null,"strCity":null,"strPoster":null,"strFanart":null,"strThumb":null,"strBanner":null,"strMap":null,"strLocked":"unlocked"},{"idEvent":"576513","idSoccerXML":"389898","strEvent":"Newcastle vs Arsenal","strFilename":"English Premier League 2018-09-15 Newcastle vs Arsenal","strSport":"Soccer","idLeague":"4328","strLeague":"English Premier League","strSeason":"1819","strDescriptionEN":null,"strHomeTeam":"Newcastle","strAwayTeam":"Arsenal","intHomeScore":null,"intRound":"5","intAwayScore":null,"intSpectators":null,"strHomeGoalDetails":null,"strHomeRedCards":null,"strHomeYellowCards":null,"strHomeLineupGoalkeeper":null,"strHomeLineupDefense":null,"strHomeLineupMidfield":null,"strHomeLineupForward":null,"strHomeLineupSubstitutes":null,"strHomeFormation":null,"strAwayRedCards":null,"strAwayYellowCards":null,"strAwayGoalDetails":null,"strAwayLineupGoalkeeper":null,"strAwayLineupDefense":null,"strAwayLineupMidfield":null,"strAwayLineupForward":null,"strAwayLineupSubstitutes":null,"strAwayFormation":null,"intHomeShots":null,"intAwayShots":null,"dateEvent":"2018-09-15","strDate":"15\/09\/18","strTime":"14:00:00+00:00","strTVStation":null,"idHomeTeam":"134777","idAwayTeam":"133604","strResult":null,"strCircuit":null,"strCountry":null,"strCity":null,"strPoster":null,"strFanart":null,"strThumb":null,"strBanner":null,"strMap":null,"strLocked":"unlocked"},{"idEvent":"576515","idSoccerXML":"389900","strEvent":"Bournemouth vs Leicester","strFilename":"English Premier League 2018-09-15 Bournemouth vs Leicester","strSport":"Soccer","idLeague":"4328","strLeague":"English Premier League","strSeason":"1819","strDescriptionEN":null,"strHomeTeam":"Bournemout

NextMatch class

class NextMatch(val event: List<Event>)
class Event(val strDate: String, val strHomeTeam: String, val strAwayTeam: String)

fetchJson function

fun fetchJson(){
    //Json for prev match
    val url = "https://www.thesportsdb.com/api/v1/json/1/eventspastleague.php?id=4328"
    val url2 = "https://www.thesportsdb.com/api/v1/json/1/eventsnextleague.php?id=4328"
    val request = Request.Builder().url(url).build()
    val request2 = Request.Builder().url(url2).build()
    val client = OkHttpClient()
    client.newCall(request).enqueue(object: Callback{
        override fun onResponse(call: Call?, response: Response?){
            println("sukses")
            val body = response?.body()?.string()
            println(body)

            val gson = GsonBuilder().create()

            val prevMatch = gson.fromJson(body, PrevMatch::class.java)

            runOnUiThread { recyclerView_prevMatch.adapter = MainAdapters(prevMatch) }
        }
        override fun onFailure(call: Call?, e: IOException?){
            println("failed request")
        }
    })
    client.newCall(request2).enqueue(object: Callback{
        override fun onResponse(call: Call?, response: Response?){
            println("sukses")
            val body = response?.body()?.string()
            println(body)

            val gson = GsonBuilder().create()

            val nextMatch = gson.fromJson(body, NextMatch::class.java)

            runOnUiThread { recyclerView_nextMatch.adapter = MainAdapter(nextMatch) }
        }
        override fun onFailure(call: Call?, e: IOException?){
            println("failed request")
        }
    })

MainAdapter.kt file:

class MainAdapter(val nextMatch: NextMatch): RecyclerView.Adapter<CustomViewHolder>(){

//Adapter Next Match

override fun getItemCount(): Int {
    return 15
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomViewHolder {
    val layoutInflater = LayoutInflater.from(parent.context)
    val callForRow = layoutInflater.inflate(R.layout.item_row,parent,false)
    return CustomViewHolder(callForRow)
}

override fun onBindViewHolder(holder: CustomViewHolder, position: Int) {
    holder.view.team_home.text =  nextMatch.event.get(position).strHomeTeam
    holder.view.team_away.text =  nextMatch.event.get(position).strAwayTeam
    holder.view.time_schedule.text = nextMatch.event.get(position).strDate
}

}

And when I tried to run it, it force stopped. After I look at the Logcat:

Process: com.example.android.footballmatchschedule, PID: 8307
java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.Object java.util.List.get(int)' on a null object reference
    at com.example.android.footballmatchschedule.MainAdapter.onBindViewHolder(MainAdapter.kt:24)
    at com.example.android.footballmatchschedule.MainAdapter.onBindViewHolder(MainAdapter.kt:9)
    at android.support.v7.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:6673)
    at android.support.v7.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:6714)
    at android.support.v7.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline(RecyclerView.java:5647)
    at android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5913)
    at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5752)
    at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5748)
    at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2232)
    at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1559)
    at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1519)
    at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:614)
    at android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3812)
    at android.support.v7.widget.RecyclerView.onMeasure(RecyclerView.java:3225)
    at android.view.View.measure(View.java:19147)
    at android.support.constraint.ConstraintLayout.internalMeasureChildren(ConstraintLayout.java:1212)
    at android.support.constraint.ConstraintLayout.onMeasure(ConstraintLayout.java:1552)
    at android.view.View.measure(View.java:19147)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6113)
    at android.widget.FrameLayout.onMeasure(FrameLayout.java:223)
    at android.support.v7.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:141)
    at android.view.View.measure(View.java:19147)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6113)
    at android.support.v7.widget.ActionBarOverlayLayout.onMeasure(ActionBarOverlayLayout.java:400)
    at android.view.View.measure(View.java:19147)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6113)
    at android.widget.FrameLayout.onMeasure(FrameLayout.java:223)
    at android.view.View.measure(View.java:19147)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6113)
    at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1723)
    at android.widget.LinearLayout.measureVertical(LinearLayout.java:788)
    at android.widget.LinearLayout.onMeasure(LinearLayout.java:648)
    at android.view.View.measure(View.java:19147)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6113)
    at android.widget.FrameLayout.onMeasure(FrameLayout.java:223)
    at com.android.internal.policy.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:3346)
    at android.view.View.measure(View.java:19147)
    at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2491)
    at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1450)
    at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1704)
    at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1323)
    at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6718)
    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:894)
    at android.view.Choreographer.doCallbacks(Choreographer.java:696)
    at android.view.Choreographer.doFrame(Choreographer.java:631)
    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:880)
    at android.os.Handler.handleCallback(Handler.java:815)
    at android.os.Handler.dispatchMessage(Handler.java:104)
    at android.os.Looper.loop(Looper.java:207)
    at android.app.ActivityThread.main(ActivityThread.java:5737)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller

It shows that the get(position) function from API trying to get it from a null object. How can it be? I mean how can I solve this?

Zoe
  • 27,060
  • 21
  • 118
  • 148
Rayhan Hanaputra
  • 106
  • 2
  • 16
  • Check that `nextMatch.event` isn't null before running your code in `onBindViewHolder` – MFazio23 Sep 07 '18 at 14:06
  • Be careful with deleting post, you don't want to end up with a post ban. https://stackoverflow.com/help/question-bans –  Sep 07 '18 at 15:05
  • Okay.. my bad. I don't know about this and you're telling me about this. thank you very much. – Rayhan Hanaputra Sep 07 '18 at 15:20
  • Possible duplicate of [What is a NullPointerException, and how do I fix it?](https://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-do-i-fix-it) – Zoe Sep 07 '18 at 19:04
  • @RayhanHanaputra you're welcome. that's why I mentioned it. –  Sep 09 '18 at 00:02

2 Answers2

1

Suspect your NextMatch is a java defined type, where the event could be null. Try change on onBindViewHolder function to below

fun onBindViewHolder(holder: CustomViewHolder, position: Int) {
    val event = nextMatch.event
    if (event != null) {
        holder.view.team_home.text = event.get(position).strHomeTeam
        holder.view.team_away.text = event.get(position).strAwayTeam
        holder.view.time_schedule.text = event.get(position).strDate
    } else {
        Log.d("TAG", "event is null!!")
    }
}

If you see the log event is null, it's confirm you need to set your event in the nextMatch object first, before using it.

UPDATED

Per the additional shared information, the issue is due to the event variable of NextMatch mis-match with the body JSON name events.

So to fix, just change the

class NextMatch(val event: List<Event>)

to

class NextMatch(val events: List<Event>)

Then the gson deserialization will work, where events now is no longer null.

Elye
  • 53,639
  • 54
  • 212
  • 474
1

Your RecyclerView adapter's item count is constant, are you sure for this?

override fun getItemCount(): Int {
     return 15
}
Mete
  • 2,805
  • 1
  • 28
  • 38
  • Oh yeah. my bad. I could use nextMatch.events.count() instead. thanks for your reminder. really appreciate this. – Rayhan Hanaputra Sep 07 '18 at 15:17
  • 1
    In my opinion Mete is correct. This is the true root to the issue the OP is experiencing. No need to check for `null` when `getItemCount()` returns the correct value! – Barns Sep 07 '18 at 15:53