因為要寫團隊的推文所以寫了這個因妙,很多東西都參考自《Android開發(fā)藝術探索》這本書,姑且當做自己的學習筆記票髓。感覺自己還需要學很多東西攀涵,要有自己的東西和思想。
在Android中洽沟,線程分為主線程和子線程以故,主界面用于與用戶交互谓传,進行UI的相關操作照筑,而子線程則負責耗時操作。如果在主線程中進行耗時操作烙懦,就會使程序無法及時的響應跷车。因此耗時操作必須放在子線程中進行棘利。
1、主線程和子線程
主線程是指進程所有用的線程朽缴,在Android中即指進行UI與用戶交互的線程就是主線程善玫。因此在Android開發(fā)中,需要竟可能的把耗時操作密强,網絡請求訪問操作茅郎,數(shù)據(jù)庫讀取操作等放在子線程,以避免主線程長期處于占用狀態(tài)以降低用戶體驗或渤。系統(tǒng)要求網絡訪問必須在子線程中進行系冗,否則會拋出NetworkOnMainThreadException異常。
2薪鹦、線程形態(tài)
Android中的線程形態(tài)有傳統(tǒng)的Thread掌敬,AsyncTask,HandlerThread和IntentService池磁。
2.1奔害、AsyncTask
AsyncTask封裝了Thread和Handler,必須在主線程進行調用地熄,它可以在子線程中執(zhí)行任務华临,然后將執(zhí)行的結果傳遞給主線程并更新UI。但AsyncTask并不適合執(zhí)行特別耗時的任務端考。
2.1.1雅潭、參數(shù):
AsyncTask是一個泛型類揭厚,提供了三個泛型參數(shù),Params 扶供,Progress 和Result筛圆。
- Params表示參數(shù)的類型
- Progress表示后臺任務的執(zhí)行進度的類型
- Result表示后臺任務返回結果的類型
AsyncTask的聲明:
public abstract class Asynctask<Params,Progress,Result>
2.1.2、方法:
AsyncTask提供了一些核心方法:
- onPreExecute() 在主線程中調用用來進行異步任務的準備操作椿浓。
- doInBackground(Params …… params) 在執(zhí)行完onPreExecute()后進行子線程任務時自動調用顽染,Params表示異步任務的輸入參數(shù)。在方法中可以通過publishProgress更新任務的完成進度轰绵,同時在結束調用后會返回結果給onPostExecute()方法。
- onProgressUpdate(Params …… params) 在主線程中用于顯示任務進行的進度尼荆,在publishProgress()方法中被調用左腔。
- onProgressExecute(Result result) 在主線程中用戶獲取任務結束后回返的結果,即doInBackground的返回值捅儒。
- onCancelled() 在主線程中執(zhí)行液样,當異步任務被取消后不會執(zhí)行onProgressExecute方法而會執(zhí)行onCancelled方法。
2.1.3巧还、調用:
AsyncTask的使用步驟如下:
1.創(chuàng)建AsyncTask子類鞭莽,具體實現(xiàn)其核心方法
2.創(chuàng)建子類的實例對象
3.調用execute執(zhí)行異步線程任務
2.1.4、AsyncTask的限制:
1.必須在主線程加載麸祷,即第一次訪問AsyncTask必須在主線程澎怒,對象必須在主線程創(chuàng)建
2.execute必須在UI線程中調用
3.不能再程序中直接調用onPreExecute(),onPostExecute(),doInBackground和onProgressUpdate方法。
4.一個AsyncTask方法只能使用一次
2.1.5阶牍、AsyncTask的工作原理:
- execute方法
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
public final AsyncTask<Params,Progress,Result>executeOnExecutor(Executor exec, Params...params){
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
case FINISHED:
throw new IllegalStateException("Cannot execute task:"
+ " the task has already been executed "
+ "(a task can be executed only once)");
}
}
mStatus=Status.RUNNING;
onPreExecute();
mWorker.mParams=params;
exec.execute(mFuture);
return this;
}
在execute方法中喷面,會檢測AsyncTask的當前狀態(tài),如果當前為RUNNING或FINISHED狀態(tài)走孽,系統(tǒng)會拋出異常惧辈,當為空閑狀態(tài),則置為RUNNING狀態(tài)磕瓷。
置為RUNNING狀態(tài)后會調用onPreExecute方法盒齿,同時將參數(shù)Params傳遞給mWorker的mParams。之后調用exec.execute困食,并傳入mFuture边翁,其中exec就是傳進來的sDefaultExecutor。
- sDefaultExecutor
sDefaultExecutor是一個串行的線程池陷舅,一個進程中的所有的AsyncTask全部在這個串行線程池中排隊執(zhí)行倒彰,在executeOnExecute方法中,onPreExecute方法最先執(zhí)行莱睁。
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
mTasks代表了SerialExecutor這個串行線程池的任務緩存隊列待讳,之后用offer向任務緩存隊列中添加了一個任務芒澜,調用了r的run方法,r就是傳入的mFuture创淡,而mFuture的run方法內部會調用MWorker的call方法痴晦,接著調用doInBackground方法,開始執(zhí)行后臺任務琳彩。執(zhí)行結束后會調用scheduleNext方法誊酌,執(zhí)行下一個任務。另外mActive表示了AsyncTask的對象露乏,如果MActive為null碧浊,則同樣會執(zhí)行scheduleNext方法。在scheduleNext方法中瘟仿,若緩存隊列不為空箱锐,則從隊列中取出任務執(zhí)行。
綜上劳较,SerialExecutor的工作是將任務加入緩存隊列中驹止,而執(zhí)行任務的是THREAD_POOL_EXECUTOR。
- THREAD_POOL_EXECUTOR
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE = 1;
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable r) {
return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
}
};
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
即corePoolSize的CPU數(shù)加一观蜗,maxumumPoolSize的CPU數(shù)二倍加一臊恋,存活1s,任務緩存隊列為LinkedBlockingQueue墓捻。
- postResult方法
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
首先用getHandler方法獲取AsyncTask獲取內部包含的sHandler抖仅,然后發(fā)送MESSAGE_POST_RESULT消息。
- sHandler
private static final InternalHandler sHandler = new InternalHandler();
private static class InternalHandler extends Handler {
public InternalHandler() {
super(Looper.getMainLooper());
}
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
// There is only one result
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
sHandler是一個靜態(tài)的Handler對象砖第,為了sHandler能夠執(zhí)行環(huán)境從后臺切換到主線程岸售,則應使用主線程的Looper,在主線程中創(chuàng)建sHandler厂画。sHandler收到MESSAGE_POST_RESULT后凸丸,會調用finish方法。源碼如下:
- finish
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
}
else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
調用isCancelled()判斷任務是否取消袱院,如果取消則調用 onCancelled(result)屎慢,否則調用onPostExecute(result)。同時將mStatus設為FINISHED忽洛,表示對象執(zhí)行完畢腻惠。
2.2、HandlerThread
2.2.1欲虚、簡介及實現(xiàn)
HandlerThread繼承了Thread集灌,能夠使用Handler,實現(xiàn)簡單,節(jié)省系統(tǒng)資源開銷欣喧。
實現(xiàn)如下:
HandlerThread thread = new HandlerThread("MyHandlerThread");
thread.start();
mHandler = new Handler(thread.getLooper());
mHandler.post(new Runnable(){...});
2.2.2腌零、源碼及分析
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
protected void onLooperPrepared() {
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
}
它創(chuàng)建了一個消息隊列,外界需要通過Handler的消息通知它執(zhí)行一個任務唆阿,由于HandlerThread的run方法是一個無限循環(huán)方法益涧,所以可以通過quit方法終止線程的執(zhí)行。
2.3驯鳖、IntentService
IntentService是特殊的Service闲询,繼承了Service,因為IntentService是一個抽象類浅辙,所以必須創(chuàng)建IntentService的子類才能使用扭弧。
同時,IntentService是服務记舆,所以在執(zhí)行時寄狼,優(yōu)先級較高。
IntentService封裝了HandlerThread和Handler氨淌。
2.3.1、使用
1.定義IntentService子類伊磺,傳入線程名稱盛正,復寫onHandlerIntent()方法。
2.在Manifest.xml中注冊
3.在Activity中開啟服務
2.3.2屑埋、源碼分析
- onCreate
在IntentThread被第一次啟動時豪筝,會調用相應的onCreate方法。具體如下:
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
首先實例化新線程摘能,然后獲得工作線程的 Looper续崖,并且構造一個Handler對象mServiceHandler,通過mServiceHandler發(fā)送的消息都會在HandlerThread中執(zhí)行团搞。
- onStartCommand
每次啟動IntentService都會調用onStartCommand方法严望,用于處理每個后臺任務的Intent。
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
可以看出在onStartCommand中會調用onStart 方法逻恐,在onStart方法中像吻,獲得ServiceHandler消息的引用,后將消息包裝到msg中复隆,之后發(fā)送消息拨匆。這個消息會在HandlerThread中被處理。
- ServiceHandler方法
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
IntentService的onHandleIntent方法是一個抽象方法挽拂,需要實現(xiàn)惭每,作用是從Intent中區(qū)分具體任務并執(zhí)行,調用執(zhí)行完任務后亏栈,stopSelf會直接停止服務台腥,當存在多個任務時宏赘,stopSelf則會在最后一個任務執(zhí)行完畢后停止服務。
3览爵、線程池
在實際使用中置鼻,線程池往往更加放標,和線程相比蜓竹,線程池性能開銷小箕母,可避免因為大量線程搶占資源而堵塞,也更容易管理俱济。
java中線程池的接口是ExecutorService嘶是,默認實現(xiàn)是ThreadPoolExecutor。
3.1蛛碌、ThreadPoolExecutor
ThreadPoolExecutor是線程池的實現(xiàn)聂喇,構造方法如下
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory)
- corePoolSize
核心線程數(shù),核心線程會在線程池中一直存活蔚携。若將allowCoreThreadTimeOut設置為true希太,那么核心線程也將有timepout,會在超時后被殺死酝蜒。
- maximumPoolSize
最大線程數(shù)誊辉。
- keepAliveTime
非核心線程限制的超時時長,超過設置時間后非核心線程會被收回亡脑,allowCoreThreadTimeOut設置為true后核心線程也會被收回堕澄。
unit
時間的參數(shù)單位workQueue
任務隊列,通過線程池的execute方法提交的Runnable對象儲存在其中
- threadFactory
線程工廠霉咨,為線程池創(chuàng)建線程
ThreadPoolExecutor在執(zhí)行線程任務是需滿足一定的規(guī)則
- 首先使用核心線程蛙紫,在核心線程不夠時才啟用新線程
- 當任務書大于核心線程數(shù)量,那么會被插入等待隊列中
- 如果不能插入等待隊列途戒,且線程數(shù)量未達到最大線程數(shù)坑傅,則會開啟新線程
- 若無法插入等待隊列且無法創(chuàng)建新線程,則請求會被拒絕
3.2喷斋、線程池的分類
線程池分為四種不同的功能裁蚁,分別是FixedThreadPool、CachedThreadPool继准、ScheduledThreadPool枉证、SingkeThreadExecutor。
- FixedThreadPool
通過execute的newFixedThreadPool方法創(chuàng)建移必,固定大小的線程池室谚,每次提交任務都會創(chuàng)建新的線程,直到池中線程數(shù)目達到最大。如果有一個線程異常結束后秒赤,會產生一個新的線程補充進去猪瞬。能夠更快地相應外界請求。
具體實現(xiàn)如下:
public static ExecutorSrevice newFixedThreadPool(int nThreads){
return new ThreadPoolExecutor(nThread,nThreads,
0L,TimeUnit.MILLISECINDS,
new LinkedBlockingQueue<Runnable>());
}
- CachedThreadPool
一個可以根據(jù)需要創(chuàng)建線程的線程池入篮,對于很多短期的異步任務陈瘦,將有效提高性能,調用execute()將重用已構造的線程潮售,如果沒有線程可用痊项,將創(chuàng)造一個新的線程并加入線程池,并移除超過60s未使用的線程酥诽。適合執(zhí)行耗時少的任務鞍泉。
具體實現(xiàn)如下:
public static ExecutorService newCachedThreadPool(){
reutrn new ThreadPoolExecutor(0,Interger.MAX_VALUE,
60L,TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
- ScheduledThreadPool
核心線程有限,非核心線程數(shù)無線肮帐,創(chuàng)建一個大小無限的線程池咖驮,此線程池支持定時以及周期性執(zhí)行任務的需求。
具體實現(xiàn)如下:
public static ScheduledThreadPool newScheduledThreadPool(int corePoolSize){
reutrn new ScheduledThreadPool(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize){
super(corePoolSize,Integer.MAX_VALUE,0,MANOSECONDS,new DelayWorkQueue());
}
- SingkeThreadExecutor
創(chuàng)建單線程池训枢,即線程池中只有一個線程托修,所有的任務是串行執(zhí)行,如果池中線程因異常結束恒界,會有一個新的線程來代替睦刃。以此保證了任務按提交順序執(zhí)行。
具體實現(xiàn)如下:
public static ExecutorService newScheduledThreadExecutor(){
reutrn new FinalizeableDelegatedExecutorService
(new ThreadPoolExecutor(1,1,0L,TimeUnit.MILLISECINDS,new LinkedBlockingQueue<Runnable>()));
}
參考來源:
《Android開發(fā)藝術探索》
https://www.cnblogs.com/absfree/p/5357678.html
https://blog.csdn.net/carson_ho/article/details/53407806