非ui线程更新ui问题

android初学者,刚开始并没有意识到,android中更新UI只能用UI线程,写了一个下载线程,在线程里更新progessbar,并用textview显示下载进度

public void listenProgress(){ 
        new Thread(new Runnable() { 
             
            @Override 
            public void run() { 
                while(progress < MsgService.MAX_PROGRESS){ 
                    progress = msgService.getProgress();  
                    progressbar.setProgress(progress); 
                    text.setText("下载" + progress + "%");
                    try { 
                        Thread.sleep(1000); 
                    } catch (InterruptedException e) { 
                        e.printStackTrace(); 
                    } 
                    //text.setText("下载" + progress + "%");
                } 
                 
            } 
        }).start(); 
    }

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

后来才意识到,在非ui线程里不能直接更新ui。子线程中数据发生改变来更新主线程的ui,一般是通过消息机制,message和handler结合的方式。

但是,我继续测试发现,把TextView更新注释掉(//text.setText("下载" + progress + "%");),就没有上面报错,运行后progress能正常更新。

android里面的准则是非ui线程是不能去修改ui线程里面的ui控件的, 但是为什么不在主线程调用setProgress 方法没有报错呢,查看源代码可以发现,setProgress 会调用到private synchronized void refreshProgress(int id, int progress, boolean fromTouch) 方法,首先会判断当前线程是否为主UI线程,若是主UI线程则直接调用 doRefreshProgress 方法更新进度;若不是主UI线程则会先创建一个RefreshProgressRunnable 对象,然后调用 view 的 post(Runnable action) 方法,将 RefreshProgressRunnable 放到主UI线程的消息队列等待处理。从表面上看似乎是在非UI线程里面去修改了主线程的控件,而实际上并非这样。同理,SeekBar、ProgressDialog 也是可以在子线程直接更新进度的。

参考博客:http://blog.csdn.net/androidzhaoxiaogang/article/details/8136222

参考源码:

private synchronized void refreshProgress(int id, int progress, boolean fromTouch) {
        if (mUiThreadId == Thread.currentThread().getId()) {
            doRefreshProgress(id, progress, fromTouch);
        } else {
            RefreshProgressRunnable r;
            if (mRefreshProgressRunnable != null) {
                // Use cached RefreshProgressRunnable if available
                r = mRefreshProgressRunnable;
                // Uncache it
                mRefreshProgressRunnable = null;
                r.setup(id, progress, fromTouch);
            } else {
                // Make a new one
                r = new RefreshProgressRunnable(id, progress, fromTouch);
            }
            post(r);
        }
    }

时间: 2024-11-08 19:51:34

非ui线程更新ui问题的相关文章

Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面

Android应用的开发过程中需要把繁重的任务(IO,网络连接等)放到其他线程中异步执行,达到不阻塞UI的效果. 下面将由浅入深介绍Android进行异步处理的实现方法和系统底层的实现原理. 本文介绍Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面: 即如何使用Thread+Handler的方式从非UI线程发送界面更新消息到UI线程. 概述:每个Android应用程序都运行在一个dalvik虚拟机进程中,进程开始的时候会启动一个主线程(MainThread),

学习通过Thread+Handler实现非UI线程更新UI组件

[Android线程机制] 出于性能考虑,Android的UI操作并不是线程安全的,这就意味着如果有多个线程并发操作UI组件,可能导致线程安全问题.为了解决这个问题,Android制定了一条简单的规则:只允许UI线程修改Activity里的UI组件 当一个程序第一次启动时,Android会同时启动一条主线程(Main Thread),主线程主要负责处理与UI相关的事件,如用户的按键事件,用户接触屏幕的事件及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理.所以主线程通常又被叫做UI线程 [H

Android异步处理系列文章四篇之一使用Thread+Handler实现非UI线程更新UI界面

目录: Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面Android异步处理二:使用AsyncTask异步更新UI界面Android异步处理三:Handler+Looper+MessageQueue深入详解Android异步处理四:AsyncTask的实现原理 Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面 概述:每个Android应用程序都运行在一个dalvik虚拟机进程中,进程开始的时候会启动一个主线程(MainTh

学习通过Thread+Handler实现非UI线程更新UI组件(转)

[Android线程机制] 出于性能考虑,Android的UI操作并不是线程安全的,这就意味着如果有多个线程并发操作UI组件,可能导致线程安全问题.为了解决这个问题,Android制定了一条简单的规则:只允许UI线程修改Activity里的UI组件 当一个程序第一次启动时,Android会同时启动一条主线程(Main Thread),主线程主要负责处理与UI相关的事件,如用户的按键事件,用户接触屏幕的事件及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理.所以主线程通常又被叫做UI线程 [H

Android异步机制一:使用Thread+Handler实现非UI线程更新UI界面

概述:每个Android应用程序都运行在一个dalvik虚拟机进程中,进程开始的时候会启动一个主线程(MainThread),主线程负责处理和ui相关的事件,因此主线程通常又叫UI线程.而由于Android采用UI单线程模型,所以只能在主线程中对UI元素进行操作.如果在非UI线程直接对UI进行了操作,则会报错: CalledFromWrongThreadException only the original thread that created a view hierarchy can tou

Android非UI线程更新UI的几种方法

Android用于实现非UI线程与UI线程的交互方法如下: 1.Handler 2.Activity.runOnUIThread(Runnable) 3.View.Post(Runnable) 4.View.PostDelayed(Runnabe,long) 5.AsyncTask

非UI线程更新UI!?

今天晚上被弟弟告知他在子线程中更新了UI,问我是不是版本的问题,我果断说是他的代码写错了,不过分分钟被打脸,经过我一番仔细的探查最终发现了原因,或许这件事的结果不是多么的重要,但是我认为探查的过程还是有一定的参考价值的. 首先,遇见这种问题时下意识的是去google,所以我采取了下面的措施(请忽视我不堪入目的英语,相信google的强大-.) 然而我发现我并没有得到我想要的结果,大部分的答案是告诉我如何在子线程中转到主线程中更新UI,好吧,难道是我不应该用?号,所以,我做了下面的事. 可悲的是g

安卓 异步线程更新Ui

异步跟新UI: 1.handler+Thread(runnable):如果handler和Thread都写在了一个Java文件中,就不说了,如果runnable定义在了一个单独的类文件中,可以通过在构造方法里接收handler参数,然后执行完耗时操作后,通过handler发送消息来通知主UI线程更新UI 2.接口回调,定义一个接口,然后在主UI执行耗时操作的时候,借助匿名内部类,在这里写异步线程返回来的数据处理操作,异步线程接收一个匿名的内部类实例,然后在执行完耗时操作后回调接口的方法,可以把耗

android中子线程更新UI的方式浅析

一.为何写作此文 ??你是不是经常看到很多书籍中说:不能在子线程中操作ui,不然会报错.你是不是也遇到了如下的疑惑(见下面的代码): @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv = (TextView) findViewById(R.id.tv); Threa