`
huaxin803
  • 浏览: 113365 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Android 进程和线程(二)

 
阅读更多
线程

应用程序启动时,Android系统会给应用程序创建一个叫做“main”的执行线程。这个线程很重要,因为它负责给适当的用户界面窗口调度事件,包括描画事件。它也是你的应用程序与Android UI工具中的组件交互的线程(这些组件来自android.widget和android.view包)。如,“main”线程有时也叫UI线程。

系统不会给每个组件的实例创建一个单独的线程。运行在同一个进程的所有的组件都被实例化在UI线程,并且系统会调用每个由线程调度的组件。因此响应系统回调的方法(如报告用户动作的onKeyDown()方法或一个生命周期的回调方法)始终运行在这个进程的UI线程中。

例如,当用户触摸屏幕上的一个按钮时,你的应用程序的UI线程会调度对应窗口的touch事件,它会依次设置按钮的按下状态,并且把一个有效的请求发送给这个事件队列。UI线程会让请求出队并通知对应的窗口应该重绘自己。

当你的应用程序要在响应用户的交互中执行密集的工作时,除非你正确的实现了应用程序,否则这种单线程模式会降低执行效率。尤其是把每件正在发生的事情都放在UI线程中,如执行像网络访问、数据库查询这样的长时操作将会使整个UI被阻塞。线程被阻塞时,任何事件都不能被调度,包括描画事件。从用户的角度,应用程序似乎被挂起了。甚至更糟,如果UI线程被阻塞几秒钟(大约是5秒钟),用户就会看到臭名昭著的“应用程序没有响应”(ANR)对话框。那么用户就可能决定退出你的应用程序,并且如果他们感觉不好,还会卸载这个应用程序。

另外,Android UI 工具集不是线程安全的。因此你不能由一个工作线程来控制你的UI---你必须用UI线程来对你用户界面进行所有的控制。这样对于Android单线程模式,有以下两个简单的规则:

1.不要阻塞UI线程;

2.不要从UI线程的外部访问Android UI工具集。

工作线程

因为以上介绍的单线程模式的缘故,你的应用程序UI的响应不阻塞UI线程是至关重要的。如果你执行的不是瞬时操作,就应该用一个单独的线程(后台或工作线程)来工作。

例如,一下click监听器的代码就是从一个单独的线程中下载图片,并在一个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();
}

初看以上这段代码,似乎能够很好的工作,因为它为处理网络操作创建了一个新的线程。但是,它违反了单线程模式的第二个规则:不从外部UI线程访问Android UI工具集---这个示例在工作线程中修改了ImageView对象而不是在UI线程中。这样会导致未知的和不确定的异常行为,这对于查找问题是困难和费时的。

要修正这个问题,Android提供了以下几个方法用于从其他线程访问UI线程:

1.Activity.runOnUiThread(Runnable )

2.View.post(Runnable )

3.View.postDelayed(Runnable, long)

例如,你能够通过View.post(Runnable)方法来修改以上代码:

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();
}

现在的这个实现是线程安全的,因为网络操作是在一个单独的线程中完成的,而对ImageView对象的操作则在UI线程中完成。

但是操作的复杂性增加了,这类型的代码使代码的维护变的复杂和困难了。要处理跟工作线程更复杂的交互,你可能考虑在你的工作线程中使用Handler对象,来处理由UI线程发送的消息。继承AsyncTask类可能是最好的解决方案,它简化了工作线程执行需要跟UI交互的任务。

使用AnsyncTask类

AsyncTask类允许你在用户界面上执行异步的工作。它在工作线程中执行一个阻塞操作,然后在UI线程上发布执行结果,不要求你自己来处理线程和/或处理器。

要使用这个类,必须继承AsyncTask类并且实现doInBackground()回调方法,它在后台的线程池中运行。要更新UI,你应该实现onPostExecute()方法,它提供了来自doInBackground()方法的结果,并且在UI线程中运行,因此你能安全的更新你的UI。然后你能够通过execute()方法从UI线程中运行任务。

例如,你能够使用AsyncTask类的方法来实现前面的例子:

public void onClick(View v) {
    new DownloadImageTask().execute("http://example.com/image.png");
}

private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
    /** The system calls this to perform work in a worker thread and
      * delivers it the parameters given to AsyncTask.execute() */
    protected Bitmap doInBackground(String... urls) {
        return loadImageFromNetwork(urls[0]);
    }
    
    /** The system calls this to perform work in the UI thread and delivers
      * the result from doInBackground() */
    protected void onPostExecute(Bitmap result) {
        mImageView.setImageBitmap(result);
    }
}

现在的UI是安全的并且代码也简化了,因为把它把工作分为在工作线程中执行的部分和在UI线程中执行的部分。

要完全理解这个类应该读AsyncTask参考,但是以下可以快速浏览一下这个类的工作方式:

1.你能够指定常用类型的参数,如进度值、任务结束的值;

2.doInBackground()方法在工作线程上自动的执行;

3.onPreExecute()、onPostExecute()、和onProgressUpdate()方法都在UI线程上调用;

4.由doInBackground()方法返回值被发送给onPostExecute()方法

5.你能够在任何时候调用doInBackground()方法中的publishProgress()方法在UI线程上执行onProgressUpdate()方法;

6.你能够在任何时候取消来自任何线程的任务。

警告:当你使用工作线程的Activity由于运行时配置的改变而导致异常重启(如用户改变了屏幕的方向)时,你可能遇到另外一个问题:可能销毁你的工作线程。要了解在Activity重启期间如何保持你的后台任务和在Activity被销毁时如何正确的取消任务等信息,请看Shelves示例应用程序的源代码。(http://code.google.com/p/shelves/

线程安全的方法

在某些情况中,你实现的方法可能可能被多个线程调用,因此,必须要写线程安全的方法。

线程安全主要是针对能够被远程调用的方法---如绑定类型Service中的方法。当IBinder实现类中的一个方法调用源于与IBinder对象运行那个进程时,这个方法就会在调用者的线程中执行。但是,当调用源于另一个进程时,就会从系统维护的与IBinder对象相同的进程那个线程池中选择执行这个方法的线程(不会在进程的UI线程中执行)。如,一个Service的onBind()方法将会被这个Service进程的主线程调用,由onBind()方法返回的对象中实现的方法(如实现RPC方法的一个子类)将会从线程池中调用。因为一个服务能够有多个客户端,多个线程能够同时调用同一个IBinder对象方法,因此IBinder方法必须实现线程安全。

类似地,一个内容提供器能够接受源自其他进程的数据申请。尽管ContentResolver类和ContentProvider类隐藏了如何管理进程进程间通信的细节,但是响应那些请求的ContentProvider方法(query()、insert()、delete()、update()和getType())是从内容提供器进程中的线程池调用的,而不是进程的UI线程。因为这些方法可能同时被多个线程调用,因此它们也必须实现线程安全。

进程间通信

Android使用远程过程调用(RPCs)给进程间通信(IPC)提供了一种机制,在这种机制中一个被Activity或其他应用程序组件调用的方法,不是在本地执行,而是在远程(其他进程)执行,它会给调用者返回一个结果。这就必需把一个方法分解为操作系统层面上能够理解的调用和数据,并且把它从本地进程和地址空间中传递给远程进程和它的地址空间,然后再在调用的地方重新组装和执行。然后把返回值反向传输回来。Android提供了所有的执行这些IPC传输的代码,因此你能够关注RPC编程接口的定义和实现。

要执行IPC,你的应用程序必须使用bindService()方法绑定一个Sevice。

分享到:
评论

相关推荐

    详解Android进程和线程

    Android进程和线程是Android应用程序运行的基础,理解这两个概念对于开发高质量的Android应用至关重要。在Android系统中,每个应用都是一个独立的Linux进程,这意味着它们在各自的沙箱环境中运行,互不影响,提高了...

    Android Task 进程与线程详解

    Android 中的进程和线程概念是紧密相连的,一个进程可以包含多个线程,每个线程都可以执行不同的任务。在 Android 中,进程和线程的概念是动态运行的,会关心 Task 的概念。Task 的概念是 Android 中的主要概念,...

    Android 进程和线程

    在Android系统中,进程和线程是应用程序运行的基础,它们决定了程序如何管理和执行任务。深入理解这两个概念对于优化应用性能、提高用户体验至关重要。 首先,我们要明白什么是进程。在计算机科学中,进程是程序的...

    安卓 进程/线程绑定cpu

    为了确保正确操作,需要熟悉Linux的进程和线程管理知识,以及对Android NDK的使用。 `adb shell ps -t -p -c`是一个用于查看系统中所有进程和线程的命令。`ps`命令列出当前系统的进程状态,`-t`选项表示按线程显示...

    Android进程结束杀掉子线程Demo

    http://blog.csdn.net/qq_28690547/article/details/50375997;关于demo的文章详解,有兴趣的童鞋可以看看,解决popupwindow/dialog的BadTokenException异常

    Android下线程与进程

    在Android系统中,线程(Thread)和进程(Process)是理解应用程序运行机制的关键概念。它们决定了应用如何分配资源和执行任务,对于优化性能、提高用户体验具有重要意义。 **线程** 线程是程序中的执行流,是操作...

    线程和进程的区别,详细解释

    线程进程的区别于联系,详细介绍.希望对大家有用。如果有不足的地方,麻烦留言。

    android 进程与线程 - 开发文档翻译 - 进程.doc

    在Android系统中,进程和线程是应用程序执行的基础。每个应用组件的启动都可能伴随着新进程的创建或已有进程的重用。默认情况下,同一应用的所有组件在同一进程中运行,共享一个主线程。这是因为主线程负责处理用户...

    进程和线程-Android Developers1

    在Android系统中,进程和线程是应用程序执行和资源管理的核心概念。这篇文章主要阐述了Android应用如何使用进程和线程,以及系统如何管理和优化这些资源。 首先,Android系统中的进程有五种不同的生命周期状态,...

    Android进程和线程详解

    Android进程和线程详解.当启动一个应用程序组件时,如果该应用没有正在运行的其它程序组件,那么Android系统将为这个应用创建一个新进程(包含一个线程)用于运行应用。  当启动一个应用程序组件时,如果该应用没有...

    Android-可保持线程日志统一输出多线程不混乱

    "Android-可保持线程日志统一输出多线程不混乱"这个主题关注的是如何在多线程环境中,有效地组织和打印线程相关的日志,以便于开发者追踪和理解程序执行流程。在多线程环境下,如果不对日志进行适当的管理,不同线程...

    掌握Android中的进程和线程

    Android作为一种的、承袭Linux的移动操作系统,其进程和线程的概念是开发者和安全工作人员需要深入了解的问题。本文将详细介绍Android中的进程、线程以及相关的技术问题。  进程和线程的基本概念  当一个应用...

    Android 应用程序模块 应用, 任务, 进程, 和线程--千锋培训

    在Android应用开发中,理解应用程序模块、任务(Tasks)、进程(Processes)和线程(Threads)的概念至关重要。这些组件是构建高效、响应且资源管理良好的应用程序的基础。 1. **应用程序模块(Application Modules...

    Android 中三种启用线程的方法总结

    首先说明Android的CPU分配的最小单元是线程,Handler一般是在某个线程里创建的,因而Handler和Thread就是相互绑定的,一一对应。 而Runnable是一个接口,Thread是Runnable的子类。所以说,他俩都算一个进程。 ...

    Android实现多线程下载

    在Android平台上,多线程下载是一项重要的技术,它允许应用程序同时从服务器获取数据,从而显著提高了文件下载的速度和效率。本教程将深入讲解如何在Android环境中实现多线程下载功能,以及涉及的相关知识点。 首先...

    线程/进程绑定CPU代码

    在计算机系统中,进程和线程是执行程序的基本单元。进程是系统资源分配的基本单位,而线程则是调度和执行的基本单位。当我们谈论"线程/进程绑定CPU代码"时,我们通常指的是通过编程手段将特定的进程或线程与特定的...

    android进程和新城之间的通信

    在Android系统中,进程和线程的通信是应用程序运行的核心组成部分。Android系统为每个应用程序启动一个单独的Linux进程,这个进程在默认情况下承载了应用程序的所有组件,如Activity、Service等。每个应用程序至少有...

    Android线程和进程介绍.pdf

    在Android系统中,线程和进程是两个关键概念,它们对于理解应用程序的执行环境和多任务处理至关重要。本文将深入探讨Android线程和进程的工作原理,以及如何在Android应用程序开发中正确地使用它们。 首先,Android...

Global site tag (gtag.js) - Google Analytics