android多线程编程总结
16lz
2022-04-27
n 在Android中,只要是关于UI相关的东西,就不能放在子线程中,因为子线程是不能操作UI的,只能进行数据、系统等其他非UI的操作。 n 在单线程模型下,为了解决类似的问题,Android设计了一个Message Queue(消息队列), 线程间可以通过该Message Queue并结合Handler和Looper组件进行信息交换。下面将对它们进行分别介绍 n andriod提供了 Handler 和 Looper 来满足线程间的通信。例如一个子线程从网络上下载了一副图片,当它下载完成后会发送消息给主线程,这个消息是通过绑定在主线程的Handler来传递的。 n Message消息,线程间交流的信息,处理数据后台线程需要更新UI,则发送Message内含一些数据给UI线程。 public final class Message implements Parcelable { public int what; public Messenger replyTo; long when; Bundle data; Handler target; Runnable callback; Message next; private static Object mPoolSync = new Object(); private static Message mPool; private static int mPoolSize = 0; private static final int MAX_POOL_SIZE = 10; When: 向Handler发送Message生成的时间 Data: 在Bundler 对象上绑定要线程中传递的数据 Next: 当前Message 对一下个Message 的引用 Handler: 处理当前Message 的Handler对象. mPool: 通过字面理解可能叫他Message池,但是通过分析应该叫有下一个Message引用的Message链更加适合. 其中Message.obtain(),通过源码分析就是获取断掉Message链关系的第一个Message.
Handler承担着接受子线程传过来的 (子线程用 sedMessage()或 sendEmptyMessage方法传弟 )Message对象 (里面包含数据 ),把这些消息放入主线程队列中,配合主线程进行更新 UI n使用 Handler,需要 implement 该类的 handleMessage(Message)方法,它是处理这些 Message的操作内容,例如 Update UI。通常需要子类化 Handler来实现 handleMessage方法。 n Handler 可以分发 Message 对象和 Runnable 对象到主线程中 , 每个 Handler 实 例 , 都会绑定到创建他的线程中 ( 一般是位于主线程 ), n它有两个作用 : ¨ 安排消息或 Runnable 在某个主线程中某个地方执行 , ¨安排一个动作在不同的线程中执行
n Message Queue消息队列,用来存放通过 Handler发布的消息,按照先进先出执行。 n 每个 message queue都会有一个对应的 Handler。 Handler会向 message queue通过两种方法发送消息: sendMessage或 post。这两种消息都会插在 message queue队尾并按先进先出执行。但通过这两种方法发送的消息执行的方式略有不同:通过 sendMessage发送的是一个 message对象 ,会被 Handler的 handleMessage()函数处理;而通过 post方法发送的是一个 runnable对象,则会自己执行。
n Looper是每条线程里的 Message Queue的管家。 Android没有 Global的 Message Queue,而 Android会自动替主线程 (UI线程 )建立 Message Queue,但在子线程里并没有建立 Message Queue。所以调用 Looper.getMainLooper()得到的主线程的 Looper不为 NULL,但调用 Looper.myLooper()得到当前线程的 Looper就有可能为 NULL。 n对于子线程使用 Looper, API Doc提供了正确的使用方法: 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 } }
n在 Looper.loop()方法运行开始后,循环地按照接收顺序取出 Message Queue里面的非 NULL的 Message。 n 一开始 Message Queue里面的 Message都是 NULL的。当 Handler.sendMessage(Message)到 Message Queue,该函数里面设置了那个 Message对象的 target属性是当前的 Handler对象。随后 Looper取出了那个 Message,则调用该 Message的 target指向的 Hander的 dispatchMessage函数对 Message进行处理。 ¨ 在 dispatchMessage方法里,如何处理 Message则由用户指定,三个判断,优先级从高到低: n Message里面的 Callback,一个实现了 Runnable接口的对象,其中 run函数做处理工作; n Handler里面的 mCallback指向的一个实现了 Callback接口的对象,由其 handleMessage进行处理; n 理消息 Handler对象对应的类继承并实现了其中 handleMessage函数,通过这个实现的 handleMessage函数处理消息。 n Handler处理完该 Message (update UI) 后, Looper则设置该 Message为 NULL,以便回收!
Android 使用 mHandler = new MyHandler(Looper.getMainLooper()); 可诞生用来处理 main线程的 Handler对象;其中, MyHandler是自已实现的 Handler的子类别。 同线程内不同组件间的消息传递 public class Activity1 extends Activity implements OnClickListener{ Button button = null; TextView text = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity1); button = (Button)findViewById(R.id.btn); button.setOnClickListener(this); text = (TextView)findViewById(R.id.content); } public void onClick(View v) { switch (v.getId()) { case R.id.btn: Looper looper = Looper.myLooper();//取得当前线程里的looper MyHandler mHandler = new MyHandler(looper);//构造一个handler使之可与looper通信 mHandler.removeMessages(0); String msgStr = "主线程不同组件通信:消息来自button"; Message m = mHandler.obtainMessage(1, 1, 1, msgStr);//构造要传递的消息 mHandler.sendMessage(m);//发送消息:系统会自动调用handleMessage方法来处理消息 break; } } private class MyHandler extends Handler{ public MyHandler(Looper looper){ super(looper); } public void handleMessage(Message msg) {//处理消息 text.setTex ……
}
}
子线程传递消息给主线程 private class MyThread extends Thread{ public void run() { Looper curLooper = Looper. myLooper (); Looper mainLooper = Looper. getMainLooper (); String msg ; if(curLooper==null){ mHandler = new MyHandler(mainLooper); msg = "curLooper is null"; }else{ mHandler = new MyHandler(curLooper); msg = "This is curLooper"; } mHandler.removeMessages(0); Message m = mHandler.obtainMessage(1, 1, 1, msg); mHandler.sendMessage(m); } } }
Android另外提供了一个工具类:AsyncTask。它使得UI thread的使用变得异常简单。它使创建需要与用户界面交互的长时间运行的任务变得更简单,不需要借助线程和Handler即可实现。 AsyncTask的构造函数的参数设置需要看明白:AsyncTask Params对应doInBackground(Params...)的参数类型。而new AsyncTask().execute(Params... params),就是传进来的Params数据,你可以execute(data)来传送一个数据,或者execute(data1, data2, data3)这样多个数据。 Progress对应onProgressUpdate(Progress...)的参数类型; Result对应onPostExecute(Result)的参数类型。 当以上的参数类型都不需要指明某个时,则使用Void,注意不是void。 实现AsyncTask中定义的下面一个或几个方法 onPreExecute() 开始执行前的准备工作; doInBackground(Params...) 开始执行后台处理,可以调用publishProgress方法来更新实时的任务进度; onProgressUpdate(Progress...) 在publishProgress方法被调用后,UI thread将调用这个方法从而在界面上展示任务的进展情况,例如通过一个进度条进行展示。 onPostExecute(Result) 执行完成后的操作,传送结果给UI 线程。 这4个方法都不能手动调用。而且除了doInBackground(Params...)方法,其余3个方法都是被UI线程所调用的,所以要求: AsyncTask的实例必须在UI thread中创建; AsyncTask.execute方法必须在UI thread中调用;
((Button) findViewById(R.id.load_AsyncTask)).setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View view) { data = null; data = new ArrayList(); adapter = null; //显示ProgressDialog放到AsyncTask.onPreExecute()里 //showDialog(PROGRESS_DIALOG); new ProgressTask().execute(data); } }); private class ProgressTask extends AsyncTask, Void, Integer> { /* 该方法将在执行实际的后台操作前被UI thread调用。可以在该方法中做一些准备工作,如在界面上显示一个进度条。*/ @Override protected void onPreExecute() { // 先显示ProgressDialog showDialog(PROGRESS_DIALOG); } /* 执行那些很耗时的后台计算工作。可以调用publishProgress方法来更新实时的任务进度。 */ @Override protected Integer doInBackground(ArrayList... datas) { ArrayList data = datas[0]; for (int i=0; i<8; i++) { data.add("ListItem"); } return STATE_FINISH; } /* 在doInBackground 执行完成后,onPostExecute 方法将被UI thread调用, 后台的计算结果将通过该方法传递到UI thread. * */ protected void onPostExecute(Integer result) { int state = result.intValue(); switch(state){ case STATE_FINISH: dismissDialog(PROGRESS_DIALOG); Toast.makeText(getApplicationContext(), "加载完成!", Toast.LENGTH_LONG) .show(); 。。。。。。 break; case STATE_ERROR: dismissDialog(PROGRESS_DIALOG); Toast.makeText(getApplicationContext(), "处理过程发生错误!",Toast.LENGTH_LONG).show(); 。。。。。 break; default: } }
public void handleMessage(Message msg) {//处理消息 text.setText(msg.obj.toString()); } } }
Handler承担着接受子线程传过来的 (子线程用 sedMessage()或 sendEmptyMessage方法传弟 )Message对象 (里面包含数据 ),把这些消息放入主线程队列中,配合主线程进行更新 UI n使用 Handler,需要 implement 该类的 handleMessage(Message)方法,它是处理这些 Message的操作内容,例如 Update UI。通常需要子类化 Handler来实现 handleMessage方法。 n Handler 可以分发 Message 对象和 Runnable 对象到主线程中 , 每个 Handler 实 例 , 都会绑定到创建他的线程中 ( 一般是位于主线程 ), n它有两个作用 : ¨ 安排消息或 Runnable 在某个主线程中某个地方执行 , ¨安排一个动作在不同的线程中执行
n Message Queue消息队列,用来存放通过 Handler发布的消息,按照先进先出执行。 n 每个 message queue都会有一个对应的 Handler。 Handler会向 message queue通过两种方法发送消息: sendMessage或 post。这两种消息都会插在 message queue队尾并按先进先出执行。但通过这两种方法发送的消息执行的方式略有不同:通过 sendMessage发送的是一个 message对象 ,会被 Handler的 handleMessage()函数处理;而通过 post方法发送的是一个 runnable对象,则会自己执行。
n Looper是每条线程里的 Message Queue的管家。 Android没有 Global的 Message Queue,而 Android会自动替主线程 (UI线程 )建立 Message Queue,但在子线程里并没有建立 Message Queue。所以调用 Looper.getMainLooper()得到的主线程的 Looper不为 NULL,但调用 Looper.myLooper()得到当前线程的 Looper就有可能为 NULL。 n对于子线程使用 Looper, API Doc提供了正确的使用方法: 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 } }
n在 Looper.loop()方法运行开始后,循环地按照接收顺序取出 Message Queue里面的非 NULL的 Message。 n 一开始 Message Queue里面的 Message都是 NULL的。当 Handler.sendMessage(Message)到 Message Queue,该函数里面设置了那个 Message对象的 target属性是当前的 Handler对象。随后 Looper取出了那个 Message,则调用该 Message的 target指向的 Hander的 dispatchMessage函数对 Message进行处理。 ¨ 在 dispatchMessage方法里,如何处理 Message则由用户指定,三个判断,优先级从高到低: n Message里面的 Callback,一个实现了 Runnable接口的对象,其中 run函数做处理工作; n Handler里面的 mCallback指向的一个实现了 Callback接口的对象,由其 handleMessage进行处理; n 理消息 Handler对象对应的类继承并实现了其中 handleMessage函数,通过这个实现的 handleMessage函数处理消息。 n Handler处理完该 Message (update UI) 后, Looper则设置该 Message为 NULL,以便回收!
Android 使用 mHandler = new MyHandler(Looper.getMainLooper()); 可诞生用来处理 main线程的 Handler对象;其中, MyHandler是自已实现的 Handler的子类别。 同线程内不同组件间的消息传递 public class Activity1 extends Activity implements OnClickListener{ Button button = null; TextView text = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity1); button = (Button)findViewById(R.id.btn); button.setOnClickListener(this); text = (TextView)findViewById(R.id.content); } public void onClick(View v) { switch (v.getId()) { case R.id.btn: Looper looper = Looper.myLooper();//取得当前线程里的looper MyHandler mHandler = new MyHandler(looper);//构造一个handler使之可与looper通信 mHandler.removeMessages(0); String msgStr = "主线程不同组件通信:消息来自button"; Message m = mHandler.obtainMessage(1, 1, 1, msgStr);//构造要传递的消息 mHandler.sendMessage(m);//发送消息:系统会自动调用handleMessage方法来处理消息 break; } } private class MyHandler extends Handler{ public MyHandler(Looper looper){ super(looper); } public void handleMessage(Message msg) {//处理消息 text.setTex ……
}
}
子线程传递消息给主线程 private class MyThread extends Thread{ public void run() { Looper curLooper = Looper. myLooper (); Looper mainLooper = Looper. getMainLooper (); String msg ; if(curLooper==null){ mHandler = new MyHandler(mainLooper); msg = "curLooper is null"; }else{ mHandler = new MyHandler(curLooper); msg = "This is curLooper"; } mHandler.removeMessages(0); Message m = mHandler.obtainMessage(1, 1, 1, msg); mHandler.sendMessage(m); } } }
Android另外提供了一个工具类:AsyncTask。它使得UI thread的使用变得异常简单。它使创建需要与用户界面交互的长时间运行的任务变得更简单,不需要借助线程和Handler即可实现。 AsyncTask的构造函数的参数设置需要看明白:AsyncTask
((Button) findViewById(R.id.load_AsyncTask)).setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View view) { data = null; data = new ArrayList
public void handleMessage(Message msg) {//处理消息 text.setText(msg.obj.toString()); } } }
更多相关文章
- Android支持HTML标签
- android文本内容自动朗读实例教程
- android利用线程池高效实现异步任务
- andr
- Android进阶知识:Handler相关
- FastBoot 刷机方法
- Android(安卓)Service生命周期及用法!
- 浅谈Java中Collections.sort对List排序的两种方法
- Python list sort方法的具体使用