Android下基於線程池的網絡訪問基礎框架


引言

  現在的Android開發很多都使用Volley、OkHttp、Retrofit等框架,這些框架固然有優秀的地方(以后會寫代碼學習分享),但是我們今天介紹一種基於Java線程池的網絡訪問框架。

實現思路及實現

  APP界面上面的數據都是通過網絡請求獲取的,我們能不能將網絡請求依次入隊,然后配合着Java線程池,讓線程依次處理我們的請求,最后返回結果給我們。下面我們先來看一下線程池工具類的實現:

 1 public class ThreadPoolUtils {
 2 
 3     private ThreadPoolUtils() {}
 4     //核心線程數
 5     private static int CORE_POOL_SIZE = 8;
 6     //最大線程數
 7     private static int MAX_POOL_SIZE = 64;
 8     //線程池中超過corePoolSize數目的空閑線程最大存活時間;可以allowCoreThreadTimeOut(true)使得核心線程有效時間
 9     private static int KEEP_ALIVE_TIME = 5;
10     //任務隊列
11     private static BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(64);
12 
13     private static ThreadPoolExecutor threadpool;
14 
15     static {
16         threadpool = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS, workQueue);
17     }
18 
19     public static void execute(Runnable runnable) {
20         threadpool.execute(runnable);
21     }
22 }

  我們來看一下ThreadPoolExecutor的構造函數及相關參數:

參數名 作用
corePoolSize 核心線程池大小
maximumPoolSize 最大線程池大小
keepAliveTime 線程池中超過corePoolSize數目的空閑線程最大存活時間;可以allowCoreThreadTimeOut(true)使得核心線程有效時間
TimeUnit keepAliveTime時間單位
workQueue 阻塞任務隊列
threadFactory 新建線程工廠
RejectedExecutionHandler 當提交任務數超過maxmumPoolSize+workQueue之和時,任務會交給RejectedExecutionHandler來處理

  重點講解:
  其中比較容易讓人誤解的是:corePoolSize,maximumPoolSize,workQueue之間關系。
  1.當線程池小於corePoolSize時,新提交任務將創建一個新線程執行任務,即使此時線程池中存在空閑線程。
  2.當線程池達到corePoolSize時,新提交任務將被放入workQueue中,等待線程池中任務調度執行
  3.當workQueue已滿,且maximumPoolSize>corePoolSize時,新提交任務會創建新線程執行任務
  4.當提交任務數超過maximumPoolSize時,新提交任務由RejectedExecutionHandler處理
  5.當線程池中超過corePoolSize線程,空閑時間達到keepAliveTime時,關閉空閑線程
  6.當設置allowCoreThreadTimeOut(true)時,線程池中corePoolSize線程空閑時間達到keepAliveTime也將關閉

網絡訪問的封裝

  通過上面的分析,我們知道ThreadPoolExecutor里面可以執行Runable對象,那么我們將網絡訪問邏輯封裝成Runable對象,然后扔進線程池進行執行。我們來看一下封裝的邏輯:

 1 /**
 2  * post線程
 3  */
 4 public class HttpPostThread implements Runnable {
 5 
 6     private Handler hand;
 7     private String strURL;
 8     private String method;
 9     private List<String> params;
10     private Handler netHand;
11 
12     public HttpPostThread(Handler hand, String strURL, String method, List<String> params) {
13         this.hand = hand;
14         //實際的傳值
15         this.strURL = strURL;
16         this.method = method;
17         this.params = params;
18     }
19 
20     public HttpPostThread(Handler hand, Handler netHand, String strURL, String method, List<String> params) {
21         this.hand = hand;
22         //實際的傳值
23         this.strURL = strURL;
24         this.method = method;
25         this.params = params;
26         this.netHand = netHand;
27     }
28 
29     @Override
30     public void run() {
31         Message msg = hand.obtainMessage();
32         try {
33             String result;
34             if(!strURL.startsWith("https")) {
35                 RpcHttp rpcHttp = new RpcHttp();
36                 result = rpcHttp.post(strURL, method, params);
37             }
38             else {
39                 RpcHttps rpcHttps = new RpcHttps();
40                 result = rpcHttps.post(strURL, method, params);
41             }
42             /**
43              * 根據訪問http來設置標識位
44              * 然后發送msg到handlerMessage進行處理(此處配合Handler進行使用)
45              */
46             if (result.equals("noNet")) {
47                 if (netHand != null) {
48                     netHand.sendEmptyMessage(600);
49                 }
50             } else {
51                 msg.what = 200;
52                 msg.obj = result;
53             }
54         } catch(Exception e){
55             e.printStackTrace();
56         }
57         finally {
58             hand.sendMessage(msg);
59         }
60     }
61 }

  我們看到,我們封裝的這個類的構造函數只需要使用者提供回調的Handler、Http訪問的Url、訪問的方法及參數。這樣就可以將其放入線程中進行處理,然后我們只需要在客戶端使用寫好回調的Handler即可。我們看34-40行,這時候我們看到會使用封裝的Http類去進行網絡訪問,我們來看一下:

 1  /**
 2      * post請求
 3      *
 4      * @param strURL 請求的地址
 5      * @param method 請求方法
 6      * @param params 請求元素
 7      * @return
 8      */
 9     public String post(String strURL, String method, List<String> params) {
10         Log.e("開始請求","獲取請求");
11         String RequestParams = "";
12         long timestamp = System.currentTimeMillis();
13         RequestParams += "{\"method\":\"" + method + "\"";
14         if (params != null && params.size() > 0) {
15             RequestParams += ",\"params\":{";
16             for (String item : params) {
17                 String first = item.substring(0, item.indexOf(":"));
18                 String second = item.substring(item.indexOf(":") + 1);
19                 RequestParams += "\"" + first + "\":\"" + second + "\",";
20             }
21 
22             RequestParams = RequestParams.substring(0, (RequestParams.length() - 1));
23             RequestParams += "}";
24         } else {
25             RequestParams += ",\"params\":{}";
26         }
27         RequestParams += ",\"id\":\"" + timestamp + "\"";
28         RequestParams += "}";
29         return this.post(strURL, RequestParams);
30     }
31 
32     private String post(String strURL, String params) {
33         try {
34             URL url = new URL(strURL);// 創建連接
35             HttpURLConnection connection = (HttpURLConnection) url.openConnection();
36 
37             connection.setDoOutput(true);
38             connection.setDoInput(true);
39             connection.setUseCaches(false);
40             connection.setInstanceFollowRedirects(true);
41             connection.setRequestMethod("POST"); // 設置請求方式
42             connection.setRequestProperty("Accept", "application/json"); // 設置接收數據的格式
43             connection.setRequestProperty("Content-Type", "application/json"); // 設置發送數據的格式
44             connection.setConnectTimeout(10000);//設置超時
45             connection.setReadTimeout(10000);//設置超時
46             Log.e("開始連接","開始連接");
47             connection.connect();
48 
49             OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream(), "UTF-8"); // utf-8編碼
50             out.append(params);
51             out.flush();
52             out.close();
53 
54             String result = convertStreamToString(connection.getInputStream());
55             Log.e("responseContent",result);
56             return result;
57         } catch (Exception e) {
58             Log.e("responseException",String.valueOf(e.getStackTrace()));
59             Log.e("responseException",String.valueOf(e.getLocalizedMessage()));
60             Log.e("responseException",String.valueOf(e.getMessage()));
61             e.printStackTrace();
62         }
63         return "noNet"; // 自定義錯誤信息
64     }

  我們看到,我們將Http訪問進行了簡單的封裝。在客戶端使用的時候我們就只需要簡單的幾行代碼即可:

1 List<String> params = new ArrayList<>();
2 params.add("access_token:" + getAccessToken());
3 //開始用戶更新信息
4 ThreadPoolUtils.execute(new HttpPostThread(userhand, APIAdress.UserClass, APIAdress.GetUserInfoMethod, params));

  我們看到,我們創建了一個Runable實例,然后傳遞了回調的Handler、Url、Method及參數。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM