Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> Android應用開發教程之二十九(終結篇):線程池的經典使用

Android應用開發教程之二十九(終結篇):線程池的經典使用

編輯:關於android開發

  由於經常會在網上或群裡看到有朋友會問線程方面的東西,就像我一個朋友他們老師講的,J2SE、J2EE裡面使用的線程方面的東西可能不是太多 ,但是在Android開發裡面,玩的就是線程(UI Thread)! 好了,廢話就說這麼多吧,直入正題!今天要講的東西就是線程池、線程的高效率使用,靈活控制!今天死馬我就用最常用的幾種方式來分別實現應用中使用的線程方面的知識,(共寫了兩個不同入口的Activity來分開不同的實現方式,大家可以自行注釋AndroidManifest.xml中的Launch入口或打開注釋)好了,先隨便列幾個吧,如:AsyncTask 、Runnable 、Thread、ThreadPool、 Executors等等的使用,看我文章的朋友應該都很清楚我的方式啦,果斷先上效果,再一步步分解代碼,來吧,效果圖如下:

  一:無大小限制的線程池執行效果如下

Android應用開發教程之二十九(終結篇):線程池的經典使用

  二:限制按順序來執行任務的線程池效果如下

Android應用開發教程之二十九(終結篇):線程池的經典使用

  三:一個一個任務的執行線程池效果如下(與按順序執行效果是一樣的,只是內部實現稍有不同)

Android應用開發教程之二十九(終結篇):線程池的經典使用

  四:按指定個數來執行任務的線程池效果如下

Android應用開發教程之二十九(終結篇):線程池的經典使用

  五:創建一個可在指定時間裡執行任務的線程池,亦可重復執行,不常用,效果與四相同

Android應用開發教程之二十九(終結篇):線程池的經典使用

  六:按指定工廠模式來執行的線程池,效果與四、五一樣,但用方式六創建的線程池都有在工廠中指定的線程屬性,

  比如:線程名字、是否為用戶線程等等屬性

Android應用開發教程之二十九(終結篇):線程池的經典使用

  七:線程池中任務執行時可暫停效果圖如下

Android應用開發教程之二十九(終結篇):線程池的經典使用

  八:用Runnable、ConcurrentLinkedQueue、ConcurrentMap、Future、ExecutorService關聯實現的效果圖如下

Android應用開發教程之二十九(終結篇):線程池的經典使用

  哦的了,效果看完了,現在就請大家自行修改AndroidManifest.xml中主Activity的入口來看兩種不同方式實現的代碼效果吧,首先,先貼一下Main.java類的代碼,希望大家詳細看裡面的注釋,一定要詳細看,你不會吃虧的,相信我!(備注:為了寫文章加注釋還有查找的時候方便,把所有的主類及輔助類以內部類的形式寫到一個.java文件裡面了,如果朋友們覺得看著亂,不爽的話,可以自行將裡面的類抽取到單獨的.java文件中,幾分鐘搞定的事!)

  方式一(純ExecutorService、AsyncTask、Runnable關聯實現相關文件如下):

  1.1:主類文件(Main.java)

Java代碼
  1. /* 
  2.  * FileName:  Main.java 
  3.  * CopyRight:  Belong to  <XiaoMaGuo Technologies > own  
  4.  * Description:  <description> 
  5.  * Modify By :  XiaoMaGuo ^_^  
  6.  * Modify Date:   2013-10-15 
  7.  * Follow Order No.:  <Follow Order No.> 
  8.  * Modify Order No.:  <Modify Order No.> 
  9.  * Modify Content:  <modify content > 
  10.  */  
  11. package com.xiaoma.threadpooltest;  
  12.    
  13. import java.util.ArrayList;  
  14. import java.util.List;  
  15. import java.util.concurrent.ExecutorService;  
  16. import java.util.concurrent.Executors;  
  17. import java.util.concurrent.ThreadFactory;  
  18.    
  19. import android.annotation.TargetApi;  
  20. import android.app.Activity;  
  21. import android.content.Context;  
  22. import android.os.AsyncTask;  
  23. import android.os.Build;  
  24. import android.os.Bundle;  
  25. import android.os.SystemClock;  
  26. import android.util.AttributeSet;  
  27. import android.util.Log;  
  28. import android.view.LayoutInflater;  
  29. import android.view.View;  
  30. import android.view.ViewGroup;  
  31. import android.widget.AdapterView;  
  32. import android.widget.AdapterView.OnItemClickListener;  
  33. import android.widget.BaseAdapter;  
  34. import android.widget.LinearLayout;  
  35. import android.widget.ListView;  
  36. import android.widget.ProgressBar;  
  37. import android.widget.TextView;  
  38. import android.widget.Toast;  
  39.    
  40. /** 
  41.  * @TODO [The Class File Description] 
  42.  * @author XiaoMaGuo ^_^ 
  43.  * @version [version-code, 2013-10-15] 
  44.  * @since [Product/module] 
  45.  */  
  46. @TargetApi(Build.VERSION_CODES.HONEYCOMB)  
  47. public class Main extends Activity  
  48. {  
  49.     private static int order = 0;  
  50.    
  51.     /** 總共多少任務(根據CPU個數決定創建活動線程的個數,這樣取的好處就是可以讓手機承受得住) */  
  52.     // private static final int count = Runtime.getRuntime().availableProcessors() * 3 + 2;  
  53.    
  54.     /** 總共多少任務(我是在模擬器裡面跑的,為了效果明顯,所以寫死了為10個,如果在手機上的話,推薦使用上面的那個count) */  
  55.     private static final int count = 10;  
  56.    
  57.     /** 每次只執行一個任務的線程池 */  
  58.     private static ExecutorService singleTaskExecutor = null;  
  59.    
  60.     /** 每次執行限定個數個任務的線程池 */  
  61.     private static ExecutorService limitedTaskExecutor = null;  
  62.    
  63.     /** 所有任務都一次性開始的線程池 */  
  64.     private static ExecutorService allTaskExecutor = null;  
  65.    
  66.     /** 創建一個可在指定時間裡執行任務的線程池,亦可重復執行 */  
  67.     private static ExecutorService scheduledTaskExecutor = null;  
  68.    
  69.     /** 創建一個可在指定時間裡執行任務的線程池,亦可重復執行(不同之處:使用工程模式) */  
  70.     private static ExecutorService scheduledTaskFactoryExecutor = null;  
  71.    
  72.     private List<AsyncTaskTest> mTaskList = null;  
  73.    
  74.     /** 任務是否被取消 */  
  75.     private boolean isCancled = false;  
  76.    
  77.     /** 是否點擊並取消任務標示符 */  
  78.     private boolean isClick = false;  
  79.    
  80.     /** 線程工廠初始化方式一 */  
  81.     ThreadFactory tf = Executors.defaultThreadFactory();  
  82.    
  83.     /** 線程工廠初始化方式二 */  
  84.     private static class ThreadFactoryTest implements ThreadFactory  
  85.     {  
  86.    
  87.         @Override  
  88.         public Thread newThread(Runnable r)  
  89.         {  
  90.             Thread thread = new Thread(r);  
  91.             thread.setName("XiaoMaGuo_ThreadFactory");  
  92.             thread.setDaemon(true); // 將用戶線程變成守護線程,默認false  
  93.             return thread;  
  94.         }  
  95.     }  
  96.    
  97.     static  
  98.     {  
  99.         singleTaskExecutor = Executors.newSingleThreadExecutor();// 每次只執行一個線程任務的線程池  
  100.         limitedTaskExecutor = Executors.newFixedThreadPool(3);// 限制線程池大小為7的線程池  
  101.         allTaskExecutor = Executors.newCachedThreadPool(); // 一個沒有限制最大線程數的線程池  
  102.         scheduledTaskExecutor = Executors.newScheduledThreadPool(3);// 一個可以按指定時間可周期性的執行的線程池  
  103.         scheduledTaskFactoryExecutor = Executors.newFixedThreadPool(3, new ThreadFactoryTest());// 按指定工廠模式來執行的線程池  
  104.         scheduledTaskFactoryExecutor.submit(new Runnable()  
  105.         {  
  106.    
  107.             @Override  
  108.             public void run()  
  109.             {  
  110.                 Log.i("KKK", "This is the ThreadFactory Test  submit Run! ! ! ");  
  111.             }  
  112.         });  
  113.     };  
  114.    
  115.     @Override  
  116.     public void onCreate(Bundle icicle)  
  117.     {  
  118.         super.onCreate(icicle);  
  119.         setContentView(R.layout.demo);  
  120.         final ListView taskList = (ListView)findViewById(R.id.task_list);  
  121.         taskList.setAdapter(new AsyncTaskAdapter(getApplication(), count));  
  122.         taskList.setOnItemClickListener(new OnItemClickListener()  
  123.         {  
  124.    
  125.             @Override  
  126.             public void onItemClick(AdapterView<?> parent, View view, int position, long id)  
  127.             {  
  128.                 if (position == 0) // 以第一項為例,來測試關閉線程池  
  129.                 {  
  130.                     /** 
  131.                      * 會關閉線程池方式一:但不接收新的Task,關閉後,正在等待 執行的任務不受任何影響,會正常執行,無返回值! 
  132.                      */  
  133.                     // allTaskExecutor.shutdown();  
  134.    
  135.                     /** 
  136.                      * 會關閉線程池方式二:也不接收新的Task,並停止正等待執行的Task(也就是說, 執行到一半的任務將正常執行下去),最終還會給你返回一個正在等待執行但線程池關閉卻沒有被執行的Task集合! 
  137.                      */  
  138.                     List<Runnable> unExecRunn = allTaskExecutor.shutdownNow();  
  139.    
  140.                     for (Runnable r : unExecRunn)  
  141.                     {  
  142.                         Log.i("KKK", "未執行的任務信息:=" + unExecRunn.toString());  
  143.                     }  
  144.                     Log.i("KKK", "Is shutdown ? = " + String.valueOf(allTaskExecutor.isShutdown()));  
  145.                     allTaskExecutor = null;  
  146.                 }  
  147.    
  148.                 // 以第二項為例來測試是否取消執行的任務  
  149.                 AsyncTaskTest sat = mTaskList.get(1);  
  150.                 if (position == 1)  
  151.                 {  
  152.                     if (!isClick)  
  153.                     {  
  154.                         sat.cancel(true);  
  155.                         isCancled = true;  
  156.                         isClick = !isClick;  
  157.                     }  
  158.                     else  
  159.                     {  
  160.                         sat.cancel(false);  
  161.                         isCancled = false;  
  162.                         // isClick = false;  
  163.                         isClick = !isClick;  
  164.                         if (null != sat && sat.getStatus() == AsyncTask.Status.RUNNING)  
  165.                         {  
  166.                             if (sat.isCancelled())  
  167.                             {  
  168.                                 sat = new AsyncTaskTest(sat.mTaskItem);  
  169.                             }  
  170.                             else  
  171.                             {  
  172.                                 Toast.makeText(Main.this, "A task is already running, try later", Toast.LENGTH_SHORT)  
  173.                                     .show();  
  174.                             }  
  175.                         }  
  176.    
  177.                         /** 
  178.                          * 由於上面測試關閉,在不重新生成allTaskExecutor的同時,會報異常(沒有可以使用的線程池,故此處重新生成線程池對象) 
  179.                          */  
  180.                         if (allTaskExecutor == null)  
  181.                         {  
  182.                             allTaskExecutor = Executors.newCachedThreadPool();  
  183.                         }  
  184.                         sat.executeOnExecutor(allTaskExecutor); // The task is already running(這也是個異常哦,小心使用! )  
  185.                     }  
  186.                 }  
  187.                 else  
  188.                 {  
  189.                     sat.cancel(false);  
  190.                     isCancled = false;  
  191.                     // sat.execute(sat.mTaskItem);  
  192.                     // sat.executeOnExecutor(allTaskExecutor);  
  193.                 }  
  194.    
  195.             }  
  196.         });  
  197.     }  
  198.    
  199.     /** 
  200.      * @TODO [ListView Item的條目適配器] 
  201.      * @author XiaoMaGuo ^_^ 
  202.      * @version [version-code, 2013-10-22] 
  203.      * @since [Product/module] 
  204.      */  
  205.     private class AsyncTaskAdapter extends BaseAdapter  
  206.     {  
  207.         private Context mContext;  
  208.    
  209.         private LayoutInflater mFactory;  
  210.    
  211.         private int mTaskCount;  
  212.    
  213.         public AsyncTaskAdapter(Context context, int taskCount)  
  214.         {  
  215.             mContext = context;  
  216.             mFactory = LayoutInflater.from(mContext);  
  217.             mTaskCount = taskCount;  
  218.             mTaskList = new ArrayList<AsyncTaskTest>(taskCount);  
  219.         }  
  220.    
  221.         @Override  
  222.         public int getCount()  
  223.         {  
  224.             return mTaskCount;  
  225.         }  
  226.    
  227.         @Override  
  228.         public Object getItem(int position)  
  229.         {  
  230.             return mTaskList.get(position);  
  231.         }  
  232.    
  233.         @Override  
  234.         public long getItemId(int position)  
  235.         {  
  236.             return position;  
  237.         }  
  238.    
  239.         @Override  
  240.         public View getView(int position, View convertView, ViewGroup parent)  
  241.         {  
  242.             if (convertView == null)  
  243.             {  
  244.                 convertView = mFactory.inflate(R.layout.list_view_item, null);  
  245.                 AsyncTaskTest task = new AsyncTaskTest((MyListItem)convertView);  
  246.    
  247.                 /** 
  248.                  * 下面兩種任務執行效果都一樣,形變質不變 
  249.                  * */  
  250.                 // task.execute();  
  251.                 // task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);  
  252.    
  253.                 /** 
  254.                  * 下面的方式在小於API 11級時效果是一樣的,但在高版本中的稍微有點不同,可以看以下AsyncTask核心變量的定義就知道了使用如下 
  255.                  * 方式時,系統會默認的采用五個一組,五個一組的方式來執行我們的任務,定義在:AsyncTask.class中,private static final int CORE_POOL_SIZE = 5; 
  256.                  * */  
  257.                 // use AsyncTask#THREAD_POOL_EXECUTOR is the same to older version #execute() (less than API 11)  
  258.                 // but different from newer version of #execute()  
  259.                 // task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);  
  260.    
  261.                 /** 
  262.                  * 一個一個執行我們的任務,效果與按順序執行是一樣的(AsyncTask.SERIAL_EXECUTOR) 
  263.                  * */  
  264.                 // task.executeOnExecutor(singleTaskExecutor);  
  265.    
  266.                 /** 
  267.                  * 按我們指定的個數來執行任務的線程池 
  268.                  * */  
  269.                 // task.executeOnExecutor(limitedTaskExecutor);  
  270.    
  271.                 /** 
  272.                  * 不限定指定個數的線程池,也就是說:你往裡面放了幾個任務,他全部同一時間開始執行, 不管你手機受得了受不了 
  273.                  * */  
  274.                 task.executeOnExecutor(allTaskExecutor);  
  275.    
  276.                 /** 
  277.                  * 創建一個可在指定時間裡執行任務的線程池,亦可重復執行 
  278.                  * */  
  279.                 // task.executeOnExecutor(scheduledTaskExecutor);  
  280.    
  281.                 /** 
  282.                  * 創建一個按指定工廠模式來執行任務的線程池,可能比較正規,但也不常用 
  283.                  */  
  284.                 // task.executeOnExecutor(scheduledTaskFactoryExecutor);  
  285.                 mTaskList.add(task);  
  286.             }  
  287.             return convertView;  
  288.         }  
  289.     }  
  290.    
  291.     class AsyncTaskTest extends AsyncTask<Void, Integer, Void>  
  292.     {  
  293.         private MyListItem mTaskItem;  
  294.    
  295.         private String id;  
  296.    
  297.         private AsyncTaskTest(MyListItem item)  
  298.         {  
  299.             mTaskItem = item;  
  300.             if (order < count || order == count)  
  301.             {  
  302.                 id = "執行:" + String.valueOf(++order);  
  303.             }  
  304.             else  
  305.             {  
  306.                 order = 0;  
  307.                 id = "執行:" + String.valueOf(++order);  
  308.             }  
  309.         }  
  310.    
  311.         @Override  
  312.         protected void onPreExecute()  
  313.         {  
  314.             mTaskItem.setTitle(id);  
  315.         }  
  316.    
  317.         /** 
  318.          * Overriding methods 
  319.          */  
  320.         @Override  
  321.         protected void onCancelled()  
  322.         {  
  323.             super.onCancelled();  
  324.         }  
  325.    
  326.         @Override  
  327.         protected Void doInBackground(Void... params)  
  328.         {  
  329.             if (!isCancelled() && isCancled == false) // 這個地方很關鍵,如果不設置標志位的話,直接setCancel(true)是無效的  
  330.             {  
  331.                 int prog = 0;  
  332.    
  333.                 /** 
  334.                  * 下面的while中,寫了個分支用來做個假象(任務東西剛開始下載的時候,速度快,快下載完成的時候就突然間慢了下來的效果, 大家可以想象一下,類似 
  335.                  * :PP手機助手、91手機助手中或其它手機應用中,幾乎都有這個假象,開始快,結束時就下載變慢了,講白了 就是開發的人不想讓你在下載到大於一半的時候,也就是快下載完的時候去點取消,你那樣得多浪費 
  336.                  * !所以造個假象,讓你不想去取消而已) 
  337.                  */  
  338.                 while (prog < 101)  
  339.                 {  
  340.    
  341.                     if ((prog > 0 || prog == 0) && prog < 70) // 小於70%時,加快進度條更新  
  342.                     {  
  343.                         SystemClock.sleep(100);  
  344.                     }  
  345.                     else  
  346.                     // 大於70%時,減慢進度條更新  
  347.                     {  
  348.                         SystemClock.sleep(300);  
  349.                     }  
  350.    
  351.                     publishProgress(prog); // 更新進度條  
  352.                     prog++;  
  353.                 }  
  354.             }  
  355.             return null;  
  356.         }  
  357.    
  358.         @Override  
  359.         protected void onPostExecute(Void result)  
  360.         {  
  361.         }  
  362.    
  363.         @Override  
  364.         protected void onProgressUpdate(Integer... values)  
  365.         {  
  366.             mTaskItem.setProgress(values[0]); // 設置進度  
  367.         }  
  368.     }  
  369. }  
  370.    
  371. /** 
  372.  * @TODO [一個簡單的自定義 ListView Item] 
  373.  * @author XiaoMaGuo ^_^ 
  374.  * @version [version-code, 2013-10-22] 
  375.  * @since [Product/module] 
  376.  */  
  377. class MyListItem extends LinearLayout  
  378. {  
  379.     private TextView mTitle;  
  380.    
  381.     private ProgressBar mProgress;  
  382.    
  383.     public MyListItem(Context context, AttributeSet attrs)  
  384.     {  
  385.         super(context, attrs);  
  386.     }  
  387.    
  388.     public MyListItem(Context context)  
  389.     {  
  390.         super(context);  
  391.     }  
  392.    
  393.     public void setTitle(String title)  
  394.     {  
  395.         if (mTitle == null)  
  396.         {  
  397.             mTitle = (TextView)findViewById(R.id.task_name);  
  398.         }  
  399.         mTitle.setText(title);  
  400.     }  
  401.    
  402.     public void setProgress(int prog)  
  403.     {  
  404.         if (mProgress == null)  
  405.         {  
  406.             mProgress = (ProgressBar)findViewById(R.id.task_progress);  
  407.         }  
  408.         mProgress.setProgress(prog);  
  409.     }  
  410. }  

  1.2:布局文件

XML/HTML代碼
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:paddingLeft="10dip"  
  6.     android:paddingRight="10dip"  
  7.     android:orientation="vertical" >  
  8.     <ListView android:id="@+id/task_list"  
  9.         android:layout_width="fill_parent"  
  10.         android:layout_height="wrap_content"  
  11.         android:divider="#cccccc"  
  12.         android:dividerHeight="0.6dip"  
  13.         android:footerDividersEnabled="true"  
  14.         android:headerDividersEnabled="true" />  
  15. </LinearLayout>  

  方式二(Runnable、ConcurrentLinkedQueue、ConcurrentMap、Future、ExecutorService關聯實現的相關文件如 下):

  2.1:主類文件(MyRunnableActivity.java)

Java代碼
  1. /* 
  2.  * FileName:  MyRunnableActivity.java 
  3.  * CopyRight:  Belong to  <XiaoMaGuo Technologies > own  
  4.  * Description:  <description> 
  5.  * Modify By :  XiaoMaGuo ^_^  
  6.  * Modify Date:   2013-10-21 
  7.  * Follow Order No.:  <Follow Order No.> 
  8.  * Modify Order No.:  <Modify Order No.> 
  9.  * Modify Content:  <modify content > 
  10.  */  
  11. package com.xiaoma.threadpooltest;  
  12.    
  13. import java.util.Iterator;  
  14. import java.util.Map;  
  15. import java.util.concurrent.ConcurrentHashMap;  
  16. import java.util.concurrent.ConcurrentLinkedQueue;  
  17. import java.util.concurrent.ConcurrentMap;  
  18. import java.util.concurrent.ExecutorService;  
  19. import java.util.concurrent.Executors;  
  20. import java.util.concurrent.Future;  
  21.    
  22. import android.app.Activity;  
  23. import android.os.Bundle;  
  24. import android.os.Handler;  
  25. import android.os.Message;  
  26. import android.util.Log;  
  27. import android.view.View;  
  28. import android.view.View.OnClickListener;  
  29. import android.widget.ProgressBar;  
  30. import android.widget.Toast;  
  31.    
  32. /** 
  33.  * @TODO [線程池控制 ] 
  34.  * @author XiaoMaGuo ^_^ 
  35.  * @version [version-code, 2013-10-22] 
  36.  * @since [Product/module] 
  37.  */  
  38. public class MyRunnableActivity extends Activity implements OnClickListener  
  39. {  
  40.    
  41.     /** 任務執行隊列 */  
  42.     private ConcurrentLinkedQueue<MyRunnable> taskQueue = null;  
  43.    
  44.     /** 
  45.      * 正在等待執行或已經完成的任務隊列 
  46.      *  
  47.      * 備注:Future類,一個用於存儲異步任務執行的結果,比如:判斷是否取消、是否可以取消、是否正在執行、是否已經完成等 
  48.      *  
  49.      * */  
  50.     private ConcurrentMap<Future, MyRunnable> taskMap = null;  
  51.    
  52.     /** 
  53.      * 創建一個不限制大小的線程池 此類主要有以下好處 1,以共享的無界隊列方式來運行這些線程. 2,執行效率高。 3,在任意點,在大多數 nThreads 線程會處於處理任務的活動狀態 
  54.      * 4,如果在關閉前的執行期間由於失敗而導致任何線程終止,那麼一個新線程將代替它執行後續的任務(如果需要)。 
  55.      *  
  56.      * */  
  57.     private ExecutorService mES = null;  
  58.    
  59.     /** 在此類中使用同步鎖時使用如下lock對象即可,官方推薦的,不推薦直接使用MyRunnableActivity.this類型的,可以詳細讀一下/framework/app下面的隨便一個項目 */  
  60.     private Object lock = new Object();  
  61.    
  62.     /** 喚醒標志,是否喚醒線程池工作 */  
  63.     private boolean isNotify = true;  
  64.    
  65.     /** 線程池是否處於運行狀態(即:是否被釋放!) */  
  66.     private boolean isRuning = true;  
  67.    
  68.     /** 任務進度 */  
  69.     private ProgressBar pb = null;  
  70.    
  71.     /** 用此Handler來更新我們的UI */  
  72.     private Handler mHandler = null;  
  73.    
  74.     /** 
  75.      * Overriding methods 
  76.      *  
  77.      * @param savedInstanceState 
  78.      */  
  79.     @Override  
  80.     protected void onCreate(Bundle savedInstanceState)  
  81.     {  
  82.         // TODO Auto-generated method stub  
  83.         super.onCreate(savedInstanceState);  
  84.         setContentView(R.layout.my_runnable_main);  
  85.         init();  
  86.     }  
  87.    
  88.     public void init()  
  89.     {  
  90.         pb = (ProgressBar)findViewById(R.id.progressBar1);  
  91.         findViewById(R.id.button1).setOnClickListener(this);  
  92.         findViewById(R.id.button2).setOnClickListener(this);  
  93.         findViewById(R.id.button3).setOnClickListener(this);  
  94.         findViewById(R.id.button4).setOnClickListener(this);  
  95.         findViewById(R.id.button5).setOnClickListener(this);  
  96.         taskQueue = new ConcurrentLinkedQueue<MyRunnable>();  
  97.         taskMap = new ConcurrentHashMap<Future, MyRunnable>();  
  98.         if (mES == null)  
  99.         {  
  100.             mES = Executors.newCachedThreadPool();  
  101.         }  
  102.    
  103.         // 用於更新ProgressBar進度條  
  104.         mHandler = new Handler()  
  105.         {  
  106.             /** 
  107.              * Overriding methods 
  108.              *  
  109.              * @param msg 
  110.              */  
  111.             @Override  
  112.             public void handleMessage(Message msg)  
  113.             {  
  114.                 super.handleMessage(msg);  
  115.                 pb.setProgress(msg.what);  
  116.             }  
  117.    
  118.         };  
  119.    
  120.     }  
  121.    
  122.     /** 
  123.      * Overriding methods 
  124.      *  
  125.      * @param v 
  126.      */  
  127.     @Override  
  128.     public void onClick(View v)  
  129.     {  
  130.         switch (v.getId())  
  131.         {  
  132.             case R.id.button1:  
  133.                 start();  
  134.                 break;  
  135.             case R.id.button2:  
  136.                 stop();  
  137.                 break;  
  138.             case R.id.button3:  
  139.                 reload(new MyRunnable(mHandler));  
  140.                 break;  
  141.             case R.id.button4:  
  142.                 release();  
  143.                 break;  
  144.             case R.id.button5:  
  145.                 addTask(new MyRunnable(mHandler));  
  146.                 break;  
  147.    
  148.             default:  
  149.                 break;  
  150.         }  
  151.     }  
  152.    
  153.     /** 
  154.      * <Summary Description> 
  155.      */  
  156.     private void addTask(final MyRunnable mr)  
  157.     {  
  158.    
  159.         mHandler.sendEmptyMessage(0);  
  160.    
  161.         if (mES == null)  
  162.         {  
  163.             mES = Executors.newCachedThreadPool();  
  164.             notifyWork();  
  165.         }  
  166.    
  167.         if (taskQueue == null)  
  168.         {  
  169.             taskQueue = new ConcurrentLinkedQueue<MyRunnable>();  
  170.         }  
  171.    
  172.         if (taskMap == null)  
  173.         {  
  174.             taskMap = new ConcurrentHashMap<Future, MyRunnable>();  
  175.         }  
  176.    
  177.         mES.execute(new Runnable()  
  178.         {  
  179.    
  180.             @Override  
  181.             public void run()  
  182.             {  
  183.                 /** 
  184.                  * 插入一個Runnable到任務隊列中 這個地方解釋一下,offer跟add方法,試了下,效果都一樣,沒區別,官方的解釋如下: 1 offer : Inserts the specified 
  185.                  * element at the tail of this queue. As the queue is unbounded, this method will never return 
  186.                  * {@code false}. 2 add: Inserts the specified element at the tail of this queue. As the queue is 
  187.                  * unbounded, this method will never throw {@link IllegalStateException} or return {@code false}. 
  188.                  *  
  189.                  *  
  190.                  * */  
  191.                 taskQueue.offer(mr);  
  192.                 // taskQueue.add(mr);  
  193.                 notifyWork();  
  194.             }  
  195.         });  
  196.    
  197.         Toast.makeText(MyRunnableActivity.this, "已添加一個新任務到線程池中 !", 0).show();  
  198.     }  
  199.    
  200.     /** 
  201.      * <Summary Description> 
  202.      */  
  203.     private void release()  
  204.     {  
  205.         Toast.makeText(MyRunnableActivity.this, "釋放所有占用的資源!", 0).show();  
  206.    
  207.         /** 將ProgressBar進度置為0 */  
  208.         mHandler.sendEmptyMessage(0);  
  209.         isRuning = false;  
  210.    
  211.         Iterator iter = taskMap.entrySet().iterator();  
  212.         while (iter.hasNext())  
  213.         {  
  214.             Map.Entry<Future, MyRunnable> entry = (Map.Entry<Future, MyRunnable>)iter.next();  
  215.             Future result = entry.getKey();  
  216.             if (result == null)  
  217.             {  
  218.                 continue;  
  219.             }  
  220.             result.cancel(true);  
  221.             taskMap.remove(result);  
  222.         }  
  223.         if (null != mES)  
  224.         {  
  225.             mES.shutdown();  
  226.         }  
  227.    
  228.         mES = null;  
  229.         taskMap = null;  
  230.         taskQueue = null;  
  231.    
  232.     }  
  233.    
  234.     /** 
  235.      * <Summary Description> 
  236.      */  
  237.     private void reload(final MyRunnable mr)  
  238.     {  
  239.         mHandler.sendEmptyMessage(0);  
  240.         if (mES == null)  
  241.         {  
  242.             mES = Executors.newCachedThreadPool();  
  243.             notifyWork();  
  244.         }  
  245.    
  246.         if (taskQueue == null)  
  247.         {  
  248.             taskQueue = new ConcurrentLinkedQueue<MyRunnable>();  
  249.         }  
  250.    
  251.         if (taskMap == null)  
  252.         {  
  253.             taskMap = new ConcurrentHashMap<Future, MyRunnable>();  
  254.         }  
  255.    
  256.         mES.execute(new Runnable()  
  257.         {  
  258.    
  259.             @Override  
  260.             public void run()  
  261.             {  
  262.                 /** 插入一個Runnable到任務隊列中 */  
  263.                 taskQueue.offer(mr);  
  264.                 // taskQueue.add(mr);  
  265.                 notifyWork();  
  266.             }  
  267.         });  
  268.    
  269.         mES.execute(new Runnable()  
  270.         {  
  271.             @Override  
  272.             public void run()  
  273.             {  
  274.                 if (isRuning)  
  275.                 {  
  276.                     MyRunnable myRunnable = null;  
  277.                     synchronized (lock)  
  278.                     {  
  279.                         myRunnable = taskQueue.poll(); // 從線程隊列中取出一個Runnable對象來執行,如果此隊列為空,則調用poll()方法會返回null  
  280.                         if (myRunnable == null)  
  281.                         {  
  282.                             isNotify = true;  
  283.                         }  
  284.                     }  
  285.    
  286.                     if (myRunnable != null)  
  287.                     {  
  288.                         taskMap.put(mES.submit(myRunnable), myRunnable);  
  289.                     }  
  290.                 }  
  291.             }  
  292.         });  
  293.     }  
  294.    
  295.     /** 
  296.      * <Summary Description> 
  297.      */  
  298.     private void stop()  
  299.     {  
  300.    
  301.         Toast.makeText(MyRunnableActivity.this, "任務已被取消!", 0).show();  
  302.    
  303.         for (MyRunnable runnable : taskMap.values())  
  304.         {  
  305.             runnable.setCancleTaskUnit(true);  
  306.         }  
  307.     }  
  308.    
  309.     /** 
  310.      * <Summary Description> 
  311.      */  
  312.     private void start()  
  313.     {  
  314.    
  315.         if (mES == null || taskQueue == null || taskMap == null)  
  316.         {  
  317.             Log.i("KKK", "某資源是不是已經被釋放了?");  
  318.             return;  
  319.         }  
  320.         mES.execute(new Runnable()  
  321.         {  
  322.             @Override  
  323.             public void run()  
  324.             {  
  325.                 if (isRuning)  
  326.                 {  
  327.                     MyRunnable myRunnable = null;  
  328.                     synchronized (lock)  
  329.                     {  
  330.                         myRunnable = taskQueue.poll(); // 從線程隊列中取出一個Runnable對象來執行,如果此隊列為空,則調用poll()方法會返回null  
  331.                         if (myRunnable == null)  
  332.                         {  
  333.                             isNotify = true;  
  334.                             // try  
  335.                             // {  
  336.                             // myRunnable.wait(500);  
  337.                             // }  
  338.                             // catch (InterruptedException e)  
  339.                             // {  
  340.                             // e.printStackTrace();  
  341.                             // }  
  342.                         }  
  343.                     }  
  344.    
  345.                     if (myRunnable != null)  
  346.                     {  
  347.                         taskMap.put(mES.submit(myRunnable), myRunnable);  
  348.                     }  
  349.                 }  
  350.    
  351.             }  
  352.         });  
  353.     }  
  354.    
  355.     private void notifyWork()  
  356.     {  
  357.         synchronized (lock)  
  358.         {  
  359.             if (isNotify)  
  360.             {  
  361.                 lock.notifyAll();  
  362.                 isNotify = !isNotify;  
  363.             }  
  364.         }  
  365.     }  
  366. }  

  2.2:輔助類(MyRunnable.java)

Java代碼
  1. /* 
  2.  * FileName:  MyRunnable.java 
  3.  * CopyRight:  Belong to  <XiaoMaGuo Technologies > own  
  4.  * Description:  <description> 
  5.  * Modify By :  XiaoMaGuo ^_^  
  6.  * Modify Date:   2013-10-21 
  7.  * Follow Order No.:  <Follow Order No.> 
  8.  * Modify Order No.:  <Modify Order No.> 
  9.  * Modify Content:  <modify content > 
  10.  */  
  11. package com.xiaoma.threadpooltest;  
  12.    
  13. import android.os.Handler;  
  14. import android.os.SystemClock;  
  15. import android.util.Log;  
  16.    
  17. /** 
  18.  * @TODO [The Class File Description] 
  19.  * @author XiaoMaGuo ^_^ 
  20.  * @version [version-code, 2013-10-21] 
  21.  * @since [Product/module] 
  22.  */  
  23. public class MyRunnable implements Runnable  
  24. {  
  25.    
  26.     private boolean cancleTask = false;  
  27.    
  28.     private boolean cancleException = false;  
  29.    
  30.     private Handler mHandler = null;  
  31.    
  32.     public MyRunnable(Handler handler)  
  33.     {  
  34.         mHandler = handler;  
  35.     }  
  36.    
  37.     /** 
  38.      * Overriding methods 
  39.      */  
  40.     @Override  
  41.     public void run()  
  42.     {  
  43.         Log.i("KKK", "MyRunnable  run() is executed!!! ");  
  44.         runBefore();  
  45.         if (cancleTask == false)  
  46.         {  
  47.             running();  
  48.             Log.i("KKK", "調用MyRunnable run()方法");  
  49.         }  
  50.    
  51.         runAfter();  
  52.     }  
  53.    
  54.     /** 
  55.      * <Summary Description> 
  56.      */  
  57.     private void runAfter()  
  58.     {  
  59.         Log.i("KKK", "runAfter()");  
  60.     }  
  61.    
  62.     /** 
  63.      * <Summary Description> 
  64.      */  
  65.     private void running()  
  66.     {  
  67.         Log.i("KKK", "running()");  
  68.         try  
  69.         {  
  70.             // 做點有可能會出異常的事情!!!  
  71.             int prog = 0;  
  72.             if (cancleTask == false && cancleException == false)  
  73.             {  
  74.                 while (prog < 101)  
  75.                 {  
  76.                     if ((prog > 0 || prog == 0) && prog < 70)  
  77.                     {  
  78.                         SystemClock.sleep(100);  
  79.                     }  
  80.                     else  
  81.                     {  
  82.                         SystemClock.sleep(300);  
  83.                     }  
  84.                     if (cancleTask == false)  
  85.                     {  
  86.                         mHandler.sendEmptyMessage(prog++);  
  87.                         Log.i("KKK", "調用 prog++ = " + (prog));  
  88.                     }  
  89.                 }  
  90.             }  
  91.         }  
  92.         catch (Exception e)  
  93.         {  
  94.             cancleException = true;  
  95.         }  
  96.     }  
  97.    
  98.     /** 
  99.      * <Summary Description> 
  100.      */  
  101.     private void runBefore()  
  102.     {  
  103.         // TODO Auto-generated method stub  
  104.         Log.i("KKK", "runBefore()");  
  105.     }  
  106.    
  107.     public void setCancleTaskUnit(boolean cancleTask)  
  108.     {  
  109.         this.cancleTask = cancleTask;  
  110.         Log.i("KKK", "點擊了取消任務按鈕 !!!");  
  111.         // mHandler.sendEmptyMessage(0);  
  112.     }  
  113.    
  114. }  

  2.3:布局文件

XML/HTML代碼
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:orientation="vertical" >  
  6.    
  7.     <LinearLayout  
  8.         android:layout_width="match_parent"  
  9.         android:layout_height="wrap_content"  
  10.         android:orientation="horizontal" >  
  11.    
  12.         <Button  
  13.             android:id="@+id/button5"  
  14.             android:layout_width="0dp"  
  15.             android:layout_height="wrap_content"  
  16.             android:layout_weight="1"  
  17.             android:text="添加任務" />  
  18.    
  19.         <Button  
  20.             android:id="@+id/button1"  
  21.             android:layout_width="0dp"  
  22.             android:layout_height="wrap_content"  
  23.             android:layout_weight="1"  
  24.             android:text="開始任務" />  
  25.    
  26.         <Button  
  27.             android:id="@+id/button2"  
  28.             android:layout_width="0dp"  
  29.             android:layout_height="wrap_content"  
  30.             android:layout_weight="1"  
  31.             android:text="取消任務" />  
  32.    
  33.         <Button  
  34.             android:id="@+id/button3"  
  35.             android:layout_width="0dp"  
  36.             android:layout_height="wrap_content"  
  37.             android:layout_weight="1"  
  38.             android:text="重新加載" />  
  39.    
  40.         <Button  
  41.             android:id="@+id/button4"  
  42.             android:layout_width="0dp"  
  43.             android:layout_height="wrap_content"  
  44.             android:layout_weight="1"  
  45.             android:text="釋放資源" />  
  46.     </LinearLayout>  
  47.    
  48.     <include layout="@layout/my_runnable_merge"/>  
  49.    
  50. </LinearLayout>  

  方式一、方式二的全局配置文件AndroidManifest.xml文件的配置如下:

XML/HTML代碼
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     package="com.xiaoma.threadpooltest"  
  4.     android:versionCode="1"  
  5.     android:versionName="1.0" >  
  6.    
  7.     <uses-sdk  
  8.         android:minSdkVersion="8"  
  9.         android:targetSdkVersion="15" />  
  10.    
  11.     <application  
  12.         android:allowBackup="true"  
  13.         android:icon="@drawable/ic_launcher"  
  14.         android:label="@string/app_name"  
  15.         android:theme="@style/AppTheme" >  
  16.         <activity  
  17.             android:name="Main"  
  18.             android:label="@string/app_name" >  
  19. <!--             <intent-filter> -->  
  20. <!--                 <action android:name="android.intent.action.MAIN" /> -->  
  21.    
  22. <!--                 <category android:name="android.intent.category.LAUNCHER" /> -->  
  23. <!--             </intent-filter> -->  
  24.         </activity>  
  25.         <activity  
  26.             android:name="MyRunnableActivity"  
  27.             android:label="@string/app_name" >  
  28.             <intent-filter>  
  29.                 <action android:name="android.intent.action.MAIN" />  
  30.    
  31.                 <category android:name="android.intent.category.LAUNCHER" />  
  32.             </intent-filter>  
  33.         </activity>  
  34.     </application>  
  35.    
  36. </manifest>  

  好了,今天要寫內容,大體就是這些了,項目的源碼大家可以到這http://mzh3344258.blog.51cto.com/1823534/1313611 裡面的附件下載,WordPress裡面不知道怎麼上傳,大家多見諒吧,還得繞個路去下載,非常抱歉! O_O 如果能仔細的將上面的東西都看完並消化的話,線程池方面的東西可能以後並不會太過為難你啦!呵呵,當然了,這些代碼中寫的都是一些比較簡單的寫法, 僅僅是使用了在線程中休眠的方式來模擬網絡下載(還是個假象),如果在實際代碼中使用時,尤其在釋放資源這一塊,不要只是單單釋放了我們自己控制的線程池及其任務,還要將網絡請求的Http也一同銷毀(disconnection)掉哦,這樣才算做到了完美!如果還有哪位朋友沒有安卓源碼的話,可以到這個地址查看官方在線的安卓系統源碼:https://github.com/android  急急忙忙寫的,如果文章中有什麼地方寫的不對的,真的很希望Android老鳥、菜鳥都來指點、提問,代碼中若不對的,或不太合理的地方,有朋友發覺了還請及時批評指正!先在此謝謝大家啦!加油,每天進步一點,堅持總會有收獲的!廢話不多說了,大家晚安!…O_O…

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved