线程进程android
2011-02-27 23:28:00 editionman 阅读数 320

Android开发之旅:进程与线程

2010-05-02 16:58 by 吴秦, 3396 visits, 网摘 , 收藏 , 编辑

引言

当应用程序的组件第一次运行时,Android将启动一个只有一个执行线程的Linux进程。默认,应用程序所有的组件运行在这个进程和线程中。然而,你可以安排组件运行在其他进程中,且你可以为进程衍生出其它线程。本文从下面几点来介绍Android的进程与线程:

  • 1、进程
  • 2、线程
    • 2.1、远程过程调用(Remote procedure calls,RPCs)
    • 2.2、线程安全方法

1、进程

组件运行于哪个进程中由清单文件控制。组件元素——<activity><service><receiver><provider> ,都有一个process 属性可以指定组件运行在哪个进程中。这个属性可以设置为每个组件运行在自己的进程中,或者某些组件共享一个进程而其他的不共享。他们还可以设置为不同应用程序的组件运行在同一个进程中——假设这些应用程序共享同一个Linux用户ID且被分配了同样的权限。<application> 元素也有process 属性,为所有的组件设置一个默认值。

所有的组件都在特定进程的主线程中实例化,且系统调用组件是由主线程派遣。不会为每个实例创建单独的线程,因此,对应这些调用的方法——诸如View.onKeyDown() 报告用用户的行为和生命周期通知,总是运行在进程的主线程中。这意味着,没有组件当被系统调用时应该执行很长时间或阻塞操作(如网络操作或循环计算),因为这将阻塞进程中的其它组件。你可以为长操作衍生独立的线程。

public boolean onKeyDown (int keyCode,KeyEvent event):默认实现KeyEvent.Callback.onKeyMultiple(),当按下视图的KEYCODE_DPAD_CENTER或KEYCODE_ENTER然后释放时执行,如果视图可用且可点击。

参数

keyCode -表示按钮被按下的键码,来自KeyEvent
event -定义了按钮动作的KeyEvent对象

返回值

如果你处理事件,返回true;如果你想下一个接收者处理事件,返回false。

当内存剩余较小且其它进程请求较大内存并需要立即分配,Android要回收某些进程,进程中的应用程序组件会被销毁。当他们再次运行时,会重新开始一个进程。

当 决定终结哪个进程时,Android会权衡他们对用户重要性的相对权值。例如,与运行在屏幕可见的活动进程相比(前台进程),它更容易关闭一个进程,它的 活动在屏幕是不可见(后台进程)。决定是否终结进程,取决于运行在进程中的组件状态。关于组件的状态,将在后面一篇——组件生命周期 中介绍。

2、线程

虽然你可能会将你的应用程序限制在一个进程中,但有时候你会需要衍生一个线程做一些后台工作。因为用户界面必须很快地响应用户的操作,所以活动寄宿的线程不应该做一些耗时的操作如网络下载。任何不可能在短时间完成的操作应该分配到别的线程。

线程在代码中是用标准的Java线程对象创建的,Android提供了一些方便的类来管理线程——Looper 用于在线程中运行消息循环、Handler 用户处理消息、HandlerThread 用户设置一个消息循环的线程。

Looper类

该 类用户在线程中运行消息循环。线程默认没有消息循环,可以在线程中调用prepare()创建一个运行循环;然后调用loop()处理消息直到循环结束。 大部分消息循环交互是通过Handler类。下面是一个典型的执行一个Looper线程的例子,分别使用prepare()和loop()创建一个初始的 Handler与Looper交互:

  class LooperThread extends Thread {
      public Handler mHandler;
     
      public void run() {
          Looper.prepare();
         
          mHandler = new Handler() {
              public void handleMessage(Message msg) {
                  // process incoming messages here
              }
          };
         
          Looper.loop();
      }
  }

更多的关于Looper 的信息及Handler、HandlerThread 请参阅相关资料。

2.1、远程过程调用(Remote procedure calls,RPCs)

Android 有一个轻量级的远程过程调用机制——方法在本地调用却在远程(另外一个进程中)执行,结果返回给调用者。这需要将方法调用和它伴随的数据分解为操作系统能 够理解的层次,从本地进程和地址空间传输到远程进程和地址空间,并重新组装调用。返回值以相反方向传输。Android提供了做这些工作的所有代码,这样 我们可以专注于定义和执行RPC接口本身。

一个RPC接口仅包含方法。所有的方法同步地执行(本地方法阻塞直到远程方法执行完成),即 使是没有返回值。简言之,该机制工作原理如下:首先,你用简单的IDL(interface definition language,接口定义语言)声明一个你想实现的RPC接口。从这个声明中,aidl 工具生成一个Java接口定义,提供给本地和远程进程。它包含两个内部类,如下图所示:

binder_rpc

内部类有管理你用IDL定义的接口的远程过程调用所需要的所有代码。这两个内部类都实现了IBinder 接口。其中之一就是在本地由系统内部使用,你写代码可以忽略它。另外一个是Stub ,扩展自Binder 类。除了用于有效地IPC(interprocess communication)调用的内部代码,内部类在RPC接口声明中还包含方法声明。你可以定义Stub 的子类实现这些方法,如图中所示。

通常情况下,远程过程有一个服务管理(因为服务能通知系统关于进程和它连接的其它进程的信息)。它有由aidl 工具生成的接口文件和Stub 子类实现的RPC方法。服务的客户端仅有由aidl 工具生成的接口文件。

下面介绍服务如何与它的客户端建立连接:

  • 服务的客户端(在本地端的)应该实现onServiceConnected()onServiceDisconnected() 方法,因此当与远程服务建立连接成功和断开连接是会通知它。然后调用bindService() 建立连接。
  • 服务的onBind()方法将实现为接受或拒绝连接,者取决于它接受到的意图(该意图传送到binServive())。如果连接被接受,它返回一个Stub 子类的实例。
  • 如果服务接受连接,Android调用客户端的onServiceConnected()方法且传递给它一个IBinder对象,返回由服务管理的Stub 子类的一个代理。通过代理,客户端可以调用远程服务。

这里只是简单地描述,省略了一些RPC机制的细节。你可以查阅相关资料或继续关注Android开发之旅,后面将为你奉上。

2.2、线程安全方法

在一些情况下,你实现的方法可能会被不止一个线程调用,因此必须写成线程安全的。这对远程调用方法是正确的——如上一节讨论的RPC机制。当从IBinder 进程中调用一个IBinder 对象中实现的一个方法,这个方法在调用者的线程中执行。然而,当从别的进程中调用,方法将在Android维护的IBinder 进程中的线程池中选择一个执行,它不在进程的主线程中执行。例如,一个服务的onBind() 方法在服务进程的主线程中被调用,在onBind() 返回的对象中执行的方法(例如,实现RPC方法的Stub 子类)将在线程池中被调用。由于服务可以有一个以上的客户端,所以同时可以有一个以上的线程在执行同一个IBinder 方法。因此,IBinder 的方法必须是线程安全的。

同样,一个内容提供者可以接受其它进程产生的数据请求。虽然ContentResolverContentProvider 类隐藏进程通信如何管理的,对应哪些请求的ContentResolver 方法——query()、insert()、delete()、update()、getType(),在内容提供者的进程的线程池中被调用,而不是在这一进程的主线程中。因为这些方法可以同时从任意数量的线程中调用,他们也必须实现为线程安全的。

 

本系列的其它文章:

 

作者:吴秦
出处:http://www.cnblogs.com/skynet/

2010-05-27 17:44:00 a3015440 阅读数 405

当某个组件第一次运行的时候,Android启动了一个进程。默认的,所有的组件和程序运行在这个进程和线程中。

也可以安排组件在其他的进程或者线程中运行

进程

组件运行的进程由manifest file控制。组件的节点 — <activity>, <service>, <receiver>, 和 <provider> — 都包含一个 process 属性。 这个属性可以设置组件运行的进程:可以配置组件在一个独立进程运行,或者多个组件在同一个进程运行。甚至可以多个程序在一个进程中运行——如果这些程序共享一个User ID并给定同样的权限。<application> 节点也包含 process 属性 ,用来设置程序中所有组件的默认进程。

所有的组件在此进程的主线程中实例化 ,系统对这些组件的调用从主线程中分离。并非每个对象都会从主线程中分离。一般来说,响应例如View.onKeyDown()用户操作的方法和通知的方法也在主线程中运行。这就表示,组件被系统调用的时候不应该长时间运行或者阻塞操作(如网络操作或者计算大量数据),因为这样会阻塞进程中的其他组件 。可以把这类操作从主线程中分离。

当更加常用的进程无法获取足够内存,Android可能会关闭不常用的进程。下次启动程序的时候会重新启动进程。

当决定哪个进程需要被关闭的时候, Android会考虑哪个对用户更加有用。如Android会倾向于关闭一个长期不显示在界面的进程来支持一个经常显示在界面的进程。是否关闭一个进程决 定于组件在进程中的状态,参见后面的章节Component Lifecycles.

线程

即使为组件分配了不同的进程,有时候也需要再分配线程。比如用户界面需要很快对用户进行响应,因此某些费时的操作,如网络连接、下载或者非常占用服务器时间的操作应该放到其他线程。

线程通过java的标准对象Thread 创建. Android 提供了很多方便的管理线程的方法:— Looper 在线程中运行一个消息循环; Handler 传递一个消息; HandlerThread 创建一个带有消息循环的线程。

远程调用Remote procedure calls

Android有一个远程调用(RPCs) 的轻量级机制— 通过这个机制,方法可以在本地调用,在远程执行(在其他进程执行),还可以返回一个值。要实现这个需求,必须分解方法调用,并且所有要传递的数据必须是操 作系统可以访问的级别。从本地的进程和内存地址传送到远程的进程和内存地址并在远程处理和返回。返回值必须向相反的方向传递。Android提供了做以上 操作的代码,所以开发者可以专注于实现RPC的接口。

一个RPC接口只能包含方法。所有的方法都是同步执行的 (直到远程方法返回,本地方法才结束阻塞),没有返回值的时候也是如此。

简单来说,这个机制是这样的:使用IDL (interface definition language)定义你想要实现的接口, aidl 工具可以生成用于java的接口定义,本地和远程都要使用这个定义 。它包含2个类,见下图:

binder_rpc

inner类包含了所有的管理远程程序(符合IDL描述的接口)所需要的代码。所有的inner类实现了IBinder 接口.其中一个在本地使用,可以不管它的代码;另外一个叫做Stub继承了 Binder 类。为了实现远程调用,这个类包含RPC接口。开发者可以继承Stub类来实现需要的方法

一般来说,远程进程会被一个service管理(因为service可以通知操作系统这个进程的信息并和其他进程通信),它也会包含aidl 工具产生的接口文件,Stub类实现了远处那个方法。服务的客户端只需要aidl 工具产生的接口文件。

以下是如何连接服务和客户端调用:

  • ·服务的客户端(本地)会实现onServiceConnected() 和onServiceDisconnected() 方法,这样,当客户端连接或者断开连接的时候可以获取到通知。通过 bindService() 获取到服务的连接。
  • · 服务的 onBind() 方法中可以接收或者拒绝连接,取决它收到的intent (intent通过 bindService()方法连接到服务). 如果服务接收了连接,会返回一个Stub类的实例.
  • · 如果服务接受了连接,Android会调用客户端的onServiceConnected() 方法,并传递一个Ibinder对象(系统管理的Stub类的代理),通过这个代理,客户端可以连接远程的服务。

以上的描述省略很多RPC的机制。请参见Designing a Remote Interface Using AIDL 和 IBinder 类。

线程安全的方法

在某些情况下,方法可能调用不止一个的线程,因此需要注意方法的线程安全。

对于可以远程调用的方法,也要注意这点。当一个调用在Ibinder对象中的方法的程序启动了和Ibinder对象相同的进程,方法就在 Ibinder的进程中执行。但是,如果调用者发起另外一个进程,方法在另外一个线程中运行,这个线程在和IBinder对象在一个线程池中;它不会在进 程的主线程中运行。例如,一个service从主线程被调用onBind() 方法,onBind() 返回的对象(如实现了RPC的Stub子类)中的方法会被从线程池中调用。因为一个服务可能有多个客户端请求,不止一个线程池会在同一时间调用 IBinder的方法。因此IBinder必须线程安全。

简单来说,一个content provider 可以接收其他进程的数据请求。即使ContentResolver和ContentProvider类没有隐藏了管理交互的细 节,ContentProvider中响应这些请求的方法(query(), insert(), delete(), update(), and getType() )— 是在content provider的线程池中被调用的,而不是ContentProvider的本身进程。因为这些方法可能是同时从很多线程池运行的,所以这些方法必须要 线程安全。

2013-01-12 23:58:44 forlong401 阅读数 609

http://www.cnblogs.com/feisky/archive/2010/01/01/1637409.html

当某个组件第一次运行的时候,Android启动了一个进程。默认的,所有的组件和程序运行在这个进程和线程中。

也可以安排组件在其他的进程或者线程中运行

进程

组件运行的进程由manifest file控制。组件的节点 — <activity>, <service>, <receiver>, 和 <provider> — 都包含一个 process 属性。这个属性可以设置组件运行的进程:可以配置组件在一个独立进程运行,或者多个组件在同一个进程运行。甚至可以多个程序在一个进程中运行——如果这些程序共享一个User ID并给定同样的权限。<application> 节点也包含 process 属性,用来设置程序中所有组件的默认进程。

所有的组件在此进程的主线程中实例化,系统对这些组件的调用从主线程中分离。并非每个对象都会从主线程中分离。一般来说,响应例如View.onKeyDown()用户操作的方法和通知的方法也在主线程中运行。这就表示,组件被系统调用的时候不应该长时间运行或者阻塞操作(如网络操作或者计算大量数据),因为这样会阻塞进程中的其他组件。可以把这类操作从主线程中分离。

当更加常用的进程无法获取足够内存,Android可能会关闭不常用的进程。下次启动程序的时候会重新启动进程。

当决定哪个进程需要被关闭的时候, Android会考虑哪个对用户更加有用。如Android会倾向于关闭一个长期不显示在界面的进程来支持一个经常显示在界面的进程。是否关闭一个进程决定于组件在进程中的状态,参见后面的章节Component Lifecycles.

线程

即使为组件分配了不同的进程,有时候也需要再分配线程。比如用户界面需要很快对用户进行响应,因此某些费时的操作,如网络连接、下载或者非常占用服务器时间的操作应该放到其他线程。

线程通过java的标准对象Thread 创建. Android 提供了很多方便的管理线程的方法:— Looper 在线程中运行一个消息循环; Handler 传递一个消息; HandlerThread 创建一个带有消息循环的线程。

远程调用Remote procedure calls

Android有一个远程调用(RPCs) 的轻量级机制— 通过这个机制,方法可以在本地调用,在远程执行(在其他进程执行),还可以返回一个值。要实现这个需求,必须分解方法调用,并且所有要传递的数据必须是操作系统可以访问的级别。从本地的进程和内存地址传送到远程的进程和内存地址并在远程处理和返回。返回值必须向相反的方向传递。Android提供了做以上操作的代码,所以开发者可以专注于实现RPC的接口。

一个RPC接口只能包含方法。所有的方法都是同步执行的(直到远程方法返回,本地方法才结束阻塞),没有返回值的时候也是如此。

简单来说,这个机制是这样的:使用IDL (interface definition language)定义你想要实现的接口, aidl 工具可以生成用于java的接口定义,本地和远程都要使用这个定义。它包含2个类,见下图:

binder_rpc

inner类包含了所有的管理远程程序(符合IDL描述的接口)所需要的代码。所有的inner类实现了IBinder 接口.其中一个在本地使用,可以不管它的代码;另外一个叫做Stub继承了 Binder 类。为了实现远程调用,这个类包含RPC接口。开发者可以继承Stub类来实现需要的方法

一般来说,远程进程会被一个service管理(因为service可以通知操作系统这个进程的信息并和其他进程通信),它也会包含aidl 工具产生的接口文件,Stub类实现了远处那个方法。服务的客户端只需要aidl 工具产生的接口文件。

以下是如何连接服务和客户端调用:

  • ·服务的客户端(本地)会实现onServiceConnected() 和onServiceDisconnected() 方法,这样,当客户端连接或者断开连接的时候可以获取到通知。通过 bindService() 获取到服务的连接。
  • · 服务的 onBind() 方法中可以接收或者拒绝连接,取决它收到的intent (intent通过 bindService()方法连接到服务). 如果服务接收了连接,会返回一个Stub类的实例.
  • · 如果服务接受了连接,Android会调用客户端的onServiceConnected() 方法,并传递一个Ibinder对象(系统管理的Stub类的代理),通过这个代理,客户端可以连接远程的服务。

以上的描述省略很多RPC的机制。请参见Designing a Remote Interface Using AIDL 和 IBinder 类。

线程安全的方法

在某些情况下,方法可能调用不止一个的线程,因此需要注意方法的线程安全。

对于可以远程调用的方法,也要注意这点。当一个调用在Ibinder对象中的方法的程序启动了和Ibinder对象相同的进程,方法就在Ibinder的进程中执行。但是,如果调用者发起另外一个进程,方法在另外一个线程中运行,这个线程在和IBinder对象在一个线程池中;它不会在进程的主线程中运行。例如,一个service从主线程被调用onBind() 方法,onBind() 返回的对象(如实现了RPC的Stub子类)中的方法会被从线程池中调用。因为一个服务可能有多个客户端请求,不止一个线程池会在同一时间调用IBinder的方法。因此IBinder必须线程安全。

简单来说,一个content provider 可以接收其他进程的数据请求。即使ContentResolver和ContentProvider类没有隐藏了管理交互的细节,ContentProvider中响应这些请求的方法(query(), insert(), delete(), update(), and getType() )— 是在content provider的线程池中被调用的,而不是ContentProvider的本身进程。因为这些方法可能是同时从很多线程池运行的,所以这些方法必须要线程安全。


2016-02-25 10:44:32 yangxi_001 阅读数 248

1.Android进程基本知识:

  我们先来了解下Android中的进程基本知识。

 

  当一个程序第一次启动的时候,Android会启动一个LINUX进程和一个主线程。默认的情况下,所有该程序的组件都将在该进程和线程中运行。 同时,

Android会为每个应用程序分配一个单独的LINUX用户。Android会尽量保留一个正在运行进程,只在内存资源出现不足时,Android会尝试停止一些进程从

而释放足够的资源给其他新的进程使用, 也能保证用户正在访问的当前进程有足够的资源去及时地响应用户的事件。

 

  我们可以将一些组件运行在其他进程中,并且可以为任意的进程添加线程。组件运行在哪个进程中是在manifest文件里设置的,其中<Activity>,

<Service>,<receiver>和<provider>都有一个process属性来指定该组件运行在哪个进程之中。我们可以设置这个属性,使得每个组件运行在它们自己的

进程中,或是几个组件共同享用一个进程,或是不共同享用。<application>元素也有一个process属性,用来指定所有的组件的默认属性。 

 

  Android中的所有组件都在指定的进程中的主线程中实例化的,对组件的系统调用也是由主线程发出的。每个实例不会建立新的线程。对系统调用进行响

应的方法——例如负责执行用户动作的View.onKeyDown()和组件的生命周期函数——都是运行在这个主线程中的。这意味着当系统调用这个组件时,这个组

件不能长时间的阻塞主线程。例如进行网络操作时或是更新UI时,如果运行时间较长,就不能直接在主线程中运行,因为这样会阻塞这个进程中其他的组件

,我们可以将这样的组件分配到新建的线程中或是其他的线程中运行。

 

  Android会根据进程中运行的组件类别以及组件的状态来判断该进程的重要性,Android会首先停止那些不重要的进程。按照重要性从高到低一共有五个

级别:

 

  前台进程

  前台进程是用户当前正在使用的进程。只有一些前台进程可以在任何时候都存在。他们是最后一个被结束的,当内存低到根本连他们都不能运行的时候。

一般来说, 在这种情况下,设备会进行内存调度,中止一些前台进程来保持对用户交互的响应。

 

  如果有以下的情形的那么就是前台进程:  

  这个进程运行着一个正在和用户交互的Activity(这个Activity的onResume()方法被调用)。

  这个进程里有绑定到当前正在和用户交互的确Activity的一个service。

  这个进程里有一个service对象,这个service对象正在执行一个它的生命周期的回调函数(onCreate(), onStart(), onDestroy())

  这个进程里有一个正在的onReceive()方法的BroadCastReiver对象。

 

  可见进程

  可见进程不包含前台的组件但是会在屏幕上显示一个可见的进程是的重要程度很高,除非前台进程需要获取它的资源,不然不会被中止。

 

  如果有如下的一种情形就是可见进程: 

  这个进程中含有一个不位于前台的Activity,但是仍然对用户是可见的(这个Activity的onPause()方法被调用),这是很可能发生的,例如,如果前台

