1. Android进程
- 前台进程
前台进程是用户当前正在使用的进程。只有一些前台进程可以在任何时候都存在。他们是最后一个被结束的,当内存低到根本连他们都不能运行的时候。一般来说, 在这种情况下,设备会进行内存调度,中止一些前台进程来保持对用户交互的响应。 - 可见进程
可见进程不包含前台的组件但是会在屏幕上显示一个可见的进程是的重要程度很高,除非前台进程需要获取它的资源,不然不会被中止。 - 服务进程
运行着一个通过startService() 方法启动的service,这个service不属于上面提到的2种更高重要性的。service所在的进程虽然对用户不是直接可见的,但是他们执行了用户非常关注的任务(比如播放mp3,从网络下载数据)。只要前台进程和可见进程有足够的内存,系统不会回收他们。 - 后台进程
运行着一个对用户不可见的activity(调用过 onStop() 方法).这些进程对用户体验没有直接的影响,可以在服务进程、可见进程、前台进 程需要内存的时候回收。通常,系统中会有很多不可见进程在运行,他们被保存在LRU (least recently used) 列表中,以便内存不足的时候被第一时间回收。如果一个activity正 确的执行了它的生命周期,关闭这个进程对于用户体验没有太大的影响。 - 空进程
未运行任何程序组件。运行这些进程的唯一原因是作为一个缓存,缩短下次程序需要重新使用的启动时间。系统经常中止这些进程,这样可以调节程序缓存和系统缓存的平衡。
2. 单线程模型
2.1 子线程更新UI
2.2 Message Queue
1. Message
Message消息,理解为线程间交流的信息,处理数据后台线程需要更新UI,则发送Message内含一些数据给UI线程。
2. Handler
Handler处理者,是Message的主要处理者,负责Message的发送,Message内容的执行处理。后台线程就是通过传进来的Handler对象引用来
sendMessage(Message)。而使用Handler,需要implement 该类的
handleMessage(Message)方法,它是处理这些Message的操作内容,例如Update UI。通常需要子类化Handler来实现handleMessage方法。
3. Message Queue
Message Queue消息队列,用来存放通过Handler发布的消息,按照先进先出执行。
每个message queue都会有一个对应的Handler。Handler会向message queue通过两种方法发送消息:sendMessage或post。这两种消息都会插在message queue队尾并按先进先出执行。但通过这两种方法发送的消息执行的方式略有不同:通过sendMessage发送的是一个message对象,会被Handler的handleMessage()函数处理;而通过post方法发送的是一个runnable对象,则会自己执行。
4. Looper
Looper是每条线程里的Message Queue的管家。Android没有Global的Message Queue,而Android会自动替主线程(UI线程)建立Message Queue,但在子线程里并没有建立Message Queue。所以调用Looper.getMainLooper()得到的主线程的Looper不为NULL,但调用Looper.myLooper()得到当前线程的Looper就有可能为NULL。
01 | class LooperThread extends Thread { |
02 | public Handler mHandler; |
03 | |
04 | public void run() { |
05 | Looper.prepare(); //创建本线程的Looper并创建一个MessageQueue |
06 | |
07 | mHandler = new Handler() { |
08 | public void handleMessage(Message msg) { |
09 | // process incoming messages here |
10 | } |
11 | }; |
12 | |
13 | Looper.loop(); //开始运行Looper,监听Message Queue |
14 | } |
15 | } |
在网上有很多文章讲述主线程和其他子线程如何交互,传送信息,最终谁来执行处理信息之类的,个人理解是最简单的方法——判断Handler对象里面的Looper对象是属于哪条线程的,则由该线程来执行!
1. 当Handler对象的构造函数的参数为空,则为当前所在线程的Looper;
2. Looper.getMainLooper()得到的是主线程的Looper对象,Looper.myLooper()得到的是当前线程的Looper对象。
001 | public class ListProgressDemo extends ListActivity { |
002 | |
003 | @Override |
004 | public void onCreate(Bundle savedInstanceState) { |
005 | super .onCreate(savedInstanceState); |
006 | setContentView(R.layout.listprogress); |
007 | |
008 | ((Button) findViewById(R.id.load_Handler)).setOnClickListener( new View.OnClickListener(){ |
009 | |
010 | @Override |
011 | public void onClick(View view) { |
012 | data = null ; |
013 | data = new ArrayList<String>(); |
014 | |
015 | adapter = null ; |
016 | |
017 | showDialog(PROGRESS_DIALOG); |
018 | new ProgressThread(handler, data).start(); |
019 | } |
020 | }); |
021 | } |
022 | |
023 | @Override |
024 | protected Dialog onCreateDialog( int id) { |
025 | switch (id) { |
026 | case PROGRESS_DIALOG: |
027 | return ProgressDialog.show( this , "" , |
028 | "Loading. Please wait..." , true ); |
029 | |
030 | default : return null ; |
031 | } |
032 | } |
033 | |
034 | private class ProgressThread extends Thread { |
035 | |
036 | private Handler handler; |
037 | private ArrayList<String> data; |
038 | |
039 | public ProgressThread(Handler handler, ArrayList<String> data) { |
040 | this .handler = handler; |
041 | this .data = data; |
042 | } |
043 | |
044 | @Override |
045 | public void run() { |
046 | for ( int i= 0 ; i< 8 ; i++) { |
047 | data.add( "ListItem" ); //后台数据处理 |
048 | try { |
049 | Thread.sleep( 100 ); |
050 | } catch (InterruptedException e) { |
051 | |
052 | Message msg = handler.obtainMessage(); |
053 | Bundle b = new Bundle(); |
054 | b.putInt( "state" , STATE_ERROR); |
055 | msg.setData(b); |
056 | handler.sendMessage(msg); |
057 | |
058 | } |
059 | } |
060 | Message msg = handler.obtainMessage(); |
061 | Bundle b = new Bundle(); |
062 | b.putInt( "state" , STATE_FINISH); |
063 | msg.setData(b); |
064 | handler.sendMessage(msg); |
065 | } |
066 | |
067 | } |
068 | |
069 | // 此处甚至可以不需要设置Looper,因为Handler默认就使用当前线程的Looper |
070 | private final Handler handler = new Handler(Looper.getMainLooper()) { |
071 | |
072 | public void handleMessage(Message msg) { // 处理Message,更新ListView |
073 | int state = msg.getData().getInt( "state" ); |
074 | switch (state){ |
075 | case STATE_FINISH: |
076 | dismissDialog(PROGRESS_DIALOG); |
077 | Toast.makeText(getApplicationContext(), |
078 | "加载完成!" , |
079 | Toast.LENGTH_LONG) |
080 | .show(); |
081 | |
082 | adapter = new ArrayAdapter<String>(getApplicationContext(), |
083 | android.R.layout.simple_list_item_1, |
084 | data ); |
085 | |
086 | setListAdapter(adapter); |
087 | |
088 | break ; |
089 | |
090 | case STATE_ERROR: |
091 | dismissDialog(PROGRESS_DIALOG); |
092 | Toast.makeText(getApplicationContext(), |
093 | "处理过程发生错误!" , |
094 | Toast.LENGTH_LONG) |
095 | .show(); |
096 | |
097 | adapter = new ArrayAdapter<String>(getApplicationContext(), |
098 | android.R.layout.simple_list_item_1, |
099 | data ); |
100 | |
101 | setListAdapter(adapter); |
102 | |
103 | break ; |
104 | |
105 | default : |
106 | |
107 | } |
108 | } |
109 | }; |
110 | |
111 | |
112 | private ArrayAdapter<String> adapter; |
113 | private ArrayList<String> data; |
114 | |
115 | private static final int PROGRESS_DIALOG = 1 ; |
116 | private static final int STATE_FINISH = 1 ; |
117 | private static final int STATE_ERROR = - 1 ; |
118 | } |
2.3 AsyncTask
AsyncTask版:
01 | ((Button) findViewById(R.id.load_AsyncTask)).setOnClickListener( new View.OnClickListener(){ |
02 | |
03 | @Override |
04 | public void onClick(View view) { |
05 | data = null ; |
06 | data = new ArrayList<String>(); |
07 | |
08 | adapter = null ; |
09 | |
10 | //显示ProgressDialog放到AsyncTask.onPreExecute()里 |
11 | //showDialog(PROGRESS_DIALOG); |
12 | new ProgressTask().execute(data); |
13 | } |
14 | }); |
15 | |
16 | private class ProgressTask extends AsyncTask<ArrayList<String>, Void, Integer> { |
17 | |
18 | /* 该方法将在执行实际的后台操作前被UI thread调用。可以在该方法中做一些准备工作,如在界面上显示一个进度条。*/ |
19 | @Override |
20 | protected void onPreExecute() { |
21 | // 先显示ProgressDialog |
22 | showDialog(PROGRESS_DIALOG); |
23 | } |
24 | |
25 | /* 执行那些很耗时的后台计算工作。可以调用publishProgress方法来更新实时的任务进度。 */ |
26 | @Override |
27 | protected Integer doInBackground(ArrayList<String>... datas) { |
28 | ArrayList<String> data = datas[0]; |
29 | for (int i=0; i<8; i++) { |
30 | data.add("ListItem"); |
31 | } |
32 | return STATE_FINISH; |
33 | } |
34 | |
35 | /* 在doInBackground 执行完成后,onPostExecute 方法将被UI thread调用, |
36 | * 后台的计算结果将通过该方法传递到UI thread. |
37 | */ |
38 | @Override |
39 | protected void onPostExecute(Integer result) { |
40 | int state = result.intValue(); |
41 | switch (state){ |
42 | case STATE_FINISH: |
43 | dismissDialog(PROGRESS_DIALOG); |
44 | Toast.makeText(getApplicationContext(), |
45 | "加载完成!" , |
46 | Toast.LENGTH_LONG) |
47 | .show(); |
48 | |
49 | adapter = new ArrayAdapter<String>(getApplicationContext(), |
50 | android.R.layout.simple_list_item_1, |
51 | data ); |
52 | |
53 | setListAdapter(adapter); |
54 | |
55 | break ; |
56 | |
57 | case STATE_ERROR: |
58 | dismissDialog(PROGRESS_DIALOG); |
59 | Toast.makeText(getApplicationContext(), |
60 | "处理过程发生错误!" , |
61 | Toast.LENGTH_LONG) |
62 | .show(); |
63 | |
64 | adapter = new ArrayAdapter<String>(getApplicationContext(), |
65 | android.R.layout.simple_list_item_1, |
66 | data ); |
67 | |
68 | setListAdapter(adapter); |
69 | |
70 | break ; |
71 | |
72 | default : |
73 | |
74 | } |
75 | } |
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里面的例子。
----------------
本文的相当内容摘录于《
浅析Android线程模型一 --- 转》,但对于Message机制的流程理解则在参考《
android中Message机制的灵活应用》后修改了!