Only the original thread that created a view hierarchy can touch its views

Android 解决 Only the original thread that created a view hierarchy can touch its views问题 解决 Only the original thread that created a view hierarchy can touch its views问题 阅读详情

推荐必看:https://blog.youkuaiyun.com/persistencegoing/article/details/84376427

 

解决Only the original thread that created a view hierarchy can touch its views

很多网友在Android中使用多线程处理UI相关内容时可能会发现Logcat提示Only the original thread that created a view hierarchy can touch its views这样的错误,这主要是Android的相关View和控件不是线程安全的,我们必须做独立的处理这点比J2ME麻烦一些,这里Android给 我们提供了很多方法,有关线程的,我们需要了解下J2ME中一些传统的线程创建方法,比如Runnable或直接new Thread(),大家需要了解UI线程、worker线程以及一些概念。今天android开发网说一种简单的方法除了异步任务AsyncTask外使 用Handler可以很好的处理,和Win32的消息很像。

  首先我们需要明白,主线程或者这里说的原始线程original thread 一般情况下是UI线程,当然UI线程并不一定是主线程,我们不能长时间的阻塞该应用,在Android平台上可能会产生类似Force close或Wait这样的对话框这里我们成为ANR,这里除了使用ProgressDialog方式给用一个动态的进度代表当前处理并没有中断可能需要 一些时间,所以android123告诉大家相关的网络处理可以使用工作者线程,但是worker 线程不能处理显示元素即UI相关的View或 Widget包中的高层的控件,所以通过一个Handler对象可以很好的传递Runnable或Message ,下面我们用一个简单的例子来描述

  final Handler cwjHandler = new Handler();

   final Runnable mUpdateResults = new Runnable() {
        public void run() {
            updateUI();
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

     NetworkOperation();//一个很费时间的I/O操作,比如网络或文件读写等等。

      }

    protected void NetworkOperation() {

        Thread t = new Thread() {
            public void run() {
                doSomething(); //处理得到结果了,这里一些内容保存在主类的成员变量中
                cwjHandler.post(mUpdateResults); //高速UI线程可以更新结果了
            }
        };
        t.start();
    }

    private void updateUI() {

    //详细的更新
    }

  有关Java以及Android的线程,我们将在以后的内容中介绍到,本次相关内容讲到这些,以后我们会告诉大家一些线程同步以及死锁问题的解决方法,总体而言感觉相对于Windows Mobile平台,Android上的线程消耗过大,而Symbian的活动对象又相对保守,总的而言Android线程相对简单


在分析Android消息机制之前,我们先来看一段代码: 

[html] view plaincopyprint?
public class MainActivity extends Activity implements View.OnClickListener {  
      
    private TextView stateText;  
    private Button btn;  
      
    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
        stateText = (TextView) findViewById(R.id.tv);  
        btn = (Button) findViewById(R.id.btn);  
          
        btn.setOnClickListener(this);  
    }  
  
    @Override  
    public void onClick(View v) {  
        new WorkThread().start();  
    }  
      
    //工作线程  
    private class WorkThread extends Thread {  
        @Override  
        public void run() {  
            //......处理比较耗时的操作  
              
            //处理完成后改变状态  
            stateText.setText("completed");  
        }  
    }  
}  
这段代码似乎看上去很正常,但是当你运行时就会发现,它会报一个致命性的异常:

[html] view plaincopyprint?
ERROR/AndroidRuntime(421): FATAL EXCEPTION: Thread-8  
ERROR/AndroidRuntime(421): android.view.ViewRoot$CalledFromWrongThreadException:   
Only the original thread that created a view hierarchy can touch its views.  

 

到底是怎么回事呢?原因在于,Android系统中的视图组件并不是线程安全的,如果要更新视图,必须在主线程中更新,不可以在子线程中执行更新的操作。

既然这样,我们就在子线程中通知主线程,让主线程做更新操作吧。那么,我们如何通知主线程呢?我们需要使用到Handler对象。

我们稍微修改一下上面的代码:

[html] view plaincopyprint?
public class MainActivity extends Activity implements View.OnClickListener {  
      
    private static final int COMPLETED = 0;  
      
    private TextView stateText;  
    private Button btn;  
      
    private Handler handler = new Handler() {  
        @Override  
        public void handleMessage(Message msg) {  
            if (msg.what == COMPLETED) {  
                stateText.setText("completed");  
            }  
        }  
    };  
      
    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
        stateText = (TextView) findViewById(R.id.tv);  
        btn = (Button) findViewById(R.id.btn);  
          
        btn.setOnClickListener(this);  
    }  
  
    @Override  
    public void onClick(View v) {  
        new WorkThread().start();  
    }  
      
    //工作线程  
    private class WorkThread extends Thread {  
        @Override  
        public void run() {  
            //......处理比较耗时的操作  
              
            //处理完成后给handler发送消息  
            Message msg = new Message();  
            msg.what = COMPLETED;  
            handler.sendMessage(msg);  
        }  
    }  
}  

 

通过上面这种方式,我们就可以解决线程安全的问题,把复杂的任务处理工作交给子线程去完成,然后子线程通过handler对象告知主线程,由主线程更新视图,这个过程中消息机制起着重要的作用。

下面,我们就来分析一下Android中的消息机制。

 

熟悉Windows编程的朋友知道Windows程序是消息驱动的,并且有全局的消息循环系统。Google参考了Windows的消息循环机制,也在Android系统中实现了消息循环机制。Android通过Looper、Handler来实现消息循环机制。Android的消息循环是针对线程的,每个线程都可以有自己的消息队列和消息循环。

Android系统中的Looper负责管理线程的消息队列和消息循环。通过Looper.myLooper()得到当前线程的Looper对象,通过Looper.getMainLooper()得到当前进程的主线程的Looper对象。

前面提到,Android的消息队列和消息循环都是针对具体线程的,一个线程可以存在一个消息队列和消息循环,特定线程的消息只能分发给本线程,不能跨线程和跨进程通讯。但是创建的工作线程默认是没有消息队列和消息循环的,如果想让工作线程具有消息队列和消息循环,就需要在线程中先调用Looper.prepare()来创建消息队列,然后调用Looper.loop()进入消息循环。下面是我们创建的工作线程:

[html] view plaincopyprint?
class WorkThread extends Thread {  
      public Handler mHandler;  
  
      public void run() {  
          Looper.prepare();  
  
          mHandler = new Handler() {  
              public void handleMessage(Message msg) {  
                  // 处理收到的消息  
              }  
          };  
  
          Looper.loop();  
      }  
  }  

 

这样一来,我们创建的工作线程就具有了消息处理机制了。

那么,为什么前边的示例中,我们怎么没有看到Looper.prepare()和Looper.loop()的调用呢?原因在于,我们的Activity是一个UI线程,运行在主线程中,Android系统会在Activity启动时为其创建一个消息队列和消息循环。

前面提到最多的是消息队列(MessageQueue)和消息循环(Looper),但是我们看到每个消息处理的地方都有Handler的存在,它是做什么的呢?Handler的作用是把消息加入特定的Looper所管理的消息队列中,并分发和处理该消息队列中的消息。构造Handler的时候可以指定一个Looper对象,如果不指定则利用当前线程的Looper对象创建。下面是Handler的两个构造方法:

[html] view plaincopyprint?
/**  
     * Default constructor associates this handler with the queue for the  
     * current thread.  
     *  
     * If there isn't one, this handler won't be able to receive messages.  
     */  
    public Handler() {  
        if (FIND_POTENTIAL_LEAKS) {  
            final Class<? extends Handler> klass = getClass();  
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&  
                    (klass.getModifiers() & Modifier.STATIC) == 0) {  
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +  
                    klass.getCanonicalName());  
            }  
        }  
  
        mLooper = Looper.myLooper();  
        if (mLooper == null) {  
            throw new RuntimeException(  
                "Can't create handler inside thread that has not called Looper.prepare()");  
        }  
        mQueue = mLooper.mQueue;  
        mCallback = null;  
    }  
  
/**  
     * Use the provided queue instead of the default one.  
     */  
    public Handler(Looper looper) {  
        mLooper = looper;  
        mQueue = looper.mQueue;  
        mCallback = null;  
    }  

 

下面是消息机制中几个重要成员的关系图:

一个Activity中可以创建出多个工作线程,如果这些线程把他们消息放入Activity主线程的消息队列中,那么消息就会在主线程中处理了。因为主线程一般负责视图组件的更新操作,对于不是线程安全的视图组件来说,这种方式能够很好的实现视图的更新。

那么,子线程如何把消息放入主线程的消息队列中呢?只要Handler对象以主线程的Looper创建,那么当调用Handler的sendMessage方法,系统就会把消息主线程的消息队列,并且将会在调用handleMessage方法时处理主线程消息队列中的消息。

对于子线程访问主线程的Handler对象,你可能会问,多个子线程都访问主线程的Handler对象,发送消息和处理消息的过程中会不会出现数据的不一致呢?答案是Handler对象不会出现问题,因为Handler对象管理的Looper对象是线程安全的,不管是添加消息到消息队列还是从消息队列中读取消息都是同步保护的,所以不会出现数据不一致现象。