Activity是一个对话框的话,就会允许在它后面看到前一个Activity。

  这个进程里有一个绑定到一个可见的Activity的Service。

 

  服务进程

  运行着一个通过startService() 方法启动的service,这个service不属于上面提到的2种更高重要性的。service所在的进程虽然对用户不是直接可见的,

但是他们执行了用户非常关注的任务(比如播放mp3,从网络下载数据)。只要前台进程和可见进程有足够的内存,系统不会回收他们。

 

  后台进程

  运行着一个对用户不可见的activity(调用过 onStop() 方法).这些进程对用户体验没有直接的影响,可以在服务进程、可见进程、前台进 程需要内存的

时候回收。通常,系统中会有很多不可见进程在运行,他们被保存在LRU (least recently used) 列表中,以便内存不足的时候被第一时间回收。如果一个

activity正 确的执行了它的生命周期,关闭这个进程对于用户体验没有太大的影响。

 

  空进程

  未运行任何程序组件。运行这些进程的唯一原因是作为一个缓存,缩短下次程序需要重新使用的启动时间。系统经常中止这些进程,这样可以调节程序缓

存和系统缓存的平衡。

 

  Android 对进程的重要性评级的时候,选取它最高的级别。例如,如果一个进程含有一个service和一个可视activity,进程将被归入一个可视进程而不是

service进程。

 

  另外,当被另外的一个进程依赖的时候,某个进程的级别可能会增高。一个为其他进程服务的进程永远不会比被服务的进程重要级低。因为服务进程比后

台activity进程重要级高,因此一个要进行耗时工作的activity最好启动一个service来做这个工作,而不是开启一个子进程――特别是这个操作需要的时间比

activity存在的时间还要长的时候。例如,在后台播放音乐,向网上上传摄像头拍到的图片,使用service可以使进程最少获取到“服务进程”级别的重要级,而

不用考虑activity目前是什么状态。broadcast receivers做费时的工作的时候,也应该启用一个服务而不是开一个线程。

 

  2. 单线程模型

  线程在代码是使用标准的java Thread对象来建立,那么在Android系统中提供了一系列方便的类来管理线程——Looper用来在一个线程中执行消息循

环,Handler用来处理消息,HandlerThread创建带有消息循环的线程。具体可以看下面的详细介绍。

 

  当一个程序第一次启动时,Android会同时启动一个对应的主线程(Main Thread),主线程主要负责处理与UI相关的事件,如用户的按键事件,用户接

触屏幕的事件以及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理。所以主线程通常又被叫做UI线程。

 

  在开发Android应用时必须遵守单线程模型的原则: Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行。

 

  2.1 子线程更新UI Android的UI是单线程(Single-threaded)的。

  为了避免拖住GUI,一些较费时的对象应该交给独立的线程去执行。如果幕后的线程来执行UI对象,Android就会发出错误讯息

 CalledFromWrongThreadException。以后遇到这样的异常抛出时就要知道怎么回事了!

 

  2.2 Message Queue

  在单线程模型下,为了解决类似的问题,Android设计了一个Message Queue(消息队列), 线程间可以通过该Message Queue并结合Handler和

Looper组件进行信息交换。下面将对它们进行分别介绍:

 

  2.2.1. Message 消息

  理解为线程间交流的信息,处理数据后台线程需要更新UI,则发送Message内含一些数据给UI线程。

 

  2.2.2. Handler 处理者

  是Message的主要处理者,负责Message的发送,Message内容的执行处理。后台线程就是通过传进来的Handler对象引用来

sendMessage(Message)。而使用Handler,需要implement 该类的 handleMessage(Message) 方法,它是处理这些Message的操作内容,例如

Update UI。通常需要子类化Handler来实现handleMessage方法。

 

  2.2.3. Message Queue 消息队列

  用来存放通过Handler发布的消息,按照先进先出执行。 每个message queue都会有一个对应的Handler。Handler会向message queue通过两种方

法发送消息:sendMessage或post。这两种消息都会插在message queue队尾并按先进先出执行。但通过这两种方法发送的消息执行的方式略有不同:通过

sendMessage发送的是一个message对象,会被Handler的handleMessage()函数处理;而通过post方法发送的是一个runnable对象,则会自己执行。

 

  2.2.4. Looper Looper是每条线程里的Message Queue的管家。

  Android没有Global的Message Queue,而Android会自动替主线程(UI线程)建立Message Queue,但在子线程里并没有建立Message Queue。所

以调用Looper.getMainLooper()得到的主线程的Looper不为NULL,但调用Looper.myLooper()得到当前线程的Looper就有可能为NULL。

 

  对于子线程使用Looper,API Doc提供了正确的使用方法: 

复制代码
package com.test;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;

class LooperThread extends Thread { 
    public Handler mHandler; 
    
    public void run() { 
        Looper.prepare(); //创建本线程的Looper并创建一个MessageQueue
        mHandler = new Handler() { 
            public void handleMessage(Message msg) { 

            // process incoming messages here 
            } 
        }; 
        
        Looper.loop(); //开始运行Looper,监听Message Queue 
    }     
复制代码

  这个Message机制的大概流程:

  1. 在Looper.loop()方法运行开始后,循环地按照接收顺序取出Message Queue里面的非NULL的Message。

 

  2. 一开始Message Queue里面的Message都是NULL的。当Handler.sendMessage(Message)到Message Queue,该函数里面设置了那个Message

对象的target属性是当前的Handler对象。随后Looper取出了那个Message,则调用该Message的target指向的Hander的dispatchMessage函数对

Message进行处理。
 
  在dispatchMessage方法里,如何处理Message则由用户指定,三个判断,优先级从高到低:
 
  1) Message里面的Callback,一个实现了Runnable接口的对象,其中run函数做处理工作;

  2) Handler里面的mCallback指向的一个实现了Callback接口的对象,由其handleMessage进行处理;

  3) 处理消息Handler对象对应的类继承并实现了其中handleMessage函数,通过这个实现的handleMessage函数处理消息。
 
  由此可见,我们实现的handleMessage方法是优先级最低的!

 

  3. Handler处理完该Message (update UI) 后,Looper则设置该Message为NULL,以便回收!

 

3.Android另外提供了一个工具类:AsyncTask。

它使得UI thread的使用变得异常简单。它使创建需要与用户界面交互的长时间运行的任务变得更简单,不需要借助线程和Handler即可实现。

  1) 子类化AsyncTask

  2) 实现AsyncTask中定义的下面一个或几个方法

  onPreExecute() 开始执行前的准备工作;

  doInBackground(Params...) 开始执行后台处理,可以调用publishProgress方法来更新实时的任务进度;

 

  onProgressUpdate(Progress...) 在publishProgress方法被调用后,UI thread将调用这个方法从而在界面上展示任务的进展情况,例如通过一个进度条进行展示。

  onPostExecute(Result) 执行完成后的操作,传送结果给UI 线程。

  这4个方法都不能手动调用。而且除了doInBackground(Params...)方法,其余3个方法都是被UI线程所调用的,所以要求:

  1) AsyncTask的实例必须在UI thread中创建;

  2) AsyncTask.execute方法必须在UI thread中调用;

  同时要注意:该task只能被执行一次,否则多次调用时将会出现异常。

  在使用过程中,发现AsyncTask的构造函数的参数设置需要看明白:

  AsyncTask<Params, Progress, Result> Params对应doInBackground(Params...)的参数类型。

  而new AsyncTask().execute(Params... params),就是传进来的Params数据,你可以execute(data)来传送一个数据,或者execute(data1, data2, data3)这样多个数据。

  Progress对应onProgressUpdate(Progress...)的参数类型;

  Result对应onPostExecute(Result)的参数类型。 当以上的参数类型都不需要指明某个时,则使用Void,注意不是void。不明白的可以参考上面的例子,或者API Doc里面的例子。

  下面是关于AsyncTask的使用示例:

复制代码
((Button) findViewById(R.id.load_AsyncTask)).setOnClickListener(new View.OnClickListener(){ 
 
    @Override 
    public void onClick(View view) { 
        data = null
        data = new ArrayList<String>(); 
 
        adapter = null
 
        //显示ProgressDialog放到AsyncTask.onPreExecute()里 
        
//showDialog(PROGRESS_DIALOG); 
        new ProgressTask().execute(data); 
    } 
}); 
 
private class ProgressTask extends AsyncTask<ArrayList<String>, Void, Integer> { 
 
/* 该方法将在执行实际的后台操作前被UI thread调用。可以在该方法中做一些准备工作,如在界面上显示一个进度条。*/ 
@Override 
protected void onPreExecute() { 
    // 先显示ProgressDialog
    showDialog(PROGRESS_DIALOG); 

 
/* 执行那些很耗时的后台计算工作。可以调用publishProgress方法来更新实时的任务进度。 */ 
@Override 
protected Integer doInBackground(ArrayList<String>... datas) { 
    ArrayList<String> data = datas[0]; 
    for (int i=0; i<8; i++) { 
        data.add("ListItem"); 
    } 
    return STATE_FINISH; 

 
/* 在doInBackground 执行完成后,onPostExecute 方法将被UI thread调用, 
 * 后台的计算结果将通过该方法传递到UI thread. 
 
*/ 
@Override 
protected void onPostExecute(Integer result) { 
    int state = result.intValue(); 
    switch(state){ 
    case STATE_FINISH: 
        dismissDialog(PROGRESS_DIALOG); 
        Toast.makeText(getApplicationContext(), 
                "加载完成!", 
                Toast.LENGTH_LONG) 
             .show(); 
 
        adapter = new ArrayAdapter<String>(getApplicationContext(), 
                android.R.layout.simple_list_item_1, 
                data ); 
                 
        setListAdapter(adapter); 
 
        break
         
    case STATE_ERROR: 
       dismissDialog(PROGRESS_DIALOG); 
       Toast.makeText(getApplicationContext(), 
               "处理过程发生错误!", 
               Toast.LENGTH_LONG) 
            .show();
 
       adapter = new ArrayAdapter<String>(getApplicationContext(), 
               android.R.layout.simple_list_item_1, 
               data );
 
          setListAdapter(adapter);
 
          break;
 
   default:
 
   } 
}
复制代码

   以上是从网络获取数据,加载到ListView中示例。

  4.Android中如何结束进程 

  4.1 Android 结束进程,关闭程序的方法 即采用下面这个类

  Void android.app.ActivityManager.restartPackage(String packageName)

  public void restartPackage (String packageName)

  Since: API Level 3

  Have the system perform a force stop of everything associated with the given application package. All processes that share its uid will be killed, all services it has running stopped, all activities removed, etc. In addition, a ACTION_PACKAGE_RESTARTED broadcast will be sent, so that any of its registered alarms can be stopped, notifications removed, etc. You must hold the permission RESTART_PACKAGES to be able to call this method. Parameters packageName The name of the package to be stopped.

  使用这个类的具体源代码

final ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);   
am.restartPackage(getPackageName()); 

   不要忘记了在配置文件中设置权限:

<uses-permission android:name="android.permission.RESTART_PACKAGES"></uses-permission> 

  结束进程还有

  4.2 android.os.Process.killProcess(pid)

  只能终止本程序的进程,无法终止其它的

  public static final void killProcess (int pid)

  Kill the process with the given PID. Note that, though this API allows us to request to kill any process based on its PID, the kernel will still impose standard restrictions on which PIDs you are actually able to kill. Typically this means only the process running the caller's packages/application and any additional processes created by that app; packages sharing a common UID will also be able to kill each other's processes.

  具体代码如下:

  Process.killProcess(Process.myPid());

Process.killProcess(Process.myPid());

  public void finish ()

  Call this when your activity is done and should be closed. The ActivityResult is propagated back to whoever launched you via onActivityResult().

  这是结束当前activity的方法。 要主动的结束一个活动Activity,这里需要注意finish是结束掉一个Activity,而不是一个进程。这个方法最后会调用Activity的生命周期函数onDestroy方法,结束当前的Activity,从任务栈中弹出当前的Activity,激活下一个Activity。当然其他的finish系列方法,我们不在这里做详细讨论。

  4.3 System.exit(int code)

  例如: System.exit(0);

  该方法只能用于结束当前进程自身,在程序遇到异常,无法正常执行时,可以 通过这个方法强制退出。 

  需要注意的是: android.os.Process.killProcess(pid) 和 System.exit(int code)会导致进程非正常退出,进程退出时不会去执行Activity的onPause、onStop和onDestroy方法,那么进程很有可能错过了保存数据的机会。因此,这两个方法最好使用在出现异常的时候!大家需要注意其使用方法。

  4.4 在android2.2版本之后则不能再使用restartPackage()方法,而应该使用killBackgroundProcesses()方法

  manager.killBackgroundProcesses(getPackageName());

  使用示例代码如下:

ActivityManager manager = (ActivityManager)getSystemService(ACTIVITY_SERVICE);   
manager.killBackgroundProcesses(getPackageName());
//需要在xml中加入权限声明    
<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/>  

   另外,在android2.2以后,如果服务在ondestroy里加上了start自己,用kill backgroudprocess通常无法结束自己。

  4.5还有一种最新发现的方法,利用反射调用forceStopPackage来结束进程

 
Method forceStopPackage = am.getClass().getDeclaredMethod("forceStopPackage", String.class);  
forceStopPackage.setAccessible(true);  
forceStopPackage.invoke(am, yourpkgname);  

  配置文件中需要添加定义:

android:sharedUserId="android.uid.system"   

  另外需要再在配置文件添加权限: 

<uses-permission android:name="android.permission.FORCE_STOP_PACKAGES"></uses-permission>   

  并且采用系统platform签名 因为需要用FORCE_STOP_PACKAGES权限,该权限只赋予系统签名级程序 即可实现强制停止指定程序  

  4.6 还有一种方法 利用linux的kill -9命令

  4.7 退出到主屏幕(是对当前进程的一种处理) 

  这个方法,也是退出当前进程的一个方法。如果我们在进程中创建了很多的Activity, 但是又不想关闭时去退出不在任务栈顶的Activity ,那么就可以直接使用这个方法了。 

功能:当按下返回键时,就返回到主屏幕,并带有参数 FLAG_ACTIVITY_CLEAR_TOP , 会清理掉当前的活动。 

  以下是按下返回键同时不重复时,返回到主屏幕的示例:

复制代码
package com.test.android; 

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.KeyEvent;

/**
 * Andriod按返回键返回到主屏幕示例
 * @Description: Andriod按返回键返回到主屏幕示例

 * @FileName: MyTestProjectActivity.java 

 * @Package com.test.android 

 * @Author Hanyonglu

 * @Date 2012-4-11 上午11:57:31 

 * @Version V1.0
 
*/
public class MyTestProjectActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
    
    @Override 
    public boolean onKeyDown(int keyCode, KeyEvent event) { 
        // event.getRepeatCount():按下返回键,同时没有重复
        if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
            Intent home = new Intent(Intent.ACTION_MAIN);   
            home.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);   
            home.addCategory(Intent.CATEGORY_HOME);   
            startActivity(home);
        } 
        
        return super.onKeyDown(keyCode, event);   
    } 
}
复制代码

  这种方法其实并没有将进程完全地退出,只是将该程序进入到了后台运行,以便下次更快的启动,所以想要程序进入到后台运行可以考虑采用这种方式。关于这点呢,大家了解就可以了。

  以上就是关于Android中进程和线程的基本知识,个人觉得理解这些知识点很重要,虽然它不能让我们在立即能够让我们享受到做出一个产品的成就感,但是可以增强我们的内力,让我们对Android的一些运行机制掌握地更加清楚。

  最后,希望转载的朋友能够尊重作者的劳动成果,加上转载地址:http://www.cnblogs.com/hanyonglu/archive/2012/04/12/2443262.html


2017-04-28 09:33:41 lzc394049722 阅读数 105

一、线程应用基础

概述:线程是CPU独立运行和独立调度的基本单位(可以理解为一个进程中执行的代码片段),进程是资源分配的基本单位(进程是一块包含了某些资源的内存区域,通俗说,就是运行中的程序)。进程是线程的容器,真正完成代码执行的是线程,而进程则作为线程的执行环境。一个程序至少包含一个进程,一个进程至少包含一个线程,一个进程中的多个线程共享当前进程所拥有的资源!!!

1.线程是什么?

线程是进程中的一个顺序的执行流,是进程中的一个最小的执行单位,所有进程内部的线程共享进程内存,进程间内存相互独立。

2.进程是什么?

进程是操作系统中正在运行的一个程序,一个多任务操作系统可以并发的执行多个进程,而进程的并发严格来讲是进程中线程的并发。


3.并发是什么?(一个cpu下的线程)

1)广义的并发:同时

2)狭义的并发:交替


4.多线程应用场景?

1)多个并发下载任务

2)播放音乐的同时还可以对其进行缓存(就是下载)

3)。。。。


5.Android 中线程类型及创建启动?

1)线程类型:Thread

2)线程创建

a)构建Thread类的子类对象然后重写run方法

b)构建Thread类对象的同时传入Runnable类型的对象

3)线程启动:start方法(可以让线程处于就绪状态)

4)线程运行:线程启动以后一旦获得cpu就会执行run方法

6)相关状态:

a)新建状态(新创建的线程,还没启动)

b)就绪状态(启动了线程或休眠的线程醒了)

c)运行状态

d)阻塞状态(线程休眠或Io)

f)死亡状态(线程run方法结束)

7)相关方法(一部分):点击打开链接


二、Android 线程应用同步

1.多线程同步概述

线程同步是多线程在共享数据集上的互斥与协作。

互斥:多线程在共享数据集上排队执行。

协作:多线程在共享数据集上协作执行。


2.多线程互斥的实现

场景:

1)多个线程

2)共享数据集

3)共享数据集上的操作为非原子操作

实现过程:

1)同步方法

a)public synchronized void put(){}

b ) public static synchronized void put(){}

说明:(1)实例方法默认使用this作为对象锁

    (2)静态方法默认使用类对象作为对象锁

2)同步代码块:synchronized ("Lock"){}

回顾:

1)StringBuffer是一个线程不安全的StringBuilder

2)ArrayList是一个线程不安全的List

3)HashMap是一个线程不安全的集合

。。。。

说明:在线程不安全的环境使用集合时要考虑线程安全集合的应用,例如:

1.Collections.synchronizedList(Llist)

2.COncurrentHashMap 线程安全并且高效(采用的是局部加锁)


三.android消息模型

1.Android 中消息模型概述?
1)是生产者消费者模型的一种实现
2)是Android特有线程工作机制的一种实现。
a)主线程(UI线程)执行UI操作
b)工作线程执行耗时操作


2.Android 中消息模型应用场景?
Android中一个进程内部的多个线程之间的通讯


3.Android 中消息模型应用API及功能?
1)Message
2)MessageQueue
3)Looper
4)Handler


4.Android 中消息模型应用实现?
1)工作线程发消息给主线程
2)主线程发消息给工作线程
3)主线程发消息给主线程




5.Android 中消息模型FAQ?
1)Android中每个线程最多有一个Looper
2)Android中每个线程最多有一个MessageQueue
3)Android中线程间消息的传递需要借助handler
4)Android中每个handler对象都必须关联一个Looper
5)Android中工作线程需要looper时可以借助HandlerThread对象创建
6)Android中activity退出时工作线程线程的Looper一定要退出。
7).................


6.Android 中线程内存泄漏现象

1)android中线程类型的声明是实例内部类,
或者实例方法中的局部内部类。
2)android中handler类型的声明是实例内部类,
或者实例方法中的局部内部类。
3)android中工作线程强引用activity中的view。
4)android中工作线程的looper在页面退出时
没有退出。


案例说明:
1)线程是实例内部或局部内部类

class MainActivity{


    public void onClick(View v){
     
       new WokerThread().start();
       new Thread(){//局部匿名内部类
            public void run(){}
       }.start();//此内部类会保存外部类引用


    }
    //实例内部类会保存外部类的引用
    //假如需要使用线程内部类建议使用static的
    class WorkerThread extends Thread{
        public void run(){
           //耗时操作
        }
    }
}




2)handler类型是实例内部类或局部内部类

class MainActivity{




    /**默认引用外部类对象*/
    class WokerHandler extends Handler{


        public void handleMessage(...){}
    }//建议这样的内部类使用static修饰


}//handler.sendMessage(msg);此时消息也会关联handler




3)工作线程强引用activity中的view


class MainActivity{


    public void onCreate(...){
      ...
      View view=findViewById(..);
    }
    class DownAsyncTask extends AsyncTask{
      private View v;
      public DownAsyncTask(View v){
         this.v=v;//强引用
      }
    }
}




4)工作线程的looper没有退出?


工作线程的looper不退出,线程就会一直
处于迭代状态。


Android 进程和线程

阅读数 391

Android之进程与线程

阅读数 1357

android 进程和线程

阅读数 423

android 进程和线程

阅读数 663

没有更多推荐了,返回首页