在应用的开发中咱们正确处理好主线程和子线程之间的关系,耗时的操做都放到子线程中处理,避免阻塞主线程,致使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);
}
}复制代码
根据以上列出的异步处理技术,使用的时候须要根据如下结果因素: