【已解决】Calling View methods on another thread than the UI thread.

本文介绍了一种在Android 4.4及以上版本中解决WebView使用过程中出现的问题的方法。通过将可能引发错误的代码段置于主线程中运行,可以避免一些由于非主线程操作UI组件导致的异常。

把你报错的代码行执行在主线程

runOnUiThread(new Runnable() {
    @Override
    public void run() {
        //你的报错代码
    }
});
在4.4之后WebView的使用有点改动

在 Android 开发中,`CalledFromWrongThreadException` 是由于非主线程尝试更新 UI 所引发的异常。Android 的 UI 组件(如 `TextView`、`ListView` 等)不是线程安全的,因此必须确保所有与 UI 相关的操作都在主线程中执行[^1]。 ### 异常原理 每个 `ViewRootImpl` 在创建时会记录创建它的线程(即主线程),并将其保存在 `mThread` 成员变量中。当视图需要重绘或布局更新时,系统会调用 `checkThread()` 方法验证当前线程是否是原始线程。如果不是,则抛出 `CalledFromWrongThreadException` 异常[^2]。 ```java void checkThread() { if (mThread != Thread.currentThread()) { throw new CalledFromWrongThreadException( "Only the original thread that created a view hierarchy can touch its views."); } } ``` ### 解决方案 #### 使用 `runOnUiThread` 适用于 Activity 中从子线程切换回主线程进行 UI 更新: ```java new Thread(new Runnable() { @Override public void run() { // 后台操作 final String result = fetchData(); runOnUiThread(new Runnable() { @Override public void run() { textView.setText(result); } }); } }).start(); ``` #### 使用 `Handler` 通过绑定主线程的 `Looper` 创建 `Handler`,将任务发布到主线程的消息队列中: ```java Handler handler = new Handler(Looper.getMainLooper()); new Thread(new Runnable() { @Override public void run() { String data = fetchData(); handler.post(new Runnable() { @Override public void run() { textView.setText(data); } }); } }).start(); ``` #### 使用 `View.post(Runnable)` 每个 `View` 都提供 `post()` 方法,它会将任务提交到与该视图关联的主线程消息队列中: ```java new Thread(new Runnable() { @Override public void run() { String data = fetchData(); textView.post(new Runnable() { @Override public void run() { textView.setText(data); } }); } }).start(); ``` #### 使用 `AsyncTask`(已弃用) 虽然 `AsyncTask` 已被弃用,但在旧项目中仍常见。其 `onPostExecute()` 方法运行在主线程,适合更新 UI: ```java new AsyncTask<Void, Void, String>() { @Override protected String doInBackground(Void... voids) { return fetchData(); } @Override protected void onPostExecute(String result) { textView.setText(result); } }.execute(); ``` #### 使用 Kotlin 协程 在 Kotlin 项目中,可以使用协程来简化线程管理,通过 `Dispatchers.Main` 确保 UI 操作在主线程执行: ```kotlin GlobalScope.launch(Dispatchers.IO) { val result = fetchData() withContext(Dispatchers.Main) { textView.text = result } } ``` #### 使用 `LiveData` 和 `ViewModel` 适用于 MVVM 架构,通过观察数据变化自动在主线程回调: ```java viewModel.getData().observe(this, new Observer<String>() { @Override public void onChanged(String s) { textView.setText(s); } }); ``` --- ### 最佳实践建议 - **避免直接在子线程中操作 UI**:这是导致异常的根本原因。 - **统一使用异步通信机制**:如 `Handler`、`Runnable`、`LiveData`、协程等。 - **合理使用架构组件**:如 `ViewModel` 和 `LiveData` 可以帮助更好地管理生命周期和线程安全。 - **测试多线程逻辑**:确保所有 UI 更新都在主线程中执行。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值