我有以下与RecyclerView
配合使用的代码,同时,我有一个websocket
适用于onMessage
的代码,并正确打印了接收到的味精。 / p>
然后,我尝试将它们合并在一起,即从socket
接收数据并将其直接推送到RecyclerView
,但是在RecyclerView
屏幕上没有显示任何内容
在我的一项试验中,出现了此错误:
I / Websocket:错误仅创建视图的原始线程 层次结构可以触摸其视图。
lateinit var mWebSocketClient: WebSocketClient
lateinit var uniqueID: String
lateinit var rv: RecyclerView
val chaptersList: ArrayList<String> = ArrayList()
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
rv = rvChapterList // "@+id/rvChapterList" of RecyclerView
// chaptersList.add(s)
// rvChapterList.layoutManager = layoutManager
// rvChapterList.adapter = ChapterAdapter(this, chaptersList)
var context= this
connectWebSocket(context)
}
fun connectWebSocket(context: MainActivity) {
val uri: URI
try {
uri = URI("ws://10.0.2.2:8080/ws")
} catch (e: URISyntaxException) {
e.printStackTrace()
println("ws faild")
return
}
mWebSocketClient = object : WebSocketClient(uri) {
override fun onOpen(serverHandshake: ServerHandshake) {
Log.i("Websocket", "Opened")
mWebSocketClient.send("Hello from " + Build.MANUFACTURER + " " + Build.MODEL)
}
override fun onMessage(s: String) {
Log.i("Websocket", "Recieved $s") // This is working
chaptersList.add(s)
Log.i("chaptersList", "chaptersList $s") // This is working
rv.layoutManager = LinearLayoutManager(context)
rv.adapter = ChapterAdapter(context , chaptersList) // This is not working
}
}
mWebSocketClient.connect()
}
更新
参考this的答案,我尝试了以下操作,但没有成功:
lateinit var rv: RecyclerView
lateinit var layoutManager: RecyclerView.LayoutManager
lateinit var adaptor: ChapterAdapter
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
layoutManager = LinearLayoutManager(this)
rv = rvChapterList
adaptor = ChapterAdapter(this, chaptersList)
rv.adapter = adaptor
rv.layoutManager = layoutManager
rv.adapter = ChapterAdapter(this, chaptersList)
}
}
fun connectWebSocket(context: MainActivity) {
override fun onMessage(s: String) {
val insertIndex = chaptersList.size
chaptersList.add(insertIndex, s)
adaptor.notifyItemInserted(insertIndex)
adaptor.notifyDataSetChanged()
}
}
答案 0 :(得分:3)
只能在主线程中访问视图。由于onMessage()
方法是在 worker线程(后台)上运行的,因此无法直接在视图上进行更改。有多种方法可以从{em> worker thread 中更改视图,例如androd.os.Handler
。在您的情况下,runOnUiThread(Runnable)
提供的Activity.class
方法是一个不错的选择。它以runnable
作为参数,并在UI线程上运行。就您而言,它可以按以下方式使用:
override fun onMessage(s: String) {
val insertIndex = chaptersList.size
chaptersList.add(insertIndex, s)
Thread {
runOnUiThread {
adaptor.notifyItemInserted(insertIndex)
}
}.run()
}
更新:
另一种更可靠的方法是使用LiveData
中的Android Architecture Components。由于LiveData
是一个可观察且具有生命周期意识的数据持有者类,因此可以这样使用:
另一个类文件:
class SocketClient {
val message = MutableLiveData<String>()
fun connectWebSocket(context: Context) {
// Setup stuff
mWebSocketClient = object : WebSocketClient(uri) {
override fun onOpen(serverHandshake: ServerHandshake) {
// Opened do some stuff
}
override fun onMessage(s: String) {
message.postValue(s)
}
}
mWebSocketClient.connect()
}
}
在活动的onCreate()
中:
val client = SocketClient()
client.message.observe(this, Observer { s: String ->
val insertIndex = chaptersList.size
chaptersList.add(insertIndex, s)
adaptor.notifyItemInserted(insertIndex)
})
client.connectWebSocket(this)
在使用LiveData
之前,需要添加依赖项。参见official documentation。
为:
def lifecycle_version = "2.0.0"
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"