在應用的開發中咱們正確處理好主線程和子線程之間的關係,耗時的操做都放到子線程中處理,避免阻塞主線程,致使ANR。異步處理技術是提升應用性能,解決主線程和子線程之間通訊問題的關鍵。linux
首先看一個異步技術鏈:android
Thread是Android中異步處理技術的基礎,建立線程有兩種方法。安全
public class MyThread extends Thread {
@Override
public void run() {
super.run();
}
public void startThread() {
MyThread myThread = new MyThread();
myThread.start();
}
}複製代碼
public class MyRunnable implements Runnable {
@Override
public void run() {
}
public void startThread() {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();
}
}複製代碼
Android應用各類類型的線程本質上基於linux系統的pthreads,在應用層能夠分爲三種類型線程。bash
HandlerThread是一個集成了Looper和MessageQueue的線程,當啓動HandlerThread時,會同時生成Looper和MessageQueue,而後等待消息進行處理,它的run方法源碼:cookie
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}複製代碼
使用HandlerThread的好處是開發者不須要本身去建立和維護Looper,它的用法和普通線程同樣,以下:框架
HandlerThread handlerThread = new HandlerThread("HandlerThread");
handlerThread.start();
handler = new Handler(handlerThread.getLooper()){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//處理接受的消息
}
};複製代碼
HandlerThread中只有一個消息隊列,隊列中的消息是順序執行的,所以是線程安全的,固然吞吐量天然受到必定影響,隊列中的任務可能會被前面沒有執行完的任務阻塞。HandlerThread的內部機制確保了在建立Looper和發送消息之間不存在競態條件(是指一個在設備或者系統試圖同時執行兩個操做的時候出現的不但願的情況,可是因爲設備和系統的天然特性,爲了正確地執行,操做必須按照合適順序進行),這個是經過將HandlerThread.getLooper()實現爲一個阻塞操做實現的,只有當HandlerThread準備好接受消息以後纔會返回,源碼以下:異步
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// 若是線程已經啓動,那麼在Looper準備好以前應先等待
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}複製代碼
若是具體業務要求在HandlerThread開始接受消息以前要進行某些初始化操做的話,能夠重寫HandlerThread的onLooperPrepared函數,例如能夠在這個函數中建立於HandlerThread關聯的Handler實例,這同時也能夠對外隱藏咱們的Handler實例,代碼以下:async
public class MyHandlerThread extends HandlerThread {
private Handler mHandler;
public MyHandlerThread() {
super("MyHandlerThread", Process.THREAD_PRIORITY_BACKGROUND);
}
@Override
protected void onLooperPrepared() {
super.onLooperPrepared();
mHandler = new Handler(getLooper()) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
break;
case 2:
break;
}
}
};
}
public void publishedMethod1() {
mHandler.sendEmptyMessage(1);
}
public void publishedMethod2() {
mHandler.sendEmptyMessage(2);
}
}複製代碼
AsyncQueryHandler是用於在ContentProvider上面執行異步的CRUD操做的工具類,CRUD操做會被放到一個單獨的子線程中執行,當操做結束獲取到結果後,將經過消息的方式傳遞給調用AsyncQueryHandler的線程,一般就是主線程。AsyncQueryHandler是一個抽象類,集成自Handler,經過封裝ContentResolver、HandlerThread、AsyncQueryHandler等實現對ContentProvider的異步操做。ide
AsyncQueryHandler封裝了四個方法操做ContentProvider,對應CRUD以下:函數
public final void startDelete(int token, Object cookie, Uri uri,String selection, String[] selectionArgs);複製代碼
public final void startInsert(int token, Object cookie, Uri uri,ContentValues initialValues);複製代碼
public void startQuery(int token, Object cookie, Uri uri,
String[] projection, String selection, String[] selectionArgs,
String orderBy);複製代碼
public final void startUpdate(int token, Object cookie, Uri uri,
ContentValues values, String selection, String[] selectionArgs);複製代碼
AsyncQueryHandler的子類能夠根據實際需求實現下面的回調函數,對應上面操做的CRUD操做的返回結果。
/**
* Called when an asynchronous query is completed.
*
* @param token the token to identify the query, passed in from
* {@link #startQuery}.
* @param cookie the cookie object passed in from {@link #startQuery}.
* @param cursor The cursor holding the results from the query.
*/
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
// Empty
}
/**
* Called when an asynchronous insert is completed.
*
* @param token the token to identify the query, passed in from
* {@link #startInsert}.
* @param cookie the cookie object that's passed in from * {@link #startInsert}. * @param uri the uri returned from the insert operation. */ protected void onInsertComplete(int token, Object cookie, Uri uri) { // Empty } /** * Called when an asynchronous update is completed. * * @param token the token to identify the query, passed in from * {@link #startUpdate}. * @param cookie the cookie object that's passed in from
* {@link #startUpdate}.
* @param result the result returned from the update operation
*/
protected void onUpdateComplete(int token, Object cookie, int result) {
// Empty
}
/**
* Called when an asynchronous delete is completed.
*
* @param token the token to identify the query, passed in from
* {@link #startDelete}.
* @param cookie the cookie object that's passed in from * {@link #startDelete}. * @param result the result returned from the delete operation */ protected void onDeleteComplete(int token, Object cookie, int result) { // Empty }複製代碼
Service的各個生命週期函數是運行在主線程,所以它自己並非一個異步處理技術。爲了可以在Service中實如今子線程中處理耗時任務,Android引入了一個Service的子類:IntentService。IntentService具備Service同樣的生命週期,同時也提供了在後臺線程中處理異步任務的機制。與HandlerThread相似,IntentService也是在一個後臺線程中順序執行全部的任務,咱們經過給Context.startService傳遞一個Intent類型的參數能夠啓動IntentService的異步執行,若是此時IntentService正在運行中,那麼這個新的Intent將會進入隊列進行排隊,直到後臺線程處理完隊列前面的任務;若是此時IntentService沒有在運行,那麼將會啓動一個新的IntentService,當後臺線程隊列中全部任務處理完成以後,IntentService將會結束它的生命週期,所以IntentService不須要開發者手動結束。
IntentService自己是一個抽象類,所以,使用前須要繼承它並實現onHandlerIntent方法,在這個方法中實現具體的後臺處理業務邏輯,同時在子類的構造方法中須要調用super(String name)傳入子類的名字,以下:
public class SimpleIntentService extends IntentService {
public SimpleIntentService() {
super(SimpleIntentService.class.getName());
setIntentRedelivery(true);
}
@Override
protected void onHandleIntent(Intent intent) {
//該方法在後臺調用
}
}複製代碼
上面代碼中的setIntentRedelivery方法若是設置爲true,那麼IntentService的onStartCOmmand方法將會返回START_REDELIVER_INTENT。這時,若是onHandlerIntent方法返回以前進程死掉了,那麼進程將會從新啓動,intent將會從新投遞。
固然,相似Service,不要忘記在AndroidManifest.xml文件中註冊SimpleIntentService 。
<service android:name=".SimpleIntentService" />複製代碼
經過查看IntentService 的源碼,咱們能夠發現事實上IntentService 是經過HandlerThread來實現後臺任務的處理的,代碼邏輯很簡單:
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;
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);
}
}
public IntentService(String name) {
super();
mName = name;
}
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onDestroy() {
mServiceLooper.quit();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@WorkerThread
protected abstract void onHandleIntent(Intent intent);
}複製代碼
建立和銷燬對象是存在開銷的,在應用中頻繁出現線程的建立和銷燬,那麼會影響到應用的性能,使用Executor框架能夠經過線程池機制解決這個問題,改善應用的體驗。Executor框架爲開發者提供了以下:
Executor框架的基礎是一個名爲Executor的接口定義,Executor的主要目的是分離任務的建立和它的執行,最終實現上述功能點。
public interface Executor {
/**
* Executes the given command at some time in the future. The command
* may execute in a new thread, in a pooled thread, or in the calling
* thread, at the discretion of the {@code Executor} implementation.
*
* @param command the runnable task
* @throws RejectedExecutionException if this task cannot be
* accepted for execution
* @throws NullPointerException if command is null
*/
void execute(Runnable command);
}複製代碼
開發者經過實現Executor接口並重寫execute方法從而實現本身的Executor類,最簡單的是直接在這個方法中建立一個線程來執行Runnable。
public class SimpleExecutor implements Executor {
@Override
public void execute(Runnable command) {
new Thread(command).start();
}
}複製代碼
線程池是任務隊列和工做線程的集合,這二者組合起來實現生產者消費者模式。Executor框架爲開發者提供了預約義的線程池實現。
Executors.newFixedThreadPool(3);複製代碼
Executors.newCachedThreadPool();複製代碼
當有新任務須要執行時,線程池會建立新的線程來處理它,空閒的線程池會等待60秒來執行新任務,當沒有任務可執行時就自動銷燬,所以可變大小線程池會根據任務隊列的大小而變化。
Executors.newSingleThreadExecutor();複製代碼
這個線程池中永遠只有一個線程來串行執行任務隊列中的任務。
預約義的線程池都是基於ThreadPoolExecutor類之上構建的,而經過ThreadPoolExecutor開發者能夠自定義線程池的一些行爲,咱們主要來看看這個類的構造函數:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}複製代碼
NANOSECONDS,//微秒
MICROSECONDS,//毫秒
MILLISECONDS,// 毫微秒
SECONDS // 秒複製代碼
AsyncTask是在Executor框架基礎上進行的封裝,它實現將耗時任務移動到工做線程中執行,同時提供方便的接口實現工做線程和主線程的通訊,使用AsyncTask通常會用到以下:
public class FullTask extends AsyncTask<String,String,String> {
@Override
protected void onPreExecute() {
super.onPreExecute();
//主線程執行
}
@Override
protected String doInBackground(String... params) {
return null;
//子線程執行
}
@Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
//主線程執行
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
//主線程執行
}
@Override
protected void onCancelled() {
super.onCancelled();
//主線程執行
}
}複製代碼
一個應用中使用的全部AsyncTask實例會共享全局的屬性,也就是說若是AsnycTask中的任務是串行執行,那麼應用中全部的AsyncTask都會進行排隊,只有等前面的任務執行完成以後,纔會接着執行下一個AsnycTask中的任務,在executeOnExecutor(AsyncTask.SERIAL_EXECUTOR)或者API大於13的系統上面執行execute()方法,都會是這個效果;若是AsyncTask是異步執行,那麼在四核的CPU系統上,最多隻有五個任務能夠同時進行,其餘任務須要在隊列中排隊,等待空閒的線程。之因此會出現這種狀況是因爲AsyncTask中的ThreadPoolExecutor指定核心線程數是系統CPU核數+1,以下:
public abstract class AsyncTask<Params, Progress, Result> {
private static final String LOG_TAG = "AsyncTask";
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);
/**
* An {@link Executor} that can be used to execute tasks in parallel.
*/
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
}複製代碼
Loader是Android3.0開始引入的一個異步數據加載框架,它使得在Activity或者Fragment中異步加載數據變得簡單,同時它在數據源發生變化時,可以及時發出消息通知。Loader框架涉及的API以下:
public class ContactActivity extends ListActivity implements LoaderManager.LoaderCallbacks<Cursor> {
private static final int CONTACT_NAME_LOADER_ID = 0;
static final String[] CONTACTS_SUMMARY_PROJECTION = new String[]{ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME};
SimpleCursorAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initAdapter();
//經過LoaderManger初始化Loader,這會回調到onCreateLoader
getLoaderManager().initLoader(CONTACT_NAME_LOADER_ID, null, this);
}
private void initAdapter() {
mAdapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, null, new String[]{ContactsContract.Contacts.DISPLAY_NAME}, new int[]{android.R.id.text1}, 0);
setListAdapter(mAdapter);
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
//實際建立Loader的地方 此處使用CursorLoader
return new CursorLoader(this, ContactsContract.Contacts.CONTENT_URI, CONTACTS_SUMMARY_PROJECTION, null, null, ContactsContract.Contacts.DISPLAY_NAME + " ASC ");
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
//後臺線程中加載完數據後,回調這個方法將數據傳遞給主線程
mAdapter.swapCursor(data);
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
//Loader 被重置後的回調,在這裏能夠從新刷新頁面數據
mAdapter.swapCursor(null);
}
}複製代碼
根據以上列出的異步處理技術,使用的時候須要根據如下結果因素: