Android線程池使用終結版
有一段時間沒寫博文了,今天抽空總結一下,也希望能通過自己寫的這些文章,加深理解的同時能幫
助在技術方面有疑點的朋友搞清楚個所以然來,由於經常會在網上或羣裏看到有朋友會問線程方面的
東西,就像我一個朋友他們老師講的,J2SE、J2EE裏面使用的線程方面的東西可能不是太多,但是
在Android開發裏面,玩的就是線程(UIThread)!好了,廢話就說這麼多吧,直入正題!今天要講的
東西就是線程池、線程的高效率使用,靈活控制!今天死馬我就用最常用的幾種方式來分別實現應用
中使用的線程方面的知識,(共寫了兩個不同入口的Activity來分開不同的實現方式,大家可以自行注
釋AndroidManifest.xml中的Launch入口或打開註釋)任何發代碼中的具體實現效果,好了,先隨便列
幾個吧,如:AsyncTask、Runnable、Thread、ThreadPool、Executors等等的使用,看我文章的朋
友應該都很清楚小馬的方式啦,果斷先上效果,再一步步分解代碼,來吧,效果圖如下:
一:無大小限制的線程池執行效果如下
二:限制按順序來執行任務的線程池效果如下
三:一個一個任務的執行線程池效果如下(與按順序執行效果是一樣的,只是內部實現稍有不同)
四:按指定個數來執行任務的線程池效果如下
五:創建一個可在指定時間裏執行任務的線程池,亦可重複執行,不常用,效果與四相同
六:按指定工廠模式來執行的線程池,效果與四、五一樣,但用方式六創建的線程池都有在工廠
中指定的線程屬性,比如:線程名字、是否爲用戶線程等等屬性
七:線程池中任務執行時可暫停效果圖如下
八:用Runnable、ConcurrentLinkedQueue、ConcurrentMap、Future、ExecutorService關聯實現的效果圖如下
哦的了,效果看完了,現在就請大家自行修改AndroidManifest.xml中主Activity的入口來看兩種不同方式實現的代碼效果吧,首先,先貼一下Main.java類的代碼,希望大家詳細看裏面的註釋,一定要詳細看,你不會吃虧的,相信我!(備註:爲了寫文章加註釋還有查找的時候方便,小馬把所有的主類及輔助類以內部類的形式寫到一個.java文件裏面了,如果朋友們覺得看着亂,不爽的話,可以自行將裏面的類抽取到單獨的.java文件中,幾分鐘搞定的事!)
方式一(純ExecutorService、AsyncTask、Runnable關聯實現相關文件如下):
1.1:主類文件(Main.java)
/* * FileName: Main.java * CopyRight: Belong to <XiaoMaGuo Technologies > own * Description: <description> * Modify By : XiaoMaGuo ^_^ * Modify Date: 2013-10-15 * Follow Order No.: <Follow Order No.> * Modify Order No.: <Modify Order No.> * Modify Content: <modify content > */ package com.xiaoma.threadpooltest; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import android.annotation.TargetApi; import android.app.Activity; import android.content.Context; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.SystemClock; import android.util.AttributeSet; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.BaseAdapter; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; /** * @TODO [The Class File Description] * @author XiaoMaGuo ^_^ * @version [version-code, 2013-10-15] * @since [Product/module] */ @TargetApi(Build.VERSION_CODES.HONEYCOMB) public class Main extends Activity { private static int order = 0; /** 總共多少任務(根據CPU個數決定創建活動線程的個數,這樣取的好處就是可以讓手機承受得住) */ // private static final int count = Runtime.getRuntime().availableProcessors() * 3 + 2; /** 總共多少任務(我是在模擬器裏面跑的,爲了效果明顯,所以寫死了爲10個,如果在手機上的話,推薦使用上面的那個count) */ private static final int count = 10; /** 每次只執行一個任務的線程池 */ private static ExecutorService singleTaskExecutor = null; /** 每次執行限定個數個任務的線程池 */ private static ExecutorService limitedTaskExecutor = null; /** 所有任務都一次性開始的線程池 */ private static ExecutorService allTaskExecutor = null; /** 創建一個可在指定時間裏執行任務的線程池,亦可重複執行 */ private static ExecutorService scheduledTaskExecutor = null; /** 創建一個可在指定時間裏執行任務的線程池,亦可重複執行(不同之處:使用工程模式) */ private static ExecutorService scheduledTaskFactoryExecutor = null; private List<AsyncTaskTest> mTaskList = null; /** 任務是否被取消 */ private boolean isCancled = false; /** 是否點擊並取消任務標示符 */ private boolean isClick = false; /** 線程工廠初始化方式一 */ ThreadFactory tf = Executors.defaultThreadFactory(); /** 線程工廠初始化方式二 */ private static class ThreadFactoryTest implements ThreadFactory { @Override public Thread newThread(Runnable r) { Thread thread = new Thread(r); thread.setName("XiaoMaGuo_ThreadFactory"); thread.setDaemon(true); // 將用戶線程變成守護線程,默認false return thread; } } static { singleTaskExecutor = Executors.newSingleThreadExecutor();// 每次只執行一個線程任務的線程池 limitedTaskExecutor = Executors.newFixedThreadPool(3);// 限制線程池大小爲7的線程池 allTaskExecutor = Executors.newCachedThreadPool(); // 一個沒有限制最大線程數的線程池 scheduledTaskExecutor = Executors.newScheduledThreadPool(3);// 一個可以按指定時間可週期性的執行的線程池 scheduledTaskFactoryExecutor = Executors.newFixedThreadPool(3, new ThreadFactoryTest());// 按指定工廠模式來執行的線程池 scheduledTaskFactoryExecutor.submit(new Runnable() { @Override public void run() { Log.i("KKK", "This is the ThreadFactory Test submit Run! ! ! "); } }); }; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.demo); final ListView taskList = (ListView)findViewById(R.id.task_list); taskList.setAdapter(new AsyncTaskAdapter(getApplication(), count)); taskList.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { if (position == 0) // 以第一項爲例,來測試關閉線程池 { /** * 會關閉線程池方式一:但不接收新的Task,關閉後,正在等待 執行的任務不受任何影響,會正常執行,無返回值! */ // allTaskExecutor.shutdown(); /** * 會關閉線程池方式二:也不接收新的Task,並停止正等待執行的Task(也就是說, 執行到一半的任務將正常執行下去),最終還會給你返回一個正在等待執行但線程池關閉卻沒有被執行的Task集合! */ List<Runnable> unExecRunn = allTaskExecutor.shutdownNow(); for (Runnable r : unExecRunn) { Log.i("KKK", "未執行的任務信息:=" + unExecRunn.toString()); } Log.i("KKK", "Is shutdown ? = " + String.valueOf(allTaskExecutor.isShutdown())); allTaskExecutor = null; } // 以第二項爲例來測試是否取消執行的任務 AsyncTaskTest sat = mTaskList.get(1); if (position == 1) { if (!isClick) { sat.cancel(true); isCancled = true; isClick = !isClick; } else { sat.cancel(false); isCancled = false; // isClick = false; isClick = !isClick; if (null != sat && sat.getStatus() == AsyncTask.Status.RUNNING) { if (sat.isCancelled()) { sat = new AsyncTaskTest(sat.mTaskItem); } else { Toast.makeText(Main.this, "A task is already running, try later", Toast.LENGTH_SHORT) .show(); } } /** * 由於上面測試關閉,在不重新生成allTaskExecutor的同時,會報異常(沒有可以使用的線程池,故此處重新生成線程池對象) */ if (allTaskExecutor == null) { allTaskExecutor = Executors.newCachedThreadPool(); } sat.executeOnExecutor(allTaskExecutor); // The task is already running(這也是個異常哦,小心使用! ) } } else { sat.cancel(false); isCancled = false; // sat.execute(sat.mTaskItem); // sat.executeOnExecutor(allTaskExecutor); } } }); } /** * @TODO [ListView Item的條目適配器] * @author XiaoMaGuo ^_^ * @version [version-code, 2013-10-22] * @since [Product/module] */ private class AsyncTaskAdapter extends BaseAdapter { private Context mContext; private LayoutInflater mFactory; private int mTaskCount; public AsyncTaskAdapter(Context context, int taskCount) { mContext = context; mFactory = LayoutInflater.from(mContext); mTaskCount = taskCount; mTaskList = new ArrayList<AsyncTaskTest>(taskCount); } @Override public int getCount() { return mTaskCount; } @Override public Object getItem(int position) { return mTaskList.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = mFactory.inflate(R.layout.list_view_item, null); AsyncTaskTest task = new AsyncTaskTest((MyListItem)convertView); /** * 下面兩種任務執行效果都一樣,形變質不變 * */ // task.execute(); // task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); /** * 下面的方式在小於API 11級時效果是一樣的,但在高版本中的稍微有點不同,可以看以下AsyncTask核心變量的定義就知道了使用如下 * 方式時,系統會默認的採用五個一組,五個一組的方式來執行我們的任務,定義在:AsyncTask.class中,private static final int CORE_POOL_SIZE = 5; * */ // use AsyncTask#THREAD_POOL_EXECUTOR is the same to older version #execute() (less than API 11) // but different from newer version of #execute() // task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); /** * 一個一個執行我們的任務,效果與按順序執行是一樣的(AsyncTask.SERIAL_EXECUTOR) * */ // task.executeOnExecutor(singleTaskExecutor); /** * 按我們指定的個數來執行任務的線程池 * */ // task.executeOnExecutor(limitedTaskExecutor); /** * 不限定指定個數的線程池,也就是說:你往裏面放了幾個任務,他全部同一時間開始執行, 不管你手機受得了受不了 * */ task.executeOnExecutor(allTaskExecutor); /** * 創建一個可在指定時間裏執行任務的線程池,亦可重複執行 * */ // task.executeOnExecutor(scheduledTaskExecutor); /** * 創建一個按指定工廠模式來執行任務的線程池,可能比較正規,但也不常用 */ // task.executeOnExecutor(scheduledTaskFactoryExecutor); mTaskList.add(task); } return convertView; } } class AsyncTaskTest extends AsyncTask<Void, Integer, Void> { private MyListItem mTaskItem; private String id; private AsyncTaskTest(MyListItem item) { mTaskItem = item; if (order < count || order == count) { id = "執行:" + String.valueOf(++order); } else { order = 0; id = "執行:" + String.valueOf(++order); } } @Override protected void onPreExecute() { mTaskItem.setTitle(id); } /** * Overriding methods */ @Override protected void onCancelled() { super.onCancelled(); } @Override protected Void doInVoid... params) { if (!isCancelled() && isCancled == false) // 這個地方很關鍵,如果不設置標誌位的話,直接setCancel(true)是無效的 { int prog = 0; /** * 下面的while中,小馬寫了個分支用來做個假象(任務東西剛開始下載的時候,速度快,快下載完成的時候就突然間慢了下來的效果, 大家可以想象一下,類似 * :PP手機助手、91手機助手中或其它手機應用中,幾乎都有這個假象,開始快,結束時就下載變慢了,講白了 就是開發的人不想讓你在下載到大於一半的時候,也就是快下載完的時候去點取消,你那樣得多浪費 * !所以造個假象,讓你不想去取消而已) */ while (prog < 101) { if ((prog > 0 || prog == 0) && prog < 70) // 小於70%時,加快進度條更新 { SystemClock.sleep(100); } else // 大於70%時,減慢進度條更新 { SystemClock.sleep(300); } publishProgress(prog); // 更新進度條 prog++; } } return null; } @Override protected void onPostExecute(Void result) { } @Override protected void onProgressUpdate(Integer... values) { mTaskItem.setProgress(values[0]); // 設置進度 } } } /** * @TODO [一個簡單的自定義 ListView Item] * @author XiaoMaGuo ^_^ * @version [version-code, 2013-10-22] * @since [Product/module] */ class MyListItem extends LinearLayout { private TextView mTitle; private ProgressBar mProgress; public MyListItem(Context context, AttributeSet attrs) { super(context, attrs); } public MyListItem(Context context) { super(context); } public void setTitle(String title) { if (mTitle == null) { mTitle = (TextView)findViewById(R.id.task_name); } mTitle.setText(title); } public void setProgress(int prog) { if (mProgress == null) { mProgress = (ProgressBar)findViewById(R.id.task_progress); } mProgress.setProgress(prog); } }
1.2:佈局文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="10dip" android:paddingRight="10dip" android:orientation="vertical" > <ListView android:id="@+id/task_list" android:layout_width="fill_parent" android:layout_height="wrap_content" android:divider="#cccccc" android:dividerHeight="0.6dip" android:footerDividersEnabled="true" android:headerDividersEnabled="true" /> </LinearLayout>
方式二(Runnable、ConcurrentLinkedQueue、ConcurrentMap、Future、ExecutorService關聯實現的相關文件如下):
2.1:主類文件(MyRunnableActivity.java)
/* * FileName: MyRunnableActivity.java * CopyRight: Belong to <XiaoMaGuo Technologies > own * Description: <description> * Modify By : XiaoMaGuo ^_^ * Modify Date: 2013-10-21 * Follow Order No.: <Follow Order No.> * Modify Order No.: <Modify Order No.> * Modify Content: <modify content > */ package com.xiaoma.threadpooltest; import java.util.Iterator; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.ProgressBar; import android.widget.Toast; /** * @TODO [線程池控制 ] * @author XiaoMaGuo ^_^ * @version [version-code, 2013-10-22] * @since [Product/module] */ public class MyRunnableActivity extends Activity implements OnClickListener { /** 任務執行隊列 */ private ConcurrentLinkedQueue<MyRunnable> taskQueue = null; /** * 正在等待執行或已經完成的任務隊列 * * 備註:Future類,一個用於存儲異步任務執行的結果,比如:判斷是否取消、是否可以取消、是否正在執行、是否已經完成等 * * */ private ConcurrentMap<Future, MyRunnable> taskMap = null; /** * 創建一個不限制大小的線程池 此類主要有以下好處 1,以共享的***隊列方式來運行這些線程. 2,執行效率高。 3,在任意點,在大多數 nThreads 線程會處於處理任務的活動狀態 * 4,如果在關閉前的執行期間由於失敗而導致任何線程終止,那麼一個新線程將代替它執行後續的任務(如果需要)。 * * */ private ExecutorService mES = null; /** 在此類中使用同步鎖時使用如下lock對象即可,官方推薦的,不推薦直接使用MyRunnableActivity.this類型的,可以詳細讀一下/framework/app下面的隨便一個項目 */ private Object lock = new Object(); /** 喚醒標誌,是否喚醒線程池工作 */ private boolean isNotify = true; /** 線程池是否處於運行狀態(即:是否被釋放!) */ private boolean isRuning = true; /** 任務進度 */ private ProgressBar pb = null; /** 用此Handler來更新我們的UI */ private Handler mHandler = null; /** * Overriding methods * * @param savedInstanceState */ @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.my_runnable_main); init(); } public void init() { pb = (ProgressBar)findViewById(R.id.progressBar1); findViewById(R.id.button1).setOnClickListener(this); findViewById(R.id.button2).setOnClickListener(this); findViewById(R.id.button3).setOnClickListener(this); findViewById(R.id.button4).setOnClickListener(this); findViewById(R.id.button5).setOnClickListener(this); taskQueue = new ConcurrentLinkedQueue<MyRunnable>(); taskMap = new ConcurrentHashMap<Future, MyRunnable>(); if (mES == null) { mES = Executors.newCachedThreadPool(); } // 用於更新ProgressBar進度條 mHandler = new Handler() { /** * Overriding methods * * @param msg */ @Override public void handleMessage(Message msg) { super.handleMessage(msg); pb.setProgress(msg.what); } }; } /** * Overriding methods * * @param v */ @Override public void onClick(View v) { switch (v.getId()) { case R.id.button1: start(); break; case R.id.button2: stop(); break; case R.id.button3: reload(new MyRunnable(mHandler)); break; case R.id.button4: release(); break; case R.id.button5: addTask(new MyRunnable(mHandler)); break; default: break; } } /** * <Summary Description> */ private void addTask(final MyRunnable mr) { mHandler.sendEmptyMessage(0); if (mES == null) { mES = Executors.newCachedThreadPool(); notifyWork(); } if (taskQueue == null) { taskQueue = new ConcurrentLinkedQueue<MyRunnable>(); } if (taskMap == null) { taskMap = new ConcurrentHashMap<Future, MyRunnable>(); } mES.execute(new Runnable() { @Override public void run() { /** * 插入一個Runnable到任務隊列中 這個地方解釋一下,offer跟add方法,試了下,效果都一樣,沒區別,官方的解釋如下: 1 offer : Inserts the specified * element at the tail of this queue. As the queue is unbounded, this method will never return * {@code false}. 2 add: Inserts the specified element at the tail of this queue. As the queue is * unbounded, this method will never throw {@link IllegalStateException} or return {@code false}. * * * */ taskQueue.offer(mr); // taskQueue.add(mr); notifyWork(); } }); Toast.makeText(MyRunnableActivity.this, "已添加一個新任務到線程池中 !", 0).show(); } /** * <Summary Description> */ private void release() { Toast.makeText(MyRunnableActivity.this, "釋放所有佔用的資源!", 0).show(); /** 將ProgressBar進度置爲0 */ mHandler.sendEmptyMessage(0); isRuning = false; Iterator iter = taskMap.entrySet().iterator(); while (iter.hasNext()) { Map.Entry<Future, MyRunnable> entry = (Map.Entry<Future, MyRunnable>)iter.next(); Future result = entry.getKey(); if (result == null) { continue; } result.cancel(true); taskMap.remove(result); } if (null != mES) { mES.shutdown(); } mES = null; taskMap = null; taskQueue = null; } /** * <Summary Description> */ private void reload(final MyRunnable mr) { mHandler.sendEmptyMessage(0); if (mES == null) { mES = Executors.newCachedThreadPool(); notifyWork(); } if (taskQueue == null) { taskQueue = new ConcurrentLinkedQueue<MyRunnable>(); } if (taskMap == null) { taskMap = new ConcurrentHashMap<Future, MyRunnable>(); } mES.execute(new Runnable() { @Override public void run() { /** 插入一個Runnable到任務隊列中 */ taskQueue.offer(mr); // taskQueue.add(mr); notifyWork(); } }); mES.execute(new Runnable() { @Override public void run() { if (isRuning) { MyRunnable myRunnable = null; synchronized (lock) { myRunnable = taskQueue.poll(); // 從線程隊列中取出一個Runnable對象來執行,如果此隊列爲空,則調用poll()方法會返回null if (myRunnable == null) { isNotify = true; } } if (myRunnable != null) { taskMap.put(mES.submit(myRunnable), myRunnable); } } } }); } /** * <Summary Description> */ private void stop() { Toast.makeText(MyRunnableActivity.this, "任務已被取消!", 0).show(); for (MyRunnable runnable : taskMap.values()) { runnable.setCancleTaskUnit(true); } } /** * <Summary Description> */ private void start() { if (mES == null || taskQueue == null || taskMap == null) { Log.i("KKK", "某資源是不是已經被釋放了?"); return; } mES.execute(new Runnable() { @Override public void run() { if (isRuning) { MyRunnable myRunnable = null; synchronized (lock) { myRunnable = taskQueue.poll(); // 從線程隊列中取出一個Runnable對象來執行,如果此隊列爲空,則調用poll()方法會返回null if (myRunnable == null) { isNotify = true; // try // { // myRunnable.wait(500); // } // catch (InterruptedException e) // { // e.printStackTrace(); // } } } if (myRunnable != null) { taskMap.put(mES.submit(myRunnable), myRunnable); } } } }); } private void notifyWork() { synchronized (lock) { if (isNotify) { lock.notifyAll(); isNotify = !isNotify; } } } }
2.2:輔助類(MyRunnable.java)
/* * FileName: MyRunnable.java * CopyRight: Belong to <XiaoMaGuo Technologies > own * Description: <description> * Modify By : XiaoMaGuo ^_^ * Modify Date: 2013-10-21 * Follow Order No.: <Follow Order No.> * Modify Order No.: <Modify Order No.> * Modify Content: <modify content > */ package com.xiaoma.threadpooltest; import android.os.Handler; import android.os.SystemClock; import android.util.Log; /** * @TODO [The Class File Description] * @author XiaoMaGuo ^_^ * @version [version-code, 2013-10-21] * @since [Product/module] */ public class MyRunnable implements Runnable { private boolean cancleTask = false; private boolean cancleException = false; private Handler mHandler = null; public MyRunnable(Handler handler) { mHandler = handler; } /** * Overriding methods */ @Override public void run() { Log.i("KKK", "MyRunnable run() is executed!!! "); runBefore(); if (cancleTask == false) { running(); Log.i("KKK", "調用MyRunnable run()方法"); } runAfter(); } /** * <Summary Description> */ private void runAfter() { Log.i("KKK", "runAfter()"); } /** * <Summary Description> */ private void running() { Log.i("KKK", "running()"); try { // 做點有可能會出異常的事情!!! int prog = 0; if (cancleTask == false && cancleException == false) { while (prog < 101) { if ((prog > 0 || prog == 0) && prog < 70) { SystemClock.sleep(100); } else { SystemClock.sleep(300); } if (cancleTask == false) { mHandler.sendEmptyMessage(prog++); Log.i("KKK", "調用 prog++ = " + (prog)); } } } } catch (Exception e) { cancleException = true; } } /** * <Summary Description> */ private void runBefore() { // TODO Auto-generated method stub Log.i("KKK", "runBefore()"); } public void setCancleTaskUnit(boolean cancleTask) { this.cancleTask = cancleTask; Log.i("KKK", "點擊了取消任務按鈕 !!!"); // mHandler.sendEmptyMessage(0); } }
2.3:佈局文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <Button android:id="@+id/button5" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="添加任務" /> <Button android:id="@+id/button1" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="開始任務" /> <Button android:id="@+id/button2" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="取消任務" /> <Button android:id="@+id/button3" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="重新加載" /> <Button android:id="@+id/button4" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="釋放資源" /> </LinearLayout> <include layout="@layout/my_runnable_merge"/> </LinearLayout>
方式一、方式二的全局配置文件AndroidManifest.xml文件的配置如下:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.xiaoma.threadpooltest" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="15" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="Main" android:label="@string/app_name" > <!-- <intent-filter> --> <!-- <action android:name="android.intent.action.MAIN" /> --> <!-- <category android:name="android.intent.category.LAUNCHER" /> --> <!-- </intent-filter> --> </activity> <activity android:name="MyRunnableActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
好了,今天要寫內容,大體就是這些了,項目的源碼大家可以到附件中下載,如果能仔細的將上面的東西都看完並消化的話,線程池方面的東西可能以後並不會太過爲難你啦!呵呵,當然了,小馬這些代碼中寫的都是一些比較簡單的寫法,僅僅是使用了在線程中休眠的方式來模擬網絡下載(還是個假象),如果在實際代碼中使用時,尤其在釋放資源這一塊,不要只是單單釋放了我們自己控制的線程池及其任務,還要將網絡請求的Http也一同銷燬掉哦,這樣纔算做到了完美!急急忙忙寫的,如果文章中有什麼地方寫的不對的,真的很希望Android老鳥、菜鳥都來指點、提問,代碼中若不對的,或不太合理的地方,有朋友發覺了還請及時批評指正!小馬先在此謝謝大家啦!加油,每天進步一點,堅持總會有收穫的!廢話不多說了,大家晚安!…O_O…
一個很幸福的壞人!小馬果、酷_莫名簡單