android - 试图影响片段内的视图的问题
问题描述
所以,我目前正在使用 Android Studio 构建一个 Android 应用程序。我正在使用 Kotlin 构建它,关于该应用程序的具体要点是:
- 我正在
BottomNavigationView
使用NavFragmentView
.Navigation Graph
那部分工作正常。 - 我有 5 个主要片段,它们是应用程序的主要部分,基本上,当您点击正确片段的其中一项时,
BottonNavigationView
就会被拉到 mainNavFragmentView
。
我目前坚持RecyclerView
使用GridLayout
.
我已经准备好用户界面,并RecyclerView
用我的适配器内的列表中的静态数据填充RecyclerView
.
我做的下一件事是使用从我的 API 获取我的 JSON 数据OkHTTP
,然后使用GSON
. 到目前为止一切正常,JSON 格式正确并获得。当我想将它传递给适配器时,麻烦就开始了。
在此之前我在访问东西时遇到了一些麻烦,因为我是 Kotlin 和 Android 的新手,我无法直接从片段中访问东西,但后来我发现我可以将片段的主视图分配给一个变量并参考从那里开始。那部分部分解决了我的问题。所以,我的代码是这样的:
MesFragment.kt - 这是我的片段的 Kotlin 文件,如您所见,我将主视图分配给mesView
变量,我必须在主函数之外创建它,因为当尝试在fetchMes()
函数中分配适配器时它没有访问视图
class MesFragment : Fragment() {
var mesView : View? = null
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
mesView = inflater.inflate(R.layout.fragment_mes, container, false)
//mesView.calendario_mes.adapter = MesAdapter()
fetchInfoMes("201905")
return mesView
}
fun fetchInfoMes(mes: String) {
val url = "https://www.myoriginalsite.com/api/mes/"+ mes +"/-0500/norte"
val request = Request.Builder().url(url).build()
val client = OkHttpClient()
client.newCall(request).enqueue(object: Callback {
override fun onResponse(call: Call, response: Response) {
var body = response.body()?.string()
val gson = GsonBuilder().create()
val mesFeed : List<FechaCompleta> = gson.fromJson(body, object: TypeToken<List<FechaCompleta>>() {}.type)
mesView?.calendario_mes?.adapter = MesAdapter(mesFeed)
}
override fun onFailure(call: Call, e: IOException) {
println("Error")
}
})
}
}
class FechaCompleta(val vacia: Boolean, val imagen_signo: String, val imagen_luna: String, val fecha: String, val dia: String, val id_entrada: Int)
MesAdapter.kt - 这是我的适配器,如您所见,我已经评论了我的静态列表,我想要做的唯一 UI 更改是mes_fecha.text
class MesAdapter(val mesFeed: List<FechaCompleta>): RecyclerView.Adapter<MesViewHolder>() {
//val list = listOf<String>("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31")
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MesViewHolder {
val layoutInflater = LayoutInflater.from(parent?.context)
val cell = layoutInflater.inflate(R.layout.celda_mes_layout, parent, false)
return MesViewHolder(cell)
}
override fun getItemCount(): Int {
return mesFeed.size
}
override fun onBindViewHolder(holder: MesViewHolder, position: Int) {
holder?.view?.mes_fecha.text = mesFeed[position].dia
}
}
class MesViewHolder(val view: View): RecyclerView.ViewHolder(view) {
}
一旦我打开片段,应用程序就会关闭,我得到这个错误:
E/AndroidRuntime: FATAL EXCEPTION: OkHttp Dispatcher
Process: com.testing.fragmentapp, PID: 8148
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
解决方案
OkHttpClient 在后台线程上调用回调。
所以你应该:
1.) 改用 Retrofit,它会在 UI 线程上调用你的回调
2.) 使用 Handler 从后台线程返回 UI 线程
private val handler = Handler(Looper.getMainLooper())
call.enqueue(object: Callback {
override fun onResponse(call: Call, response: Response) {
var body = response.body()?.string()
val gson = GsonBuilder().create()
val mesFeed : List<FechaCompleta> = gson.fromJson(body, object: TypeToken<List<FechaCompleta>>() {}.type)
handler.post {
mesView?.calendario_mes?.adapter = MesAdapter(mesFeed)
}
}
override fun onFailure(call: Call, e: IOException) {
println("Error")
}
})
推荐阅读
- mysql - 在 MySQL 查询中重复 COUNT(*) 是否昂贵?
- angular - ng add @angular/fire '服务器错误。证书已过期'
- perl - 如何强制 perl 仅从标准输入而不是从命令行上的文件处理 args?
- cypress - 如何将 @babel/plugin-proposal-nullish-coalescing-operator 添加到 Cypress.io 命令?
- node.js - “@”在“@/assets/xyz”之类的路径中代表什么?
- sql - 如何从 Oracle SQL Developer 中的数据库差异中排除 ISEQ$$ 值?
- angular - 如何根据单元格中的值更改 mat-table 中 mat-icon 的颜色
- python - 为什么我的基本指数函数不起作用?
- github - 如何让我的 Heroku 应用程序可供拥有该链接的其他人查看?
- regex - 如何在提供值之前删除所有内容