Reputation: 1926
I am trying to do an async call and then update a RecyclerView
. Much like what's outlined in this question: RecyclerView element update + async network call
However, when I try to do this, I get this error:
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
Here is my code (the main issue is in the setAlbums function):
class AlbumActivity : AppCompatActivity() {
protected lateinit var adapter: MyRecyclerViewAdapter
protected lateinit var recyclerView: RecyclerView
var animalNames = listOf("nothing")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_album)
recyclerView = findViewById<RecyclerView>(R.id.rvAnimals)
recyclerView.layoutManager = LinearLayoutManager(this)
adapter = MyRecyclerViewAdapter(this, animalNames)
recyclerView.adapter = adapter
urlCall("https://rss.itunes.apple.com/api/v1/us/apple-music/coming-soon/all/10/explicit.json")
}
private fun urlCall(url: String) {
val client = OkHttpClient()
val request = Request.Builder().url(url).build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {}
override fun onResponse(call: Call, response: Response) = getJSON(response.body()?.string())
})
}
fun getJSON(data: String?) {
val gson = Gson()
val allAlbums = ArrayList<Album>()
val jsonResponse = JSONObject(data)
val feed = jsonResponse.getJSONObject("feed")
val albums = feed.getJSONArray("results")
for (i in 0 until albums.length()) {
val album = albums.getJSONObject(i)
allAlbums.add(gson.fromJson(album.toString(), Album::class.java))
}
setAlbums(allAlbums)
}
fun setAlbums(albums: ArrayList<*>) {
animalNames = listOf("sue", "betsie")
adapter.notifyDataSetChanged() // This is where I am telling the adapter the data has changed
}
internal inner class Album {
var artistName: String? = null
var name: String? = null
}
}
Does anyone know the issue I am having?
Upvotes: 2
Views: 1206
Reputation: 1007359
Your Callback
functions will be called on a background thread. In part, that is because OkHttp is not an Android-specific library, so it has no idea about Android's main application thread.
You will need to do something to update the UI in the main application thread. Modern options include:
Callback
update a MutableLiveData
that your UI observes, as then the UI will get updates on the main application threadUpvotes: 2
Reputation: 7661
You need to execute your wanted code on your main thread like this :
runOnUiThread(new Runnable() {
@Override
public void run() {
//update your UI
}
});
Upvotes: 3