`
devil587
  • 浏览: 5117 次
  • 性别: Icon_minigender_2
  • 来自: 杭州
最近访客 更多访客>>
社区版块
存档分类
最新评论

Android UI线程和非UI线程

 
阅读更多
UI线程及Android的单线程模型原则

  当应用启动,系统会创建一个主线程(main thread)。

  这个主线程负责向UI组件分发事件(包括绘制事件),也是在这个主线程里,你的应用和Android的UI组件(components from the Android UI toolkit (components from the android.widget and android.view packages))发生交互。

  所以main thread也叫UI thread也即UI线程。



  系统不会为每个组件单独创建线程,在同一个进程里的UI组件都会在UI线程里实例化,系统对每一个组件的调用都从UI线程分发出去。

  结果就是,响应系统回调的方法(比如响应用户动作的onKeyDown()和各种生命周期回调)永远都是在UI线程里运行。



  当App做一些比较重(intensive)的工作的时候,除非你合理地实现,否则单线程模型的performance会很poor。

  特别的是,如果所有的工作都在UI线程,做一些比较耗时的工作比如访问网络或者数据库查询,都会阻塞UI线程,导致事件停止分发(包括绘制事件)。对于用户来说,应用看起来像是卡住了,更坏的情况是,如果UI线程blocked的时间太长(大约超过5秒),用户就会看到ANR(application not responding)的对话框。

  另外,Andoid UI toolkit并不是线程安全的,所以你不能从非UI线程来操纵UI组件。你必须把所有的UI操作放在UI线程里,所以Android的单线程模型有两条原则:

  1.不要阻塞UI线程。

  2.不要在UI线程之外访问Android UI toolkit(主要是这两个包中的组件:android.widget and android.view)。


使用Worker线程

  根据单线程模型的两条原则,首先,要保证应用的响应性,不能阻塞UI线程,所以当你的操作不是即时的那种(not instantaneous),你应该把他们放进单另的线程中(叫做background或者叫worker线程)。

  比如点击按钮后,下载一个图片然后在ImageView中展示:
复制代码

public void onClick(View v) {
    new Thread(new Runnable() {
        public void run() {
            Bitmap b = loadImageFromNetwork("http://example.com/image.png");
            mImageView.setImageBitmap(b);
        }
    }).start();
}

复制代码



  这段代码用新的线程来处理网络操作,但是它违反了第二条原则:

  Do not access the Android UI toolkit from outside the UI thread.

  从非UI线程访问UI组件会导致未定义和不能预料的行为。



  为了解决这个问题,Android提供了一些方法,从其他线程访问UI线程:

    Activity.runOnUiThread(Runnable)
    View.post(Runnable)
    View.postDelayed(Runnable, long)



  比如,上面这段代码可以这么改:
复制代码

public void onClick(View v) {
    new Thread(new Runnable() {
        public void run() {
            final Bitmap bitmap = loadImageFromNetwork("http://example.com/image.png");
            mImageView.post(new Runnable() {
                public void run() {
                    mImageView.setImageBitmap(bitmap);
                }
            });
        }
    }).start();
}

复制代码



  这么改之后就是线程安全的了。

  但是,当操作变得复杂的时候,这种代码会变得非常复杂,为了处理非UI线程和UI线程之间更加复杂的交互,可以考虑在worker线程中使用一个Handler,来处理UI线程中传来的消息。

  也可以继承这个类AsyncTask 。


Communicating with the UI Thread

  只有在UI线程中的对象才能操作UI线程中的对象,为了将非UI线程中的数据传送到UI线程,可以使用一个 Handler运行在UI线程中。

  Handler是Android framework中管理线程的部分,一个Handler对象负责接收消息然后处理消息。

  你可以为一个新的线程创建一个Handler,也可以创建一个Handler然后将它和已有线程连接。

  如果你将一个Handler和你的UI线程连接,处理消息的代码就将会在UI线程中执行。



  可以在你创建线程池的类的构造方法中实例化Handler的对象,然后用全局变量存储这个对象。

  要和UI线程连接,实例化Handler的时候应该使用Handler(Looper) 这个构造方法。

  这个构造方法使用了一个 Looper 对象,这是Android系统中线程管理的framework的另一个部分。

  当你用一个特定的 Looper实例来创建一个 Handler时,这个 Handler就运行在这个 Looper的线程中。



  在Handler中,要覆写handleMessage() 方法。Android系统会在Handler管理的相应线程收到新消息时调用这个方法。

  一个特定线程的所有Handler对象都会收到同样的方法。(这是一个“一对多”的关系)。


参考资料

  官方Training: 与UI线程通信:

  http://developer.android.com/training/multiple-threads/communicate-ui.html

  Guides: Processes and Threads

  http://developer.android.com/guide/components/processes-and-threads.html



  类参考:

  http://developer.android.com/reference/android/os/Looper.html

  http://developer.android.com/reference/android/os/Handler.html

  http://developer.android.com/reference/android/os/HandlerThread.html



  博客:

  Android的线程使用来更新UI----Thread、Handler、Looper、TimerTask等:

  http://www.cnblogs.com/playing/archive/2011/03/24/1993583.html
分享到:
评论

相关推荐

    Xamarin.Android 非UI线程更新UI

    如果在非UI线程中直接修改UI元素,系统会抛出`Android.Content.ReceiverNotRegisteredException`或`Java.Lang.RuntimeException: Only the original thread that created a view hierarchy can touch its views.`...

    android UI线程和后台交互实例

    android UI线程和后台线程交互,包括多线程之AsyncTask等例子展示。。。。。。。。。。。

    Android-dialog库可以在任意类内调用子线程或ui线程内均可显示

    标题提到的“Android-dialog库”是Android开发中的一个第三方库,它提供了一种灵活的方式,使得开发者能够在任意类中方便地调用Dialog,并且支持在子线程或UI线程内显示,这极大地提高了代码的可复用性和执行效率。...

    UI 线程 和 工作线程 的实现

    在计算机编程中,尤其是开发图形用户界面(GUI)应用程序时,UI线程(用户界面线程)和工作线程的概念至关重要。UI线程是应用程序的主要线程,负责处理与用户交互相关的所有事件,如鼠标点击、键盘输入以及窗口的...

    010_android 之UI线程阻塞及其优化

    在Android开发中,UI线程,也被称为主线程,是负责处理用户交互和绘制界面的线程。当UI线程被阻塞时,应用程序将变得无响应,这可能导致用户界面冻结,严重影响用户体验。本视频教程“010_android 之UI线程阻塞及其...

    android 更新 UI 线程 handler

    在Android开发中,更新UI(用户界面)是一个常见的任务,但是由于Android的主线程(也称为UI线程)是负责处理用户交互和绘制界面的,所以直接在后台线程进行UI更新可能会导致程序崩溃或者界面卡顿。为了解决这个问题...

    无界面的UI线程交互

    而在Android中,通常会使用Handler, MessageQueue和Looper的组合来实现UI线程与工作线程之间的通信。 具体步骤如下: 1. **创建后台线程**:首先,我们需要创建一个无界面的UI线程,它会在后台运行,执行计算或其他...

    UI线程

    通过阅读Android系统的源码,我们可以发现`Looper`、`Handler`和`MessageQueue`这三者在UI线程中起着核心作用。`Looper`循环地从`MessageQueue`中取出`Message`,然后交给`Handler`来处理。当需要更新UI时,我们通常...

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

    ### Android异步处理详解:使用Thread+Handler实现非UI线程更新UI界面 #### 概述 Android系统中,每一个应用程序都运行在一个独立的Dalvik虚拟机进程中。当应用程序启动时,系统会创建一个主线程(MainThread),也...

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

    为了解决这个问题,Android提供了多种异步处理机制,其中一种常见的方式是使用`Thread`配合`Handler`来实现非UI线程执行耗时任务并更新UI。本篇将详细介绍这一方法。 首先,我们需要理解Android的线程模型。Android...

    WinForm后台线程与UI线程通讯

    由于.NET Framework的安全机制,直接在非UI线程修改UI组件可能会导致线程不安全的问题,因此需要正确地进行线程间通信。本文将详细探讨如何在WinForm应用中实现在后台线程与UI线程之间的通信,并确保UI更新的安全。 ...

    安卓UI线程和子线程通讯更新UI实例

    在Android应用开发中,UI线程(也称为主线程)负责处理用户交互和绘制界面,而子线程通常用于执行耗时操作,如网络请求、数据处理等。由于Android系统的安全机制,直接在子线程中修改UI是不允许的,因此我们需要通过...

    工作线程 UI线程实例

    现在,我们通过一个简单的Android应用实例来说明如何使用工作线程和UI线程。假设我们有一个按钮,当用户点击时,应用会从网络上下载一张图片并显示在界面上。 1. **UI线程操作**: - 创建一个布局文件,包含一个...

    MFC UI 线程的使用

    为了保证UI的响应性和一致性,通常不建议在非UI线程中直接修改UI组件的状态。因此,我们需要一种机制来安全地在不同线程之间传递消息。 这就引出了ON_THREAD_MESSAGE宏。ON_THREAD_MESSAGE是MFC提供的一种机制,...

    安卓UI线程机制 ,在子线程中访问UI

    1. 不允许直接操作:默认情况下,Android不允许在非UI线程中直接修改UI组件,因为这可能导致UI不一致和应用崩溃。Android的UiThread StrictMode策略会检测到这种行为并抛出异常。 2. 使用Handler:为了在子线程中...

    android 通过服务线程改变ui

    然而,直接在非UI线程中修改UI组件(如ImageView)是不允许的,因为Android的UI工具包不是线程安全的。为了解决这个问题,Android提供了几种同步机制: 1. `Activity.runOnUiThread(Runnable)`:允许在UI线程中执行...

    android 多线程 下载 更新 ui 例子

    本示例"android 多线程 下载 更新 ui 例子"旨在教你如何在Android环境中使用多线程进行文件下载,并实时更新UI来显示下载进度。 在Android主线程中,我们不能执行长时间运行的任务,因为这会导致应用程序无响应...

    Android中UI线程与后台线程交互的探讨.pdf

    总之,理解和熟练掌握Android中的UI线程与后台线程交互机制,对于开发高效、用户体验良好的Android应用程序至关重要。通过Handler和AsyncTask,开发者可以优雅地处理耗时操作,同时保持用户界面的响应性和流畅性。

Global site tag (gtag.js) - Google Analytics