歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Android多線程之Handler、Looper、Message在基於HTTP系統中的應用

Android多線程之Handler、Looper、Message在基於HTTP系統中的應用

日期:2017/3/1 10:18:28   编辑:Linux編程

1.背景

在應用TCP/IP協議進行數據傳輸的時候,經常用到的是IOCP的概念。我們經常試想如果HTTP的能夠應用多線程的模式來進行數據的交互,將會給系統/應用帶來更好的用戶體驗。通過線程訪問WEB獲取數據並將數據交給另一個線程處理是本節研究的重點。關於Handler、Looper、Message詳細的原理可以參考其他文章。這裡推薦《Android Looper和Handler分析》(見 http://www.linuxidc.com/Linux/2012-07/64095.htm)本人也是受到其啟發,設計了一個簡單的應用框架。

2.應用功能/任務

(1) 連接服務器獲取控制指令;

(2) 執行服務器的命令;

(3) 返回執行結果;

3.設計

系統設計總圖如下圖所示,系統由三個線程組成:主線程、連接服務器線程、數據處理線程。

3.1基本原理

主線程用來設置定時器,開啟線程;ConnectThread用來連接服務器,ConnectThread獲取的數據發送給DataProcessThread,而DataProcessThread則僅僅進行數據處理,數據處理完成之後,又通過Message將結果告知ConnectThread,由ConnectThread將處理結果返回給服務器。

也就是說,在整個過程中,與服務器進行數據交互的是ConnectThread,數據處理是DataProcessThread,並且僅僅是這樣。

線程ConnectThread和DataProcessThread的數據交互則通過Handler、Looper等接口來完成。ConnectThread和DataProcessThread各與一個私有的Looper和公共的Handler (分別設為handler1、handler2)綁定。

這裡要注意的是,線程不存在默認的Looper,只能自行創建。並且只能在線程內部創建。如下實例:為每個線程創建一個Handler的繼承類,而handleMessage則是進行數據提取的真正方法。

  1. //定義子線程類中的接收消息
  2. class ThreadHandler extends Handler{
  3. public ThreadHandler(Looper looper){
  4. super(looper);
  5. }
  6. @Override
  7. public void handleMessage(Message msg) {
  8. switch (msg.what) {
  9. case UPDATE_DATA://常量
  10. getData();
  11. break;
  12. default:
  13. break;
  14. }
  15. }
  16. }
  17. //接收數據、處理線程
  18. private Thread ReceiveThread = new Thread(){
  19. public void run()
  20. {
  21. Looper.prepare();
  22. //當前線程的Looper對象
  23. handler1=new ThreadHandler(Looper.myLooper());
  24. Looper.loop();
  25. }
  26. };


在兩個線程進行數據傳輸的時候,可以采取兩種方式:

①設置Request響應的全局變量Response,當ConnectThread請求到數據之後,通過handler2.sendEmptyMessage(int what)方法告知DataProcessThread,而DataProcessThread一旦接收到ConnectThread發來的空消息(因為是sendEmptyMessage發來的),則通過Response來獲取數據,並進行命令執行;

② ConnectThread利用包android.os.Handler中的obtainMessage (int what, int arg1, int arg2,Object obj)和sendMessage (Message msg)對接收數據直接進行封裝並發送給DataProcessThread,DataProcessThread再進行命令執��。

這兩種方法就好比,我們在取信件的時候有兩種方式一樣,一是人家告訴我,我自己去拿二人家直接給我送來;

測試代碼:(本人加入一些顯示界面)

  1. package home.handler;
  2. import java.io.BufferedReader;
  3. import java.io.IOException;
  4. import java.io.InputStream;
  5. import java.io.InputStreamReader;
  6. import java.util.Timer;
  7. import java.util.TimerTask;
  8. import org.apache.http.HttpEntity;
  9. import org.apache.http.HttpResponse;
  10. import org.apache.http.client.HttpClient;
  11. import org.apache.http.client.methods.HttpGet;
  12. import org.apache.http.impl.client.DefaultHttpClient;
  13. import android.app.Activity;
  14. import android.os.Bundle;
  15. import android.os.Handler;
  16. import android.os.Looper;
  17. import android.os.Message;
  18. import android.view.View;
  19. import android.widget.Button;
  20. import android.widget.EditText;
  21. public class PHPHandlerActivity extends Activity {
  22. protected static final int UPDATE_TEXT = 0;
  23. protected static final int RETURN_RESULT = 1;
  24. private Handler handler1,handler2,handler3;
  25. private EditText etGet;
  26. //private HttpPost request;
  27. //private HttpClient client;
  28. private HttpResponse response=null;
  29. /** Called when the activity is first created. */
  30. @Override
  31. public void onCreate(Bundle savedInstanceState) {
  32. super.onCreate(savedInstanceState);
  33. setContentView(R.layout.main);
  34. etGet = (EditText)findViewById(R.id.etGet);
  35. //按鈕函數:開啟線程
  36. final Button mThreadStartButton=(Button)findViewById(R.id.button1);
  37. mThreadStartButton.setOnClickListener(new Button.OnClickListener() {
  38. @Override
  39. public void onClick(View v) {
  40. // TODO Auto-generated method stub
  41. ReceiveThread.start();
  42. Timer timer = new Timer();
  43. timer.schedule(new mTask(), 30, 1000*60*2);
  44. mThreadStartButton.setEnabled(false);
  45. }
  46. });
  47. }
  48. //*****************************************************************************************
  49. //從此處添加自定義函數
  50. //*****************************************************************************************
  51. class MyHandler extends Handler{
  52. public MyHandler(Looper looper){
  53. super(looper);
  54. }
  55. @Override
  56. public void handleMessage(Message msg){
  57. super.handleMessage(msg);
  58. etGet.setText("主線程的Handler,收到了消息:"+(String)msg.obj);
  59. }
  60. }
  61. //返回執行結果Handler
  62. class ReturnHandler extends Handler{
  63. public ReturnHandler(Looper looper){
  64. super(looper);
  65. }
  66. @Override
  67. public void handleMessage(Message msg){
  68. super.handleMessage(msg);
  69. switch (msg.what) {
  70. case RETURN_RESULT:
  71. phpweb();
  72. break;
  73. default:
  74. break;
  75. }
  76. }
  77. }
  78. //定時器線程,連接服務器線程
  79. private class mTask extends TimerTask{
  80. @Override
  81. public void run() {
  82. //連接服務器
  83. HttpResponse response=phpweb();
  84. if (response!=null)
  85. handler1.sendEmptyMessage(UPDATE_TEXT);
  86. Looper.prepare();
  87. //當前線程的Looper對象
  88. handler3=new ReturnHandler(Looper.myLooper());
  89. Looper.loop();
  90. }
  91. }
  92. //定義子線程類中的接收消息
  93. class ThreadHandler extends Handler{
  94. public ThreadHandler(Looper looper){
  95. super(looper);
  96. }
  97. @Override
  98. public void handleMessage(Message msg) {
  99. switch (msg.what) {
  100. case UPDATE_TEXT:
  101. getData();
  102. break;
  103. default:
  104. break;
  105. }
  106. }
  107. }
  108. //接收數據、處理線程
  109. private Thread ReceiveThread = new Thread(){
  110. public void run()
  111. {
  112. Looper.prepare();
  113. //當前線程的Looper對象
  114. handler1=new ThreadHandler(Looper.myLooper());
  115. Looper.loop();
  116. }
  117. };
  118. //數據流轉換為字符串
  119. private static String convertStreamToString(InputStream is) {
  120. BufferedReader reader = new BufferedReader(new InputStreamReader(is));
  121. StringBuilder sb = new StringBuilder();
  122. String line = null;
  123. try {
  124. while ((line = reader.readLine()) != null) {
  125. sb.append(line + "\r\n");
  126. }
  127. } catch (IOException e) {
  128. e.printStackTrace();
  129. } finally {
  130. try {
  131. is.close();
  132. } catch (IOException e) {
  133. e.printStackTrace();
  134. }
  135. }
  136. return sb.toString();
  137. }
  138. //訪問web函數
  139. private HttpResponse phpweb(){
  140. try {
  141. HttpClient client = new DefaultHttpClient();
  142. String url = "http://www.linuxidc.com";
  143. HttpGet httpGetRequest=new HttpGet(url);
  144. //響應
  145. response = client.execute(httpGetRequest);
  146. return response;
  147. }
  148. catch (Exception e) {
  149. // TODO: handle exception
  150. e.printStackTrace();
  151. }
  152. return response;
  153. }
  154. //獲取數據函數
  155. private void getData() {
  156. try
  157. {
  158. HttpEntity entity = response.getEntity();
  159. //返回值不為空
  160. if (entity != null) {
  161. InputStream instream = entity.getContent();
  162. String result = convertStreamToString(instream);
  163. //將收到的數據返回給主界面:主線程--構造別人的Handler
  164. handler2 = new MyHandler(Looper.getMainLooper());
  165. Message msg2 = handler2.obtainMessage(1,1,1,result);
  166. handler2.sendMessage(msg2);
  167. handler3.sendEmptyMessage(RETURN_RESULT);
  168. }
  169. }
  170. catch (Exception e)
  171. {
  172. }
  173. }
  174. }
Copyright © Linux教程網 All Rights Reserved