深入理解Android消息处理机制对于应用程序开发非常重要,也可以让我们对线程同步有更加深刻的认识,希望这篇文章可以对朋友们有所帮助。



原文链接:https://blog.youkuaiyun.com/breeze666/article/details/7570914

开新线程引发的常见3个异常 开一个新线程,引起的异常。1. ANR: application not responding 2.android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. 3.java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() 立即下载

相关推荐

Android studio :后台修改前台界面Only the original thread that created a view hierarchy can touch its views

Only the original thread that created a view hierarchy can touch its views 这句话的意思是:只有创建这个view的线程才能操作这个view 解决方法就是handle 1、 Handler mHandler; 2、 mHandler = new Handler();//创建Handler 3、 //放在主线程或新开线程都可以 Runnable mRunnable0 = new Runnable(){ @Override public void run() { // TODO Au

Only the original thread that created a view hierarchy can touch its views.

场景: 项目开发中会涉及到一些耗时操作,这个时候就会开启一个子线程,将耗时操作放到子线程中取操作,操作完毕后,往往还要同步更新ui,这个时候如果直接在子线程中更新ui,将会导致程序的闪退,同时还会看到 android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a

wangwo1991的博客 8195

魔百和CM211-1刷Armbian全流程:从安卓盒子到Linux服务器的完美变身

本文详细介绍了如何将魔百和CM211-1机顶盒刷入Armbian系统,实现从安卓盒子到Linux服务器的完美变身。涵盖硬件兼容性验证、固件选择、刷机流程、系统优化及常见问题解决,特别适合技术爱好者低成本搭建家庭NAS或开发环境。

weixin_30329623的博客 238

解决Only the original thread that created a view hierarchy can touch its views

Only the original thread that created a view hierarchy can touch its views 出现原因:回调接口在子线程,并在回调接口对UI进行了操作 所以,将会出现上述提示 一般来讲,会使用handle解决这个问题 在对应的回调接口根据网络请求返回的数据来传递不同的消息 handler.sendMessage(msg); 再根据消息的内容...

i_nclude的博客 3万+

K2P padavan固件下宽带与IPTV融合

举例说下,假如你的IPTV是拨号的,IPTV端口直接连到笔记本电脑的网口,IP是自动分配的情况下,在VLC里面是可以直接播放“rtp://239.XXX.XXX.XXX:XXXX”的,即使IPTV是DHCP模式,按道理也是可以播放的。家里很少看电视,基本上就是看看春晚,然后平时老人在家没事看看,所以就把广电的机顶盒停掉了,换了一个N1的盒子刷了CoreELEC系统,既可以通过m3u8文件看网络电视,也可以看本地的多媒体,很方便,完全满足了自己的需求。在上图的第三步中,端口设置成大于1024的端口即可。

aplsc的专栏 63万+

2025-08-19利用opencv检测图片中文字及图片的坐标

该代码实现了图片中中文文本的检测与位置计算功能。主要使用CnOcr库进行OCR识别,结合OpenCV和PIL库处理图像。功能包括:1)检测图片中的中文文本及位置坐标;2)计算每个文本的像素宽度和高度;3)在原图上绘制文本边界框并标注识别结果。代码通过put_chinese_text函数解决中文显示问题,最终输出各文本内容、坐标位置及尺寸信息。适用于需要获取图片中文字精确位置的应用场景。

m0_58149406的博客 395

Only the original thread that created a view hierarchy can touch its views错误

Only the original thread that created a view hierarchy can touch its views错误

码夫的专栏 3195

机器人控制基础:电机编码器常见类型

电机编码器是测量电机位置、速度和方向的传感器,主要分为光电、磁性和旋转变压器三类。光电编码器精度高但需防尘,适用于伺服系统;磁性编码器耐环境性强,常用于汽车电机;旋转变压器适应极端环境,多用于军工领域。按信号类型可分为增量式(成本低)和绝对式(断电保留位置)。选型需综合考虑精度、环境适应性及成本。

start_up_go的博客 475

错误:Only the original thread that created a view hierarchy can touch its views——Handler的使用

今天写了一个更新UI的小例子,没想到出了log打印了这样一个错误:Only the original thread that created a view hierarchy can touch its views。goolgle了一下找到了原因。原来android中相关的view和控件不是线程安全的,我们必须单独做处理。这里借此引出Handler的使用。  Handler的官方描述:A Handler allows you to send and process Message and Runnable

djx123456的专栏 15万+

STM32(HAL库)软件IIC驱动OLED

本文通过STM32F103C8T6单片机(HAL库)通过软件IIC方式对OLED进行驱动。

weixin_44597885的博客 9761

基于C++和Basler SDK的相机开发详解

Basler相机是德国Basler公司生产的高性能工业相机,具有高分辨率、高帧率和低噪声的特点。Basler相机广泛应用于机器视觉、工业自动化、医疗影像和安防监控等领域。高分辨率和高帧率:能够捕捉清晰、细腻的图像。多种接口:支持USB、GigE、Camera Link等多种接口,方便不同应用场景的需求。丰富的配置选项:支持多种图像格式、分辨率和帧率的配置,适应不同的应用需求。本文详细介绍了如何基于C++和Basler SDK进行相机开发,涵盖了从环境搭建、相机连接、图像采集到图像处理的完整过程。

qq_38334677的博客 2099

android开发 bug问题解决:Only the original thread that created a view hierarchy can touch its views

android开发 bug问题解决:Only the original thread that created a view hierarchy can touch its views. 翻译:只有创建视图层次结构的原始线程才能触及其视图。(意思就是在异步线程中不能更新主线程UI) 解决办法之一 创建一个handler去更新UI线程 代码实现 1、handler处理返回数据请求,并更新数据到...

七夜的博客 5287

【论文硬核拆解】Ctx2Skill:让大模型自己跟自己玩,从上下文里「进化」出可复用技能

论文选择自然语言技能可解释性:技能是人类可读的 Markdown 文件,可以审查、编辑、调试可迁移性:即插即用,从一个模型到另一个模型无需参数访问:对闭源模型友好这比 SKILL0/SkillRL 等参数内化方法更实用,尤其是在商业 API 场景。

步子哥的博客 153

错误:Only the original thread that created a view hierarchy can touch its views.

错误信息“Only the original thread that created a view hierarchy can touch its views”在Android开发中通常表示,只有创建视图层次结构的原始线程才能操作这些视图。请记住,始终在主线程上执行UI操作,以避免出现此错误。如果你正在使用自定义视图或不在Activity或Fragment中的视图层次结构,你可能需要使用Handler或类似机制来确保更新被发布到主线程。

weixin_56334892的博客 1248

YOLOv8改进 | Conv篇 | 利用YOLO-MS的MSBlock轻量化网络结构(既轻量又长点)

本文给大家带来的改进机制是利用YOLO-MS提出的一种针对于实时目标检测的MSBlock模块,我们将其用于C2f中组合出一种新的结构,来替换我们网络中的模块可以达到一种轻量化的作用,我将其用于我的数据集上实验,包括多个类别的数据集,其在轻量网络结构的同时,却能够提高一定的mAP精度,所以这是一种十分高效的模块,该网络结构非常适合那些模型精度已经无法提到,想要从轻量化模型的角度入手的读者使用。欢迎大家订阅本专栏,本专栏每周更新3-5篇最新机制,更有包含我所有改进的文件和交流群提供给大家。

Snu77的博客 6094

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

在工作线程中处理UI线程报错:Only the original thread that created a view hierarchy can touch its views.

如果将更新UI控件的代码写入到工作线程中便会报错, 例子如下: Runnable socketRun = new Runnable() { @Override public void run() { // TODO Auto-generated method stub tv = (TextView) findViewById(R.id.tv); Soc

shenyuemei的专栏 2万+

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

Android单元测试 Only the original thread that created a view hierarchy can touch its views.

Only the original thread that created a view hierarchy can touch its views.

zhjali123的专栏 1180

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Only the original thread that created a view hierarchy can touch its views:

报错:Only the original thread that created a view hierarchy can touchits views:        原因:在非主线程中了进行了操作UI线程(主线程)中比如:UI更新的操作。导致的报错        解决方法:使用handler 或者asynctask等方法

奋斗的IT小民工的博客 1576

Android Only the original thread that created a view hierarchy can touch its views.

解决方法 :

爱孔孟 2738

android子线程控制UI线程,以防:Only the original thread that created a view hierarchy can touch its views.

近段时间比较空闲,也有时间让我自己冲冲电~ 今天和大家分享的是android 中子线程控制UI线程的几个常用方法,因为android是单线程执行的,如果你在子线程中操作有UI线程就会报错了以下错误:Only the original thread that created a view hierarchy can touch its views. 第一种:(简单明了) XXXActivity

Lenny的专栏 865

报错:Only the original thread that created a view hierarchy can touch its views

报错:Only the original thread that created a view hierarchy can touch its views

leveretz的博客 1852
上一篇: socket客户端与服务端正常通信,服务端过了一段时间就接收不到客户端的数据了
下一篇: 电视机观看视频监控,发现视频延迟严重怎么解决
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值