1
本文档基于EventBus 3.0.0

EventBus是一个发布/订阅事件总线,用来优化android。
EventBus-Publish-Subscribe.png

EventBus是什么

  • 简化组件之间通信。
    1. 解耦事件的发送者和接受者。
    2. 在Activities,Fragments和后台线程之间都有很好的表现
    3. 避免复杂的和容易出错的依赖和生命周期
  • 使代码简单
  • 快,高性能:特别是在注重性能的Android上。也许在其同类的解决方案是最快。
  • 小(jar包小于50K),但是强大:EventBus是一个很小的库,它的API超级简单。然而,你的软件架构也许非常受益于组件解耦:当使用事件的时候,订阅者不需要知道发送者
  • 在实践中被100,000,000+的应用安装测试证明
  • 有在线程间传递,订阅优先级等高级特性
  • 基于方便的注解(不牺牲性能):只需要通过在你的订阅方法放置@Subscribe注解。因为是在编译的时候索引注解,EventBus不需要在app运行时间做注解反射(在android上会很慢)。
  • android主线程传递:当和UI交互的时候,EventBus可以在主线程传递事件无论这个事件是怎么提交的。
  • 后台线程传递:如果订阅者运行长时间的任务,EventBus也可以使用后台线程来避免UI阻塞。
  • 事件和订阅继承:在EventBus中,事件和订阅类都是面向对象的范例。事件A是B的父类。提交B类型的事件也会提交给对A感兴趣的订阅者。类似的订阅者类也是如此。
  • 0配置:在代码中任何位置可以立刻使用一个默认的EventBus实例。
  • 可配置:可以按需求调整EventBus,可以使用建造者模式调整行为。
  • EventBus和Android的广播和Intent系统有什么不同
    不像Android的广播和intent系统,EventBus使用标准的java类作为事件并且提供更多的方便的API。EventBus更多的使用场景是不想麻烦的设置intent,准备intent extras,实现广播接收者,再提取intent extras。而且开销更低。

添加到你的工程

EventBus可以从JCenter和Maven中央仓库获取,所以只需在gradle脚本中添加这个依赖:

1
complie 'org.greenrobot:eventbus:3.0.0'

###开始使用EventBus
使用EventBus只需3步。在此之前先在Gradle脚本中添加依赖。

1
complie 'org.greenrobot:eventbus:3.0.0'

第一步:定义事件

事件是POJO(plain old java object)类型,不需要特别需求

1
2
3
4
5
6
public class MessageEvent {
public final String message;
public MessageEvent(String message) {
this.message = message;
}
}

第二步:准备订阅者

订阅者实现事件处理方法(也叫做订阅者方法),这个方法会在事件提交的时候被调用。这些是使用@Subscribe注解定义的。请注意EventBus 3的方法名字可以自由选择(不像EventBus 2中约束的那样)。

1
2
3
4
5
6
7
8
9
10
11
// 当一个Message Event提交的时候这个方法会被调用
@Subscribe
public void onMessageEvent(MessageEvent event){

Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();
}

// 当一个SomeOtherEvent被提交的时候这个方法被调用。
@Subscribe
public void handleSomethingElse(SomeOtherEvent event){

doSomethingWith(event);
}

订阅者也需要在bus中注册和注销。只有在订阅者注册的时候,他们才会收到事件。在Android中,Activities和Fragments通常绑定他们的生命周期.

1
2
3
4
5
6
7
8
9
10
11
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}

@Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}

第三步:提交事件

在代码中任意部位提交事件。所有当前注册的匹配事件类型的订阅者会收到事件。

1
EventBus.getDefault().post(new MessageEvent("Hello everyone!"));

线程间传递(线程模式)

事件可以在不同线程间传递。典型的使用就是用来处理UI改变,网络操作,或者耗时的操作。EventBus可以处理这些任务并同步UI线程(不必再考虑线程转换,使用AsyncTask,等)。
有四种线程模式:

线程模式:POSTING

默认情况下,订阅者在被提交事件的线程被调用。事件同步完成传递,一旦事件提交所有的订阅者都会被调用。这种模式意味着最小的开销,因为避免了线程切换。所以对那些花费很短的时间来完成,不需要在主线程中的简单的任务这是推荐使用的模式。事件处理程序使用这种应该是很快能返回,避免阻塞提交线程比如主线程。比如:

1
2
3
4
@Subscribe(threadMode = ThreadMode.POSTING) // ThreadMode is optional here
public void onMessage(MessageEvent event) {
log(event.message);
}

线程模式:MAIN

订阅者会在主线程被调用。如果提交的线程是主线程,事件处理方法会直接被调用(就像Thread.POSTING描述的那样同步)。事件处理程序使用这个模式必须快速返回避免阻塞主线程。比如:

1
2
3
4
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessage(MessageEvent event) {
textField.setText(event.message);
}

线程模式:BACKGROUND

订阅者会在后台线程被调用。如果不是在主线程提交,事件处理方法会直接在提交线程被调用。如果是在主线程提交,EventBus使用一个单独的后台线程按顺序传递所有事件。事件处理使用这种模式应该尽快返回避免阻塞后台线程。

1
2
3
4
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onMessage(MessageEvent event){
saveToDisk(event.message);
}

线程模式:ASYNC

事件处理方法会在一个单独的线程被调用。这个线程通常和提交的线程和主线程是独立的。提交的事件从不等待事件处理方法。事件处理方法如果需要花费一段时间比如访问网络应该使用这种模式。避免在同一时间触发大量长时间异步的处理方法来限制并发的线程。EventBus使用一个线程池来有效重复利用线程完成的异步事件处理程序的通知。

1
2
3
4
@Subscribe(threadMode = ThreadMode.ASYNC)
public void onMessage(MessageEvent event){
backend.send(event.message);
}

###配置
EventBusBuilder用来配置EventBus。比如,如果一个提交的事件没有订阅者,可以让EventBus保持安静。

1
2
EventBus eventBus = EventBus.builder().logNoSubscriberMessages(false)
.sendNoSubscriberEvent(false).build();

另一个例子是当一个订阅者抛出一个异常的失败。注意:默认情况下,EventBus捕获异常从onEvent方法中抛出并且发出一个SubscriberExceptionEvent ,这个事件可能不必处理。

1
EventBus eventBus = EventBus.builder().throwSubscriberException(true).build();

更多配置,查看官方文档

配置默认EventBus实例

使用EventBus.getDefault()是一个简单的方法获取共享的EventBus实例。EventBusBuilder也可以使用installDefaultEventBus()方法来配置这个默认的实例。
比如,当在onEvent方法中发生异常的时候,可以配置默认的EventBus实例来重新抛出异常。建议在使用DEBUG模式的时候这么使用,因为这样app会因为这个异常而崩溃。

1
EventBus.builder().throwSubscriberException(BuildConfig.DEBUG).installDefaultEventBus();

注意:只有在默认EventBus实例在第一次使用之前这么配置一次。后续调用installDefaultEventBus() 会抛出异常。这确保应用程序的行为一致。可以在Application类中配置默认的EventBus。

###Sticky Event
一些事件携带在事件提交之后仍然感兴趣的信息。比如,一个事件标记一些初始化完成或者一些传感器或位置数据的最新的值。可以使用sticky事件来代替你自己的实现。EventBus在内存中保持某一个类型的最后的sticky事件。这个sticky事件可以传递到订阅者或者也可以被明确的查询。因此,不需要任何特殊的逻辑来考虑已经可用的数据。

Sticky实例

一个sticky事件是一段时间之前被提交的。

1
EventBus.getDefault().postSticky(new MessageEvent("Hello everyone!"));

现在,sticky事件被提交了,一个新的activity启动。在注册过程中所有的sticky的订阅者方法都会立刻获取到之前提交的sticky事件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}

@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onEvent(MessageEvent event) {
// UI updates must run on MainThread
textField.setText(event.message);
}

@Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}

手动获取和移除sticky事件

就像前一段说的那样,最后的sticky事件在订阅者注册的时候会自动传递。但是,有时候手动检测sticky事件更方便。有时候他们不再传递的时候需要移除sticky事件。比如:

1
2
3
4
5
6
7
MessageEvent stickyEvent = EventBus.getDefault().getStickyEvent(MessageEvent.class);
// Better check that an event was actually posted before
if(stickyEvent != null) {
// "Consume" the sticky event
EventBus.getDefault().removeStickyEvent(stickyEvent);
// Now do something with it
}

removeStickyEvent方法是超载的:当传入一个类,它会返回之前保持的sticky事件。使用这中变化可以提升之前的例子。

1
2
3
4
5
MessageEvent stickyEvent = EventBus.getDefault().removeStickyEvent(MessageEvent.class);
// Better check that an event was actually posted before
if(stickyEvent != null) {
// Now do something with it
}

###优先级和事件取消
大部分的EventBus都不需要优先级或事件取消,但是它们在特殊情况下会派上用场。比如,一个app在后台运行的时候一个事件触发了一些UI的逻辑 ,但是如果app当前对用户是不可见的,那么应该有不同的反应。

订阅者优先级

可以通过在注册期间提供的优先级来改变事件传递的顺序。

1
2
3
4
@Subscribe(priority = 1);
public void onEvent(MessageEvent event) {

}

在相同的传递线程(ThreadMode),高优先级的订阅者接收事件会在低优先级之前。默认优先级是0。
注意:优先级不会对不同ThreadModes订阅者之间的传递顺序有影响。

取消事件传递

在订阅者事件处理方法中通过cancelEventDelivery(Object event)取消事件传递。任何之后的事件传递都会取消:后续的订阅者不再接收这个事件。

1
2
3
4
5
6
7
8
// Called in the same thread (default)
@Subscribe
public void onEvent(MessageEvent event){

// Process the event


EventBus.getDefault().cancelEventDelivery(event) ;
}

事件通常是被优先级高的订阅者取消。取消对于运行在提交线程ThreadMode.PostThread的事件处理方法是被限制的。

###订阅者索引

订阅者索引(subscriber index)是EventBus3的新特性。这是个可选的优化项来提速初始化订阅者注册。订阅者索引可以使用EventBus的注解处理器在编译阶段创建。虽然使用索引不是必须的,但是android最佳实践还是推荐使用。

索引先决条件

注意只有订阅者和事件类是public,@Subscriber方法能被索引。由于java的注解本身处理的技术限制,@Subscribe注解不会被匿名内部类识别。当EventBus不能使用索引,它会自动回退到运行时起作用。所以它仍然起作用,只是慢了一点。

生成索引

为了能够生成索引,需要添加EventBus注解处理器到使用了android-apt gradle插件的编译环境。还需要传递一个参数为“eventBusIndex”到指定完全限定的想要生成索引的类。添加下面的部分到Gradle编译脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
buildscript {
dependencies {
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
}
apply plugin: 'com.neenbedankt.android-apt'
dependencies {
compile 'org.greenrobot:eventbus:3.0.0'
apt 'org.greenrobot:eventbus-annotation-processor:3.0.1'
}
apt {
arguments {
eventBusIndex "com.example.myapp.MyEventBusIndex"
}
}

当下次编译工程的时候,“eventBusIndex”这个类会生成。当设置EventBus的时候,只需要这样:

1
EventBus eventBus = EventBus.builder().addIndex(new MyEventBusIndex()).build();

或者想使用默认的实例,可以这样:

1
2
3
EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();
// Now the default instance uses the given index. Use it like this:
EventBus eventBus = EventBus.getDefault();

索引Libraries

应用相同的原理来索引Library的一部分代码(并不是最终的应用程序)。这样,可以会生成多个索引类,在设置EventBus的时候这样使:

1
2
3
EventBus eventBus = EventBus.builder()
.addIndex(new MyEventBusAppIndex())
.addIndex(new MyEventBusLibIndex()).build();

###混淆
混淆器混淆方法名称,有可能会移除方法那些没有调用的方法。因为订阅方法没有被直接调用,混淆器误认为他们没有被使用。在ProGuard配置中使用下面的片段保护订阅者被移除:

1
2
3
4
5
6
7
8
9
10
-keepattributes *Annotation*
-keepclassmembers class ** {
@org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }

# Only required if you use AsyncExecutor
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
<init>(java.lang.Throwable);
}

注意:不管是否使用索引,都需要这么配置。

###AsyncExecutor

免责声明:AsyncExecutor不是一个核心的utility类。在处理后台线程它也许会保存一些错误代码,但是它不是一个核心的EventBus类。
AsyncExecutor像一个线程池,但是有错误(异常)处理。错误会抛出异常,AsyncExecutor会在事件中包裹这些异常。
通常调用AsyncExecutor.create()方法在Application中来创建一个实例。实现RunnableEx接口来执行。RunnableEx和Runnable不一样,RunnableEx会抛出异常。
如果RunnableEx的实现抛出一个异常,它会在ThrowableFailureEvent中捕获到。
执行的例子:

1
2
3
4
5
6
7
8
9
AsyncExecutor.create().execute(
new RunnableEx {
public void run throws LoginException {
// No need to catch any Exception (here: LoginException)
remote.login();
EventBus.getDefault().postSticky(new LoggedInEvent());
}
}
}

接收的例子:

1
2
3
4
5
6
7
public void onEventMainThread(LoggedInEvent event) {
// Change some UI
}

public void onEventMainThread(ThrowableFailureEvent event) {
// Show error in UI
}

AsyncExecutor生成器

使用静态的Async Executor来自定义Async Executor实例。它会返回一个生成器来自定义EventBus实例,线程池,和失败的事件类。
另一个可以自定义的选项是提供错误事件上下文环境信息的执行范围。比如,一个错误事件可能只关联到一个指定的Activity实例或类。你自定义错误事件实现了HasExecutionScope接口,AsyncExecutor会自动设置执行范围。这样,订阅者可以在它执行范围查询错误事件并基于它做出相应操作。

CountDownTimer

CountDownTimer是android sdk中os包下的一个辅助抽象类,这个类通过handler来实现一个倒计时的操作。在倒计时期间会定期调用用户实现的回调函数。
比如一个简单的使用场景:一个30秒倒计时

1
2
3
4
5
6
7
8
9
new CountDownTimer(30000, 1000) {

public void onTick(long millisUntilFinished) {
mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
}
public void onFinish() {
mTextField.setText("done!");
}
}.start();

onTick方法对这个对象来说是同步的,当onTick方法的实现花费的时间和倒计时的间隔来说需要很久的时候,调用onTick也是按照顺序发生的,方法不会在之前的回调完成之前发生。

1
2
3
4
5
6
7

private long mStopTimeInFuture;

/**
* 是否取消
*/

private boolean mCancelled = false;

CountDownTime的构造函数,millisInFuture从调用start方法开始直到倒计时结束的毫秒时间,countDownInterval 接收onTick回调的时间间隔

1
2
3
4
public CountDownTimer(long millisInFuture, long countDownInterval) {
mMillisInFuture = millisInFuture;
mCountdownInterval = countDownInterval;
}

取消倒计时

1
2
3
4
5
private static final int MSG = 1;
public synchronized final void cancel() {
mCancelled = true;
mHandler.removeMessages(MSG);
}

开始倒计时

1
2
3
4
5
6
7
8
9
10
public synchronized final CountDownTimer start() {
mCancelled = false;
if (mMillisInFuture <= 0) {
onFinish();
return this;
}
mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture;
mHandler.sendMessage(mHandler.obtainMessage(MSG));
return this;
}

定期执行的回调,使用的时候需要实现这个方法,millisUntilFinished参数表示剩余时间

1
public abstract void onTick(long millisUntilFinished);

当倒计时结束的时候的回调

1
public abstract void onFinish();

处理倒计时的handler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
private Handler mHandler = new Handler() {

@Override
public void handleMessage(Message msg) {

synchronized (CountDownTimer.this) {
if (mCancelled) {
return;
}

final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime();

if (millisLeft <= 0) {
onFinish();
} else if (millisLeft < mCountdownInterval) {
// 剩余时间小于一次时间间隔的时候,不再通知,只是延迟一下
sendMessageDelayed(obtainMessage(MSG), millisLeft);
} else {
long lastTickStart = SystemClock.elapsedRealtime();
onTick(millisLeft);

// 处理用户onTick执行的时间
long delay = lastTickStart + mCountdownInterval - SystemClock.elapsedRealtime();

// 特殊情况:用户的onTick方法花费的时间比interval长,那么直接跳转到下一次interval
while (delay < 0) delay += mCountdownInterval;

sendMessageDelayed(obtainMessage(MSG), delay);
}
}
}
};

通过源码可知,CountDownTimer采用的是handler机制,通过sendMessageDelayed延迟发送一条message到主线程的looper中,然后在自身中收到之后判断剩余时间,并发出相关回调,然后再次发出message的方式。之前实现这种倒计时是通过asynctask,在线程中通过Thread.sleep来实现,通过asyntask的cancel来实现取消,通过构造asynctask传入接口的实现来onTick的类似功能。这个CountDownTimer默认是在当前looper当中,可以是在UI线程也可以是在非UI线程中执行,如果在UI线程中执行,那是不是会稍微加重UI线程的负担?

LruCache

LruCache,最近最少使用缓存算法,乍一听好复杂的算法,还得记录和比较使用次数啥的,看来源码才知道,原来只是名字挺唬人。

LruCache是一种保持一定数量values(被缓存的值)的强引用的缓存。每次缓存value的时候,它会移到队列的头部。当一个value添加到一个已经满的缓存的时候,那个队列最后的value会被抛弃并且这时候最后的value可以被垃圾回收。如果缓存的values持有的资源需要明确的释放,重写entryRemoved方法来释放持有的资源。

如果一个cache miss(缓存未命中)的时候需要得到key值相对应的value,重写create()方法.即使有一个cache miss,也允许一直返回一个它假定的值,这是为了简化调用代码,

默认情况下,缓存大小通过entries的数量来计算。重写sizeOf方法按不同的单位来计算缓存。比如:

1
2
3
4
5
6
int cacheSize = 4 * 1024 * 1024; // 4MiB
LruCache<String, Bitmap> bitmapCache = new LruCache<String, Bitmap>(cacheSize) {
protected int sizeOf(String key, Bitmap value) {
return value.getByteCount();
}
}}

这个类是线程安全的。执行多个缓存操作会原子的按以下同步缓存。

1
2
3
4
5
synchronized (cache) {
if (cache.get(key) == null) {
cache.put(key, value);
}
}}

这个类不允许key或value为null。从get,put,remove返回的null表示key不存在
从android3.1开始出现

LruCache构造方法传入缓存的最大值,内部使用LinkedHashMap来保存缓存的值

1
2
3
4
5
6
7
public LruCache(int maxSize) {
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
}
this.maxSize = maxSize;
this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
}
/**
 * @hide
 */
public void resize(int maxSize) {
    if (maxSize <= 0) {
        throw new IllegalArgumentException("maxSize <= 0");
    }

    synchronized (this) {
        this.maxSize = maxSize;
    }
    trimToSize(maxSize);
}
1
2
    
get方法,如果在缓存中存在或者可以通过create方法创建的,返回key对应的value值。如果value返回了,它会移到队列的头部。如果这个value没有被缓存或不能被创建,返回null.
public final V get(K key) { if (key == null) { throw new NullPointerException("key == null"); } V mapValue; synchronized (this) { mapValue = map.get(key);//从hashmap中获取key对应的缓存值。 if (mapValue != null) { hitCount++;//不为空,缓存命中加1 return mapValue; } missCount++;//若为空缓存未命中加1 } /* 缓存未击中之后会将该值加入到map中。接下来会尝试通过用户重写的create方法创建一个value。这个创建过程可能会花好久,当create()返回的时候map可能会变的有所不一样。 当create()执行的时候,如果map中添加了一个冲突的value,那么不管map中的value,将刚创建的value释放掉。 */ V createdValue = create(key); if (createdValue == null) { return null; } synchronized (this) { createCount++; mapValue = map.put(key, createdValue);//hashmap put方法,返回key之前对应的值 if (mapValue != null) { // 这有一个冲突,所以撤销最后一次put,也就是将之前的值再put回去。 map.put(key, mapValue); } else { size += safeSizeOf(key, createdValue); } } if (mapValue != null) {//释放刚刚创建的value持有的资源。 entryRemoved(false, key, createdValue, mapValue); return mapValue; } else { trimToSize(maxSize); return createdValue; } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

put方法,被添加的value会移动到队列的头部,返回key之前映射的value


```

public final V put(K key, V value) {
if (key == null || value == null) {
throw new NullPointerException("key == null || value == null");
}

V previous;
synchronized (this) {
putCount++;//put计数器
size += safeSizeOf(key, value);
previous = map.put(key, value);
if (previous != null) {//key之前有对应的值
size -= safeSizeOf(key, previous);
}
}

if (previous != null) {//释放之前value持有的资源。
entryRemoved(false, key, previous, value);
}

trimToSize(maxSize);
return previous;
}

trimToSize方法。移除最老的entries直到所有剩余的entries在要求的大小之内。maxSize 在返回之前最大缓存值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
private void trimToSize(int maxSize) {
while (true) {
K key;
V value;
synchronized (this) {
if (size < 0 || (map.isEmpty() && size != 0)) {
throw new IllegalStateException(getClass().getName()
+ ".sizeOf() is reporting inconsistent results!");
}

if (size <= maxSize) {
break;
}

// 获取到linked列表的最后一项
// 不同版本,这得实现可能不同
Map.Entry<K, V> toEvict = null;
for (Map.Entry<K, V> entry : map.entrySet()) {
toEvict = entry;
}
if (toEvict == null) {
break;
}

key = toEvict.getKey();
value = toEvict.getValue();
map.remove(key);
size -= safeSizeOf(key, value);
evictionCount++;
}

entryRemoved(true, key, value, null);
}
}

remve方法,返回key对应的value

public final V remove(K key) {
    if (key == null) {
        throw new NullPointerException("key == null");
    }

    V previous;
    synchronized (this) {
        previous = map.remove(key);
        if (previous != null) {//成功移除,修改缓存当前大小
            size -= safeSizeOf(key, previous);
        }
    }

    if (previous != null) {//释放资源
        entryRemoved(false, key, previous, null);
    }

    return previous;
}

entryRemoved方法。已经被驱逐或被移除的entries会调用这个方法。当一个value被驱逐来释放空间,调用remove来移除或者调用put方法替换的时候会调用这个方法。默认实现什么都不做。方法调用的时候没有同步:在这个方法执行的时候其他线程可以访问缓存。evicted参数:如果entry被移除来释放空间返回true,如果移除是因为put方法或remove方法返回false。newValue参数表示key对应的新的value(如果存在的话).这个值如果不为空,是因为put引起的。否则的话是驱逐或remove引起的

1
protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {}

create方法。在缓存未中之后调用来计算key映射的value.方法调用的时候没有同步:在这个方法执行的时候其他线程可以访问缓存。当这个方法返回的时候,如果key对应的value在cache中存在,创建的value会通过entryRemove()释放并丢弃。当多个线程在同一时间请求相同的key的时候(引起多个values被创建),或者当一个线程调用put方法另一个正在为这个key创建一个value可能会发生这种情况

1
2
3
protected V create(K key) {
return null;
}

safeSizeOf方法,检测用户重写的sizeOf方法的返回值是否合法。

1
2
3
4
5
6
7
private int safeSizeOf(K key, V value) {
int result = sizeOf(key, value);
if (result < 0) {
throw new IllegalStateException("Negative size: " + key + "=" + value);
}
return result;
}

sizeOf方法按用户定义的单位返回entry的大小。默认实现是返回1,这时候size表示entris的数量,max size表示entries的最大数量。entry的大小在缓存期间不能改变

1
2
3
4
5
6
7
8
9
10
11

protected int sizeOf(K key, V value) {
return 1;
}

/**
* 清空缓存
*/

public final void evictAll() {
trimToSize(-1);
}

size方法,final类型,不能被子类重写。如果缓存没有重写sizeOf()方法,这个方法返回缓存中entries的数量。对于其他的缓存,这个返回缓存中entries大小的和。

1
2
3
public synchronized final int size() {
return size;
}

snapshot方法返回当前缓存内容的拷贝,按照最近最少使用到最近最多使用的顺序。

1
2
3
public synchronized final Map<K, V> snapshot() {
return new LinkedHashMap<K, V>(map);
}

总之,LruCache内部使用LinkedHashMap来保存缓存的值。初始化的时候传入缓存的最大值或者缓存的最大个数(如果sizeOf方法返回1的话)。如果重写来create方法,在使用get方法的时候,如果缓存不存在,就将新创建的value加入到缓存中,这样就不用再次使用put来加入缓存了(因为create不是线程安全的,所以,创建成功之后是否应该加入缓存还需要再判断一下)。

Loader

执行异步加载数据的抽象类。当Loaders是激活状态,他们会监视数据源而且当他们的内容发生变化时传递新的结果.在线程上注意:loaders客户端对Loader进行任何调用应该在他们进程中的主线程中(就是说调用者在A线程,处理过程在B线程)。Loader的子类(比如AsyncTaskLoader)通常会在一个单独线程执行任务,但是结果会传递到主线程。子类通常必须至少实现onStartLoading(),onStopLoading(),onForceLoad(),onReset().更多的实现不应该直接继承自该类,而是继承制AsyncTaskLoader

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
ContentObserver的一个实现:当observer告诉它内容已经改变的时候,这个类控制链接到Loader来使loader重新加载数据.
一般不需要用这个类;它会被CursorLoader使用:当cursor的返回数据改变的时候来控制执行更新
*/

public final class ForceLoadContentObserver extends ContentObserver {
public ForceLoadContentObserver() {
super(new Handler());
}

@Override
public boolean deliverSelfNotifications() {
return true;
}

@Override
public void onChange(boolean selfChange) {
onContentChanged();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
public interface OnLoadCompleteListener<D> {
public void onLoadComplete(Loader<D> loader, D data);
}

/**
Loaders可以跨多个activities来使用,若以直接存储context比较危险
从getContext方法返回的Context在跨Activity实例之间使用是安全的
*/

public Loader(Context context) {
mContext = context.getApplicationContext();//它是获取了Application context
}

/**
这个方法会在关联到fragment/activity上时由LoaderManager自动调用,当使用一个LoaderManager控制Loader时,你不能调用这个方法,否则会和Loader的管理冲突。
如果之前的加载已经完成而且仍然有效,结果可能立刻传递到回调接口。loader会监视数据源同时提供以后数据源变化的回调
调用stopLoading来停止传递回调
*/

public final void startLoading() {
mStarted = true;
mReset = false;
mAbandoned = false;
onStartLoading();
}

/**
尝试取消当前的加载任务。必须在进程的主线程
取消不是一个立即执行的操作,因为加载是在一个后台线程。如果当前有一个加载,这个方法要求取消加载;一旦后台线程已经完成它的remaining状态会被清除。如果其他load在这个时候要求加载,它会在取消操作完成之前保持阻塞。
当返回true,任务仍然在运行,当任务执行完毕OnLoadCanceledListener会被调用
*/

public boolean cancelLoad() {
return onCancelLoad();
}

/**
强制一个异步加载。和startLoading()不同,这个会忽略之前加载的数据,加载一个新的。
你通常应该只有在isStarted()返回true的时候才调用这个方法
*/

public void forceLoad() {
onForceLoad();
}
/**
这个方法会在取消关联到fragment/activity上时由LoaderManager自动调用,当使用一个LoaderManager控制Loader时,你不能调用这个方法,否则会和Loader的管理冲突
停止传递更新数据直到下一次startLoading被调用。实现应该不使他们的数据在这一点上无效,客户端仍然可以自由的使用loader最后提交的数据。但是如果数据改变他们通常停止提交新的数据;他们还会检测变化,但是一定不能把他们提交到客户端直到startLoading()被调用
*/

public void stopLoading() {
mStarted = false;
onStopLoading();
}

/**
这个方法会在重启一个Loader时由LoaderManager自动调用
这个必须在reset之前调用。来保留当前的数据但是不提交任何新的数据
*/

public void abandon() {
mAbandoned = true;
onAbandon();
}

/**
这个方法会在销毁一个Loader时由LoaderManager自动调用,,当使用一个LoaderManager控制Loader时,你不能调用这个方法,否则会和Loader的管理冲突

重新设置Loader的状态。loader应该在这个点释放所有资源,因为它可能永远不再被调用。但是startLoading()也许会在之后调用在这个点上它必须能够再次启动运行。
*/

public void reset() {
onReset();
mReset = true;
mStarted = false;
mAbandoned = false;
mContentChanged = false;
mProcessingChange = false;
}

/**
* 取当前标志,这个标志表明当loader已经停止的时候loader的内容是否已更改.如果已经更改,返回true同时标志清除。
*/

public boolean takeContentChanged() {
boolean res = mContentChanged;
mContentChanged = false;
mProcessingChange |= res;
return res;
}

/**
保证你实际上已经完全处理了takeContentChanged返回的内容更改。和rollbackContentChanged()一块使用来处理load取消的情形。当你已经完全处理了一个没有取消的load时调用这个方法。
*/

public void commitContentChanged() {
mProcessingChange = false;
}

/**This is
* to handle the case where a data load due to a content change has been
* canceled before its data was delivered back to the loader.
* report你已经放弃处理由takeContentChanged()返回的内容更改并且回滚到一个正在等待的内容更改的状态。这个用来处理当因为内容改变在它的的数据传回loader之前已经取消数据加载的情况
*/

public void rollbackContentChanged() {
if (mProcessingChange) {
mContentChanged = true;
}
}

/**
* 当ForceLoadContentObserver检测到改变的时候调用。默认的实现检查loader当前是否启动;如果是启动状态,仅调用forceLoad();否则的话设置一个标示使takeContentChanged()返回true。

必须从进程的主线程调用。

*/

public void onContentChanged() {
if (mStarted) {
forceLoad();
} else {
// This loader has been stopped, so we don't want to load
// new data right now... but keep track of it changing to
// refresh later if we start again.
// 这个loader已经停止,我们不想立刻加载新数据。。。
mContentChanged = true;
}
}

AsyncTaskLoader

抽象的Loader,提供一个AsyncTask来完成任务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
final class LoadTask extends AsyncTask<Void, Void, D> implements Runnable {
private final CountDownLatch mDone = new CountDownLatch(1);

// 设置为true意味着任务已经提交给handler在晚些时候执行。Used to throttle updates.
boolean waiting;

/* 在一个工作线程运行 */
@Override
protected D doInBackground(Void... params) {
try {
D data = AsyncTaskLoader.this.onLoadInBackground();
return data;
} catch (OperationCanceledException ex) {
if (!isCancelled()) {
// onLoadInBackground抛出一个取消异常。这是有问题的,因为这意味着LoaderManager没有取消Loader而且希望收到结果。
// Loader的状态不会再更新来影响任务被取消的现实。所以按未经处理的异常处理
throw ex;
}
return null;
}
}

/* 在UI线程运行*/
@Override
protected void onPostExecute(D data) {
try {
AsyncTaskLoader.this.dispatchOnLoadComplete(this, data);
} finally {
mDone.countDown();
}
}

/* 在UI线程运行*/
@Override
protected void onCancelled(D data) {
try {
AsyncTaskLoader.this.dispatchOnCancelled(this, data);
} finally {
mDone.countDown();
}
}

/*
当等待的任务提交给一个handler,在UI线程运行
当任务执行被延迟(waiting是true)这个方法才会被调用
*/

@Override
public void run() {
waiting = false;
AsyncTaskLoader.this.executePendingTask();
}

/* 用于测试目的,等待任务完成。*/
public void waitForLoader() {
try {
mDone.await();
} catch (InterruptedException e) {
}
}
}

void executePendingTask() {
if (mCancellingTask == null && mTask != null) {
if (mTask.waiting) {
mTask.waiting = false;
mHandler.removeCallbacks(mTask);
}
if (mUpdateThrottle > 0) {
long now = SystemClock.uptimeMillis();
if (now < (mLastLoadCompleteTime+mUpdateThrottle)) {
// 现在做另外一个加载还不是时候
mTask.waiting = true;
mHandler.postAtTime(mTask, mLastLoadCompleteTime+mUpdateThrottle);
return;
}
}
mTask.executeOnExecutor(mExecutor, (Void[]) null);
}
}

public AsyncTaskLoader(Context context) {
this(context, AsyncTask.THREAD_POOL_EXECUTOR);
}

/** {@hide} */
public AsyncTaskLoader(Context context, Executor executor) {
super(context);
mExecutor = executor;
}
@Override
protected void onForceLoad() {
super.onForceLoad();
cancelLoad();
mTask = new LoadTask();
executePendingTask();
}


@Override
protected boolean onCancelLoad() {
if (mTask != null) {
if (mCancellingTask != null) {
// 有一个准备好的任务已经在等待前一个任务取消;just drop it.
if (DEBUG) Slog.v(TAG,
"cancelLoad: still waiting for cancelled task; dropping next");
if (mTask.waiting) {
mTask.waiting = false;
mHandler.removeCallbacks(mTask);
}
mTask = null;
return false;
} else if (mTask.waiting) {
// 有一个task,但是它正在等待执行,扔掉它。
if (DEBUG) Slog.v(TAG, "cancelLoad: task is waiting, dropping it");
mTask.waiting = false;
mHandler.removeCallbacks(mTask);
mTask = null;
return false;
} else {
boolean cancelled = mTask.cancel(false);
if (cancelled) {
mCancellingTask = mTask;
cancelLoadInBackground();
}
mTask = null;
return cancelled;
}
}
return false;
}


void dispatchOnCancelled(LoadTask task, D data) {
onCanceled(data);
if (mCancellingTask == task) {
rollbackContentChanged();
mLastLoadCompleteTime = SystemClock.uptimeMillis();
mCancellingTask = null;
deliverCancellation();
executePendingTask();
}
}

void dispatchOnLoadComplete(LoadTask task, D data) {
if (mTask != task) {
// 完成旧任务,试着去取消。
dispatchOnCancelled(task, data);
} else {
if (isAbandoned()) {
// 这个cursor已经被放弃;只是取消新的数据
onCanceled(data);
} else {
commitContentChanged();
mLastLoadCompleteTime = SystemClock.uptimeMillis();
mTask = null;
deliverResult(data);
}
}
}


/**
在任务线程被调用执行真正的加载操作并返回加载操作的结果

这个方法的实现不应该直接传递结果,应该从这个方法返回结果这个方法最终结束的时候会在UI线程调用deliverResult。
如果方法的实现需要在UI线程处理结果,应该实现deliverResult。

为了支持取消操作,这个方法应该间断性的检测isLoadInBackgroundCanceled的值并且在它返回的时候中断掉。
子类可以直接通过重写cancelLoadInBackground来中断加载,而不是轮询isLoadInBackgroundCanceled

如果加载取消了,这个方法也许会正常返回也许会抛出OperationCanceledException。不管哪种情况,Loader都会调用onCanceled来执行取消之后的清理操作和处理结果如果有的话。
*/

public abstract D loadInBackground();

/**
这个方法是为加载框架预留的,子类应该重写loadInBackground而不是这个方法
*/

protected D onLoadInBackground() {
return loadInBackground();
}

/**
在主线程调用终止加载过程

重写这个方法来终止当前loadInBackground的调用

这个方法应该在loadInBackground还没开始或者已经结束之后啥都不做。
*/

public void cancelLoadInBackground() {
}

/**
锁定当前线程直到loader完成当前的加载操作。如果没有加载操作在运行会直接返回。
不要在UI线程调用:在UI线程调用会引起死锁
只是用来测试,不要在UI线程调用
* @hide
*/

public void waitForLoader() {
LoadTask task = mTask;
if (task != null) {
task.waitForLoader();
}
}

CursorLoader

查询ContentResolver并返回一个Cursor的loader.这个类通过标准的方式实现Loader协议来查询cursors,建造AsyncTaskLoader在后台线程来执行cursor.一个CursorLoader必须以完整信息构建来执行查询操作,要不然通过CursorLoader(Context, Uri, String[], String, String[], String),要不然通过创建一个空的实例CursorLoader(Context),并且调用setUri,setSelection,setSelectionArgs,setSortOrder,setProjection

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
/* 在任务线程运行 */
@Override
public Cursor loadInBackground() {
synchronized (this) {
if (isLoadInBackgroundCanceled()) {
throw new OperationCanceledException();
}
mCancellationSignal = new CancellationSignal();
}
try {
Cursor cursor = getContext().getContentResolver().query(mUri, mProjection, mSelection,
mSelectionArgs, mSortOrder, mCancellationSignal);
if (cursor != null) {
try {
// Ensure the cursor window is filled.
cursor.getCount();
cursor.registerContentObserver(mObserver);
} catch (RuntimeException ex) {
cursor.close();
throw ex;
}
}
return cursor;
} finally {
synchronized (this) {
mCancellationSignal = null;
}
}
}


@Override
public void cancelLoadInBackground() {
super.cancelLoadInBackground();

synchronized (this) {
if (mCancellationSignal != null) {
mCancellationSignal.cancel();
}
}
}

/* UI线程运行 */
@Override
public void deliverResult(Cursor cursor) {
if (isReset()) {
// 当loader停止的时候一个异步查询到来
if (cursor != null) {
cursor.close();
}
return;
}
Cursor oldCursor = mCursor;
mCursor = cursor;

if (isStarted()) {
super.deliverResult(cursor);
}

if (oldCursor != null && oldCursor != cursor && !oldCursor.isClosed()) {
oldCursor.close();
}
}

public CursorLoader(Context context) {
super(context);
mObserver = new ForceLoadContentObserver();
}

/**
开始一个异步的加载。当结果准备好,回调接口会在UI线程调用。如果之前的加载已经完成而且仍然有效,结果会立刻传递到回调。
必须在UI线程调用
*/

@Override
protected void onStartLoading() {
if (mCursor != null) {
deliverResult(mCursor);
}
if (takeContentChanged() || mCursor == null) {
forceLoad();
}
}

@Override
protected void onStopLoading() {
// 如果可能尝试取消当前的加载任务。
cancelLoad();
}

@Override
public void onCanceled(Cursor cursor) {
if (cursor != null && !cursor.isClosed()) {
cursor.close();
}
}

@Override
protected void onReset() {
super.onReset();

// 确保加载停止
onStopLoading();

if (mCursor != null && !mCursor.isClosed()) {
mCursor.close();
}
mCursor = null;
}

CancellationSignal

提供在过程中可以取消操作的能力

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
public boolean isCanceled() {
synchronized (this) {
return mIsCanceled;
}
}

public void throwIfCanceled() {
if (isCanceled()) {
throw new OperationCanceledException();
}
}

/**
取消相应操作并且调用取消listener。
如果操作还没开始,它会尽可能早点取消
*/

public void cancel() {
final OnCancelListener listener;
final ICancellationSignal remote;
synchronized (this) {
if (mIsCanceled) {
return;
}
mIsCanceled = true;
mCancelInProgress = true;
listener = mOnCancelListener;
remote = mRemote;
}

try {
if (listener != null) {
listener.onCancel();
}
if (remote != null) {
try {
remote.cancel();
} catch (RemoteException ex) {
}
}
} finally {
synchronized (this) {
mCancelInProgress = false;
notifyAll();
}
}
}

/**
这个方法是用来作为一个cancellation signal的接受者,比如一个数据库或一个content provider在执行一个长时间的操作时,执行取消请求。
这个方法不是给应用程序使用的
如果cancel已经被被调用,提供的listener会立刻被调用
这个方法确保listener在移除之后不被调用
如果传入的listener为null,会移除当前listener
*/

public void setOnCancelListener(OnCancelListener listener) {
synchronized (this) {
waitForCancelFinishedLocked();

if (mOnCancelListener == listener) {
return;
}
mOnCancelListener = listener;
if (!mIsCanceled || listener == null) {
return;
}
}
listener.onCancel();
}

/**
如果cancel已经被调用,提供的远程ICancellationSignal会被立刻调用
* @hide
*/

public void setRemote(ICancellationSignal remote) {
synchronized (this) {
waitForCancelFinishedLocked();

if (mRemote == remote) {
return;
}
mRemote = remote;
if (!mIsCanceled || remote == null) {
return;
}
}
try {
remote.cancel();
} catch (RemoteException ex) {
}
}

private void waitForCancelFinishedLocked() {
while (mCancelInProgress) {
try {
wait();
} catch (InterruptedException ex) {
}
}
}

/**
* Creates a transport that can be returned back to the caller of
* a Binder function and subsequently used to dispatch a cancellation signal.
*
* @hide
*/

public static ICancellationSignal createTransport() {
return new Transport();
}

/**
* Given a locally created transport, returns its associated cancellation signal.
*
* @param transport The locally created transport, or null if none.
* @return The associated cancellation signal, or null if none.
*
* @hide
*/

public static CancellationSignal fromTransport(ICancellationSignal transport) {
if (transport instanceof Transport) {
return ((Transport)transport).mCancellationSignal;
}
return null;
}

/**
* Listens for cancellation.
*/

public interface OnCancelListener {
/**
* Called when {@link CancellationSignal#cancel} is invoked.
*/

void onCancel();
}

private static final class Transport extends ICancellationSignal.Stub {
final CancellationSignal mCancellationSignal = new CancellationSignal();

@Override
public void cancel() throws RemoteException {
mCancellationSignal.cancel();
}
}

LoaderManager

关联一个Activity或Fragment的接口,管理一个或多个关联到本身上的一个或多个Loader实例,这个结合Activity或Fragment的生命周期帮助应用程序管理长时间运行的操作。最常和CursorLoader一块使用,应用程序可以随意写自己的loaders来加载其他类型的数据
  • See the blog post
  • Fragments For All for more details.
    *
  • {@sample development/samples/ApiDemos/src/com/example/android/apis/app/LoaderCursor.java
  • fragment_cursor}
    */
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
/**
和manager相关的客户端回调接口
*/

public interface LoaderCallbacks<D> {
public Loader<D> onCreateLoader(int id, Bundle args);

/** See {@link FragmentManager#beginTransaction()
* FragmentManager.openTransaction()} for further discussion on this.
当之前创建的一个loader已经完成它的加载时调用。注意:正常情况下应用程序不会允许在这个方法提交fragment transactions,因为它有可能在activity状态保存之后发生
* At this point
* you should remove all use of the old data (since it will be released
* soon), but should not do your own release of the data since its Loader
* owns it and will take care of that. The Loader will take care of
* management of its data so you don't have to.
*这个方法确保在这个Loader提供的最后的数据释放之前调用。基于这点你应该删除所有使用的旧数据(因为它会马上被释 放)
但是需要注意
特别的:
Loader会监视数据改变,通过新的调用提交给你。你不应该自己监视数据。比如:如果数据是个Cursor而且把它放到 CursorAdapter中,使用CursorAdapter#CursorAdapter(android.content.Context,
* android.database.Cursor, int)构造,没有传入CursorAdapter#FLAG_AUTO_REQUERY或 CursorAdapter#FLAG_REGISTER_CONTENT_OBSERVER(也就是这个参数传入的是0)。这会防止CursorAdapter监 视Cursor,这是不必要的因为当一个修改发生你会得到一个新的Cursor
* <li>
一旦Loader知道应用程序不再使用数据它就会释放数据。比如,如果数据是CursorLoader的Cursor,你不能调用 close().如果Cursor在CursorLoader中被替换,你应该使用swapCursor(Cursor)来使old Cursor不关闭。
* </ul>
*/

public void onLoadFinished(Loader<D> loader, D data);

/**
*在前一个创建的loader被重置调用,并且使它的数据不可用。应用程序应该在这时候删除它对Loader数据的所有引用
*/

public void onLoaderReset(Loader<D> loader);
}

/**
如果loader已经不再存在,一个新的会被创建而且(如果activity/fragment当前已经开始)启动loader。否则最后创建的loader会被重用。
在任何情况下,给定的回调是和loader相关的,而且会在loader状态改变的时候调用。如果在调用这点上,调用者在开始状态,被requested的loader已经存在而且生成了数据,然后onLoadFinished会被立刻调用(而不是这个方法),所以必须注意这种情况。
*/

public abstract <D> Loader<D> initLoader(int id, Bundle args,
LoaderManager.LoaderCallbacks<D> callback);

/**
在这个manager里启动一个新的或重启一个已经存在的Loader,注册回调,并且(如果activity/fragment当前已经开始)开始启动。
如果之前有相同id的loader已经启动,它会在新的loader完成工作之后自动销毁。
The callback will be delivered before the old loader
* is destroyed.
*/

public abstract <D> Loader<D> restartLoader(int id, Bundle args,
LoaderManager.LoaderCallbacks<D> callback);

/**
停止并移除给定id的loader. 如果loader之前通过#onLoadFinished(Loader, Object)给客户端提交过数据,a call
* will be made to {@link LoaderCallbacks#onLoaderReset(Loader)}.
*/

public abstract void destroyLoader(int id);

public abstract <D> Loader<D> getLoader(int id);


class LoaderManagerImpl extends LoaderManager {
static final String TAG = "LoaderManager";
static boolean DEBUG = false;

// 这些是当前激活的loaders。在这的都是那些从他们开始启动加载到他们被应用程序明确停止或重启
final SparseArray<LoaderInfo> mLoaders = new SparseArray<LoaderInfo>(0);

// 这些是之前运行的loaders.这个列表在内部主要用来避免在一个应用程序仍然使用loader的时候摧毁它。
// 它运行一个应用程序来重启一个loader,但是继续使用它之前运行的loader直到新的loader的数据可用
final SparseArray<LoaderInfo> mInactiveLoaders = new SparseArray<LoaderInfo>(0);

final String mWho;

Activity mActivity;
boolean mStarted;
boolean mRetaining;
boolean mRetainingStarted;

boolean mCreatingLoader;

final class LoaderInfo implements Loader.OnLoadCompleteListener<Object>,
Loader.OnLoadCanceledListener<Object> {
final int mId;
final Bundle mArgs;
LoaderManager.LoaderCallbacks<Object> mCallbacks;
Loader<Object> mLoader;
boolean mHaveData;
boolean mDeliveredData;
Object mData;
boolean mStarted;
boolean mRetaining;
boolean mRetainingStarted;
boolean mReportNextStart;
boolean mDestroyed;
boolean mListenerRegistered;

LoaderInfo mPendingLoader;

public LoaderInfo(int id, Bundle args, LoaderManager.LoaderCallbacks<Object> callbacks) {
mId = id;
mArgs = args;
mCallbacks = callbacks;
}

void start() {
if (mRetaining && mRetainingStarted) {
// Our owner is started, but we were being retained from a
// previous instance in the started state... so there is really
// nothing to do here, since the loaders are still started.
//
mStarted = true;
return;
}

if (mStarted) {
return;
}

mStarted = true;

if (mLoader == null && mCallbacks != null) {
mLoader = mCallbacks.onCreateLoader(mId, mArgs);
}
if (mLoader != null) {
if (mLoader.getClass().isMemberClass()
&& !Modifier.isStatic(mLoader.getClass().getModifiers())) {
throw new IllegalArgumentException(
"Object returned from onCreateLoader must not be a non-static inner member class: "
+ mLoader);
}
if (!mListenerRegistered) {
mLoader.registerListener(mId, this);
mLoader.registerOnLoadCanceledListener(this);
mListenerRegistered = true;
}
mLoader.startLoading();
}
}

void retain() {
mRetaining = true;
mRetainingStarted = mStarted;
mStarted = false;
mCallbacks = null;
}

void finishRetain() {
if (mRetaining) {
mRetaining = false;
if (mStarted != mRetainingStarted) {
if (!mStarted) {
// This loader was retained in a started state, but
// at the end of retaining everything our owner is
// no longer started... so make it stop.
stop();
}
}
}

if (mStarted && mHaveData && !mReportNextStart) {
// This loader has retained its data, either completely across
// a configuration change or just whatever the last data set
// was after being restarted from a stop, and now at the point of
// finishing the retain we find we remain started, have
// our data, and the owner has a new callback... so
// let's deliver the data now.
callOnLoadFinished(mLoader, mData);
}
}

void reportStart() {
if (mStarted) {
if (mReportNextStart) {
mReportNextStart = false;
if (mHaveData) {
callOnLoadFinished(mLoader, mData);
}
}
}
}

void stop() {
if (DEBUG) Log.v(TAG, " Stopping: " + this);
mStarted = false;
if (!mRetaining) {
if (mLoader != null && mListenerRegistered) {
// Let the loader know we're done with it
mListenerRegistered = false;
mLoader.unregisterListener(this);
mLoader.unregisterOnLoadCanceledListener(this);
mLoader.stopLoading();
}
}
}

void cancel() {
if (DEBUG) Log.v(TAG, " Canceling: " + this);
if (mStarted && mLoader != null && mListenerRegistered) {
if (!mLoader.cancelLoad()) {
onLoadCanceled(mLoader);
}
}
}

void destroy() {
if (DEBUG) Log.v(TAG, " Destroying: " + this);
mDestroyed = true;
boolean needReset = mDeliveredData;
mDeliveredData = false;
if (mCallbacks != null && mLoader != null && mHaveData && needReset) {
if (DEBUG) Log.v(TAG, " Reseting: " + this);
String lastBecause = null;
if (mActivity != null) {
lastBecause = mActivity.mFragments.mNoTransactionsBecause;
mActivity.mFragments.mNoTransactionsBecause = "onLoaderReset";
}
try {
mCallbacks.onLoaderReset(mLoader);
} finally {
if (mActivity != null) {
mActivity.mFragments.mNoTransactionsBecause = lastBecause;
}
}
}
mCallbacks = null;
mData = null;
mHaveData = false;
if (mLoader != null) {
if (mListenerRegistered) {
mListenerRegistered = false;
mLoader.unregisterListener(this);
mLoader.unregisterOnLoadCanceledListener(this);
}
mLoader.reset();
}
if (mPendingLoader != null) {
mPendingLoader.destroy();
}
}

@Override
public void onLoadCanceled(Loader<Object> loader) {
if (DEBUG) Log.v(TAG, "onLoadCanceled: " + this);

if (mDestroyed) {
if (DEBUG) Log.v(TAG, " Ignoring load canceled -- destroyed");
return;
}

if (mLoaders.get(mId) != this) {
// This cancellation message is not coming from the current active loader.
// We don't care about it.
if (DEBUG) Log.v(TAG, " Ignoring load canceled -- not active");
return;
}

LoaderInfo pending = mPendingLoader;
if (pending != null) {
// There is a new request pending and we were just
// waiting for the old one to cancel or complete before starting
// it. So now it is time, switch over to the new loader.
if (DEBUG) Log.v(TAG, " Switching to pending loader: " + pending);
mPendingLoader = null;
mLoaders.put(mId, null);
destroy();
installLoader(pending);
}
}

@Override
public void onLoadComplete(Loader<Object> loader, Object data) {
if (DEBUG) Log.v(TAG, "onLoadComplete: " + this);

if (mDestroyed) {
if (DEBUG) Log.v(TAG, " Ignoring load complete -- destroyed");
return;
}

if (mLoaders.get(mId) != this) {
// This data is not coming from the current active loader.
// We don't care about it.
if (DEBUG) Log.v(TAG, " Ignoring load complete -- not active");
return;
}

LoaderInfo pending = mPendingLoader;
if (pending != null) {
// There is a new request pending and we were just
// waiting for the old one to complete before starting
// it. So now it is time, switch over to the new loader.
if (DEBUG) Log.v(TAG, " Switching to pending loader: " + pending);
mPendingLoader = null;
mLoaders.put(mId, null);
destroy();
installLoader(pending);
return;
}

// Notify of the new data so the app can switch out the old data before
// we try to destroy it.
if (mData != data || !mHaveData) {
mData = data;
mHaveData = true;
if (mStarted) {
callOnLoadFinished(loader, data);
}
}

//if (DEBUG) Log.v(TAG, " onLoadFinished returned: " + this);

// We have now given the application the new loader with its
// loaded data, so it should have stopped using the previous
// loader. If there is a previous loader on the inactive list,
// clean it up.
LoaderInfo info = mInactiveLoaders.get(mId);
if (info != null && info != this) {
info.mDeliveredData = false;
info.destroy();
mInactiveLoaders.remove(mId);
}

if (mActivity != null && !hasRunningLoaders()) {
mActivity.mFragments.startPendingDeferredFragments();
}
}

void callOnLoadFinished(Loader<Object> loader, Object data) {
if (mCallbacks != null) {
String lastBecause = null;
if (mActivity != null) {
lastBecause = mActivity.mFragments.mNoTransactionsBecause;
mActivity.mFragments.mNoTransactionsBecause = "onLoadFinished";
}
try {
if (DEBUG) Log.v(TAG, " onLoadFinished in " + loader + ": "
+ loader.dataToString(data));
mCallbacks.onLoadFinished(loader, data);
} finally {
if (mActivity != null) {
mActivity.mFragments.mNoTransactionsBecause = lastBecause;
}
}
mDeliveredData = true;
}
}
}

LoaderManagerImpl(String who, Activity activity, boolean started) {
mWho = who;
mActivity = activity;
mStarted = started;
}

void updateActivity(Activity activity) {
mActivity = activity;
}

private LoaderInfo createLoader(int id, Bundle args,
LoaderManager.LoaderCallbacks<Object> callback) {
LoaderInfo info = new LoaderInfo(id, args, (LoaderManager.LoaderCallbacks<Object>)callback);
Loader<Object> loader = callback.onCreateLoader(id, args);
info.mLoader = (Loader<Object>)loader;
return info;
}

private LoaderInfo createAndInstallLoader(int id, Bundle args,
LoaderManager.LoaderCallbacks<Object> callback) {
try {
mCreatingLoader = true;
LoaderInfo info = createLoader(id, args, callback);
installLoader(info);
return info;
} finally {
mCreatingLoader = false;
}
}

void installLoader(LoaderInfo info) {
mLoaders.put(info.mId, info);
if (mStarted) {
// The activity will start all existing loaders in it's onStart(),
// so only start them here if we're past that point of the activitiy's
// life cycle
info.start();
}
}

/**
用一个特殊的ID初始化一个Loader,如果这个ID已经有Loader和它相关联,那么它保持不变而且任何之前的回调都被新的替换。如果没有和ID相关联的Loader,会产生一个新的并且启动。
这个方法通常在一个组件初始化的时候使用来确保它依赖的Loader被创建。这样如果已经有一个,会使它重用一个已经存在的Loader的数据。比如当一个Activity在configuration改变之后re-created,它就不必再re-create它的loaders.
注意:在这种情况下如果一个存在的Loader已经被使用,那么给定的args会被忽略,因为你会继续使用之前的Loader
*/

@SuppressWarnings("unchecked")
public <D> Loader<D> initLoader(int id, Bundle args, LoaderManager.LoaderCallbacks<D> callback) {
if (mCreatingLoader) {
throw new IllegalStateException("Called while creating a loader");
}

LoaderInfo info = mLoaders.get(id);

if (info == null) {
// Loader不存在,创建
info = createAndInstallLoader(id, args, (LoaderManager.LoaderCallbacks<Object>)callback);
} else {
// 重用存在的Loader
info.mCallbacks = (LoaderManager.LoaderCallbacks<Object>)callback;
}

if (info.mHaveData && mStarted) {
// 如果loader已经生产数据,现在提交
info.callOnLoadFinished(info.mLoader, info.mData);
}

return (Loader<D>)info.mLoader;
}

/**
调用来重建有特殊ID的Loader.如果当前有一个和这个Id相关联的Loader,它会在适当的时候canceled/stopped/destroyed。一个新的带有给定参数的Loader会被创建,然后它的数据会在可用的时候传给你。
这个方法减少了一些Loaders的生成。如果太多的相同ID的Loaders被创建,但是没有生成他们的数据,那么这个方法会被重新调用而且返回一个新的Loader,但是直到之前的Loader全部完成才会启动。
调用这个方法之后,任何之前相同ID的Loaders都变无效的,而且不应该再接受他们的更新数据。
*/

@SuppressWarnings("unchecked")
public <D> Loader<D> restartLoader(int id, Bundle args, LoaderManager.LoaderCallbacks<D> callback) {
if (mCreatingLoader) {
throw new IllegalStateException("Called while creating a loader");
}

LoaderInfo info = mLoaders.get(id);
if (info != null) {
LoaderInfo inactive = mInactiveLoaders.get(id);
if (inactive != null) {
if (info.mHaveData) {
// 这个loader现在有数据... we are probably being
// called from within onLoadComplete, where we haven't
// yet destroyed the last inactive loader. So just do
// that now.
inactive.mDeliveredData = false;
inactive.destroy();
info.mLoader.abandon();
mInactiveLoaders.put(id, info);
} else {
// We already have an inactive loader for this ID that we are
// waiting for! What to do, what to do...
if (!info.mStarted) {
// The current Loader has not been started... we thus
// have no reason to keep it around, so bam, slam,
// thank-you-ma'am.
if (DEBUG) Log.v(TAG, " Current loader is stopped; replacing");
mLoaders.put(id, null);
info.destroy();
} else {
// Now we have three active loaders... we'll queue
// up this request to be processed once one of the other loaders
// finishes or is canceled.
if (DEBUG) Log.v(TAG, " Current loader is running; attempting to cancel");
info.cancel();
if (info.mPendingLoader != null) {
if (DEBUG) Log.v(TAG, " Removing pending loader: " + info.mPendingLoader);
info.mPendingLoader.destroy();
info.mPendingLoader = null;
}
if (DEBUG) Log.v(TAG, " Enqueuing as new pending loader");
info.mPendingLoader = createLoader(id, args,
(LoaderManager.LoaderCallbacks<Object>)callback);
return (Loader<D>)info.mPendingLoader.mLoader;
}
}
} else {
// Keep track of the previous instance of this loader so we can destroy
// it when the new one completes.
if (DEBUG) Log.v(TAG, " Making last loader inactive: " + info);
info.mLoader.abandon();
mInactiveLoaders.put(id, info);
}
}

info = createAndInstallLoader(id, args, (LoaderManager.LoaderCallbacks<Object>)callback);
return (Loader<D>)info.mLoader;
}

/**
销毁给定ID的loader,在这个方法返回之后,任何和这个ID相关联的Loader对象都会被销毁。任何和他们相关联的数据都会被销毁。当你这样做时,你最好不要使用它。
*/

public void destroyLoader(int id) {
if (mCreatingLoader) {
throw new IllegalStateException("Called while creating a loader");
}

int idx = mLoaders.indexOfKey(id);
if (idx >= 0) {
LoaderInfo info = mLoaders.valueAt(idx);
mLoaders.removeAt(idx);
info.destroy();
}
idx = mInactiveLoaders.indexOfKey(id);
if (idx >= 0) {
LoaderInfo info = mInactiveLoaders.valueAt(idx);
mInactiveLoaders.removeAt(idx);
info.destroy();
}
if (mActivity != null && !hasRunningLoaders()) {
mActivity.mFragments.startPendingDeferredFragments();
}
}

/**
返回最近和给定ID相关联的Loader对象。
*/

@SuppressWarnings("unchecked")
public <D> Loader<D> getLoader(int id) {
if (mCreatingLoader) {
throw new IllegalStateException("Called while creating a loader");
}

LoaderInfo loaderInfo = mLoaders.get(id);
if (loaderInfo != null) {
if (loaderInfo.mPendingLoader != null) {
return (Loader<D>)loaderInfo.mPendingLoader.mLoader;
}
return (Loader<D>)loaderInfo.mLoader;
}
return null;
}

void doStart() {
if (mStarted) {
RuntimeException e = new RuntimeException("here");
e.fillInStackTrace();
return;
}

mStarted = true;

// Call out to sub classes so they can start their loaders
// Let the existing loaders know that we want to be notified when a load is complete
for (int i = mLoaders.size()-1; i >= 0; i--) {
mLoaders.valueAt(i).start();
}
}

void doStop() {
if (!mStarted) {
RuntimeException e = new RuntimeException("here");
e.fillInStackTrace();
return;
}

for (int i = mLoaders.size()-1; i >= 0; i--) {
mLoaders.valueAt(i).stop();
}
mStarted = false;
}

void doRetain() {
if (!mStarted) {
RuntimeException e = new RuntimeException("here");
e.fillInStackTrace();
return;
}

mRetaining = true;
mStarted = false;
for (int i = mLoaders.size()-1; i >= 0; i--) {
mLoaders.valueAt(i).retain();
}
}

void finishRetain() {
if (mRetaining) {

mRetaining = false;
for (int i = mLoaders.size()-1; i >= 0; i--) {
mLoaders.valueAt(i).finishRetain();
}
}
}

void doReportNextStart() {
for (int i = mLoaders.size()-1; i >= 0; i--) {
mLoaders.valueAt(i).mReportNextStart = true;
}
}

void doReportStart() {
for (int i = mLoaders.size()-1; i >= 0; i--) {
mLoaders.valueAt(i).reportStart();
}
}

void doDestroy() {
if (!mRetaining) {
for (int i = mLoaders.size()-1; i >= 0; i--) {
mLoaders.valueAt(i).destroy();
}
mLoaders.clear();
}

for (int i = mInactiveLoaders.size()-1; i >= 0; i--) {
mInactiveLoaders.valueAt(i).destroy();
}
mInactiveLoaders.clear();
}


public boolean hasRunningLoaders() {
boolean loadersRunning = false;
final int count = mLoaders.size();
for (int i = 0; i < count; i++) {
final LoaderInfo li = mLoaders.valueAt(i);
loadersRunning |= li.mStarted && !li.mDeliveredData;
}
return loadersRunning;
}
}

Activity中LoaderManager使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
ArrayMap<String, LoaderManagerImpl> mAllLoaderManagers;


public LoaderManager getLoaderManager() {
if (mLoaderManager != null) {
return mLoaderManager;
}
mCheckedForLoaderManager = true;
mLoaderManager = getLoaderManager("(root)", mLoadersStarted, true);
return mLoaderManager;
}

LoaderManagerImpl getLoaderManager(String who, boolean started, boolean create) {
if (mAllLoaderManagers == null) {
mAllLoaderManagers = new ArrayMap<String, LoaderManagerImpl>();
}
LoaderManagerImpl lm = mAllLoaderManagers.get(who);
if (lm == null) {
if (create) {
lm = new LoaderManagerImpl(who, this, started);
mAllLoaderManagers.put(who, lm);
}
} else {
lm.updateActivity(this);
}
return lm;
}

static final class NonConfigurationInstances {
Object activity;
HashMap<String, Object> children;
ArrayList<Fragment> fragments;
ArrayMap<String, LoaderManagerImpl> loaders;
}

NonConfigurationInstances mLastNonConfigurationInstances;

protected void onCreate(Bundle savedInstanceState) {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onCreate " + this + ": " + savedInstanceState);
if (mLastNonConfigurationInstances != null) {
mAllLoaderManagers = mLastNonConfigurationInstances.loaders;
}
//...其他一些与mLoaderManager无关的代码
}

protected void onStart() {
//...其他一些与mLoaderManager无关的代码

if (!mLoadersStarted) {
mLoadersStarted = true;
if (mLoaderManager != null) {
mLoaderManager.doStart();
} else if (!mCheckedForLoaderManager) {
mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false);
}
mCheckedForLoaderManager = true;
}

//...其他一些与mLoaderManager无关的代码
}

NonConfigurationInstances retainNonConfigurationInstances() {
//...其他一些与mLoaderManager无关的代码
if (mAllLoaderManagers != null) {
// prune out any loader managers that were already stopped and so
// have nothing useful to retain.
final int N = mAllLoaderManagers.size();
LoaderManagerImpl loaders[] = new LoaderManagerImpl[N];
for (int i=N-1; i>=0; i--) {
loaders[i] = mAllLoaderManagers.valueAt(i);
}
for (int i=0; i<N; i++) {
LoaderManagerImpl lm = loaders[i];
if (lm.mRetaining) {
retainLoaders = true;
} else {
lm.doDestroy();
mAllLoaderManagers.remove(lm.mWho);
}
}
}

//...其他一些与mLoaderManager无关的代码

NonConfigurationInstances nci = new NonConfigurationInstances();

//...其他一些与mLoaderManager无关的代码

nci.loaders = mAllLoaderManagers;
return nci;
}

final void performStart() {
//...其他一些与mLoaderManager无关的代码
if (mAllLoaderManagers != null) {
final int N = mAllLoaderManagers.size();
LoaderManagerImpl loaders[] = new LoaderManagerImpl[N];
for (int i=N-1; i>=0; i--) {
loaders[i] = mAllLoaderManagers.valueAt(i);
}
for (int i=0; i<N; i++) {
LoaderManagerImpl lm = loaders[i];
lm.finishRetain();
lm.doReportStart();
}
}
}

final void performStop() {
//...其他一些与mLoaderManager无关的代码
if (mLoadersStarted) {
//...其他一些与mLoaderManager无关的代码
if (mLoaderManager != null) {
if (!mChangingConfigurations) {
mLoaderManager.doStop();
} else {
mLoaderManager.doRetain();
}
}
}

//...其他一些与mLoaderManager无关的代码
}

final void performDestroy() {

//...其他一些与mLoaderManager无关的代码

if (mLoaderManager != null) {
mLoaderManager.doDestroy();
}
}

final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config)
{


//...其他一些与NonConfigurationInstances无关的代码

mLastNonConfigurationInstances = lastNonConfigurationInstances;

//...其他一些与NonConfigurationInstances无关的代码
}

final void performResume() {
performRestart();

//...其他一些与NonConfigurationInstances无关的代码

mLastNonConfigurationInstances = null;

//...其他一些与NonConfigurationInstances无关的代码

onPostResume();

//...其他一些与NonConfigurationInstances无关的代码
}

Handler

/**
Handler允许你提交并处理message或者和线程的MessageQueue相关联的Runnable对象。每一个Handler实例都和一个单独的线程以及这个线程的messge queue相关联。
当创建一个新的Handler,它就和创建了它的线程和线程创建的message queue绑定,这时候,它会传递messages和runnables到message queue,然后从message queue中取出来执行他们。

有两个主要用途1.调度messages和runnables在将来的某个时间点执行。2.在不同于你的线程里插入一个action等待被执行

messages通过调用post,postAtTime(Runnable, long),postDelayed,sendEmptyMessage,sendMessage,sendMessageAtTime,sendMessageDelayed这些方法来完成。
post系列方法允许在message queue中排列等待被调用Runnable对象;sendMessage系列方法允许排列那些将在Handler的handleMessage方法(前提是子类化了Handler)中被执行的包含bundle数据的message对象

当提交给handler,可以在message queue准备完毕之后立刻执行,或者指定一个延迟时间再执行,或绝对时间再执行。对于后两者,可以实现超时,ticks, 和其他基于时间的行为.

当应用的一个进程被创建,主线程专门用来运行一个负责管理top-level应用对象(activities, broadcast receivers,等)和这些应用创建的窗口的messge queue。
你可以创建自己的线程,然后通过一个Handler来和主应用线程通信,只需要像之前一样调用post或sendMessage方法,但是是在你的新线程。被提交的Runnable或Message会被安排到这个Handler的message queue然后在适当的时间处理。
*/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/**
如果当前线程没有looper,那么这个handler不能接受message,而且会抛出一个异常。
*/

public Handler() {
this(null, false);
}

public Handler(Callback callback) {
this(callback, false);
}

/**
使用提供的Looper而不是默认的,looper不能为空
*/

public Handler(Looper looper) {
this(looper, null, false);
}

public Handler(Looper looper, Callback callback) {
this(looper, callback, false);//第三个参数默认同步的
}

/**
设置handler是否应该是异步的
Handler默认是同步的除非构造函数明确说明使用异步
异步消息表示不需要全局顺序的中断或事件来表示同步消息。异步消息不受由MessageQueue#enqueueSyncBarrier(long)同步barriers限制
当async是true,handler会给发送给它的Message或者提交给他的Runnable调用Message的setAsynchronous(boolean)。
* @hide
*/

public Handler(boolean async) {
this(null, async);
}

/**
* @hide
*/

public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}

mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
/*
设置这个flag为true来检测继承的Handler是否是匿名,局部或成员类,而且不是静态
这些类型的可能会造成泄露
*/

private static final boolean FIND_POTENTIAL_LEAKS = false;

/**
当初始化一个Handler时避免必须实现你自己的Handler子类时,你可以使用这个回调接口
@return True 如果不需要进一步处理
*/

public interface Callback {
public boolean handleMessage(Message msg);
}

/**
子类必须实现这个方法来接受messages
*/

public void handleMessage(Message msg) {
}

/**
处理系统messages
*/

public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {//如果不需要进一步处理,返回true
return;
}
}
handleMessage(msg);
}
}

private static void handleCallback(Message message) {
message.callback.run();
}

/**从全局的message池中返回一个新的Message,比创建分配一个新的实例更高效。
检索到的消息让它的handler指向这个实例(Message.target == this).
如果你不需要这个能力,那就用Message.obtain()代替
*/

public final Message obtainMessage(){
return Message.obtain(this);
}

/**
在返回的message里设置what值
*/

public final Message obtainMessage(int what){
return Message.obtain(this, what);
}

/**
* @hide
*/

public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}

/**
将Runnable添加到message queue中,这个被添加的Runnable会在这个handler附属的线程运行
如果失败返回false,通常是因为处理message queue的looper退出了
*/

public final boolean post(Runnable r){
return sendMessageDelayed(getPostMessage(r), 0);
}

//将Runnable放到message的callback中,在Handler的dispatchMessage中被处理
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}

/**
在message queue的下一个迭代会执行这个Runnable
这个方法只有在非常特殊的情况下才会使用,它很容易饿死message queue,引起顺序问题或者其他不可预期的副作用
*/

public final boolean postAtFrontOfQueue(Runnable r){
return sendMessageAtFrontOfQueue(getPostMessage(r));
}


public final boolean sendMessageAtFrontOfQueue(Message msg) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, 0);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

/**
同步运行指定的任务
如果当前线程是handler线程,那么runnable会直接运行而不必插入队列,否则,提交runnable到handler并且在返回之前等待它完成。

这个方法很危险!不恰当的使用会引起死锁。当任何锁被持有的时候千万不能调用这个方法或者在可以重入的方法中也不能使用。
这个方法在以下场景偶尔有用:当一个后台线程必须同步的等待一个必须在handler的线程中运行的任务的完成。但是这个问题通常是不良设计的症状。在使用这个方法之前首先考虑改进设计(如果可能)

使用这个方法的一个可能:当你只是创建一个Handler线程而且需要在继续执行之前执行一些初始化步骤
超时之后返回false但是runnable仍然被提交到handler而且也许在稍后的时间已经准备或已经完成

使用了这个方法,确定要使用quitSafely来退出looper.否则runWithScissors会无限期挂起
TODO:我们应该通过将MessageQueue改为blocking runnables的方

@hide
这个方法容易滥用而且不应该出现在API中。即使我们让它成为API的一部分,我们也会用类似runUnsafe()来重命名
*/

public final boolean runWithScissors(final Runnable r, long timeout) {
if (r == null) {
throw new IllegalArgumentException("runnable must not be null");
}
if (timeout < 0) {
throw new IllegalArgumentException("timeout must be non-negative");
}

if (Looper.myLooper() == mLooper) {
r.run();
return true;
}

BlockingRunnable br = new BlockingRunnable(r);
return br.postAndWait(this, timeout);
}

以下是BlockingRunnable的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
private static final class BlockingRunnable implements Runnable {
private final Runnable mTask;
private boolean mDone;

public BlockingRunnable(Runnable task) {
mTask = task;
}

@Override
public void run() {
try {
mTask.run();
} finally {
synchronized (this) {
mDone = true;
notifyAll();
}
}
}

public boolean postAndWait(Handler handler, long timeout) {
if (!handler.post(this)) {
return false;
}

synchronized (this) {
if (timeout > 0) {
final long expirationTime = SystemClock.uptimeMillis() + timeout;
while (!mDone) {
long delay = expirationTime - SystemClock.uptimeMillis();
if (delay <= 0) {
return false; // timeout
}
try {
wait(delay);
} catch (InterruptedException ex) {
}
}
} else {
while (!mDone) {
try {
wait();
} catch (InterruptedException ex) {
}
}
}
}
return true;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/** 
在所有待执行的messages之后,在(current time + delayMillis)之前将msg插入到message queue中。会在handler附属的线程里边的handleMessage方法中收到
如果返回true,不一定意味着message将会被执行,如果looper在message传递时间发生之前退出,message会被丢掉。
*/

public final boolean sendMessageDelayed(Message msg, long delayMillis){
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
/**
在所有待执行的messages之后,在绝对时间(毫秒)uptimeMillis之前将msg插入到message queue中
时间基准是android.os.SystemClock#uptimeMillis
*/

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}

最终调用message queue的enqueueMessage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
/**
移除所有在message queue里边准备提交的Runnable
*/

public final void removeCallbacks(Runnable r){
mQueue.removeMessages(this, r, null);
}

/**
移除所有message queue里包含what的message
*/

public final void removeMessages(int what) {
mQueue.removeMessages(this, what, null);
}

public final boolean sendMessage(Message msg){
return sendMessageDelayed(msg, 0);
}

/**
发送一个只包含what值的message
*/

public final boolean sendEmptyMessage(int what){
return sendEmptyMessageDelayed(what, 0);
}

public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}



final IMessenger getIMessenger() {
synchronized (mQueue) {
if (mMessenger != null) {
return mMessenger;
}
mMessenger = new MessengerImpl();
return mMessenger;
}
}

private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
Handler.this.sendMessage(msg);
}
}

Message

/*
定义一个可以发送给Handler的message,这个message可以包含一个描述和任意数据对象。这个对象包含两个额外的int域和一个额外的对象域,这样在很多情况下就不必再分配
虽然构造方法是public,但是最好的方式得到一个message是调用Message.obtain()或者Handler.obtainMessage(),这些方法会从一个循环的对象池中取出他们
/

/*
一个任意的对象
当使用Messager在进程间发送message时,如果包含一个Parcelable的一个框架类(不是由系统实现),这是唯一不能为空的
/

public Object obj;

/**

  • Optional Messenger where replies to this message can be sent. The
  • semantics of exactly how this is used are up to the sender and
  • receiver.
    */

public Messenger replyTo;

// 有些时候我们以链表形式存储他们
/package/ Message next;

private static Message sPool;
private static final int MAX_POOL_SIZE = 50;
private static final Object sPoolSync = new Object();

当看到以下代码是感觉到大学的数据结构没白学啊。但是为什么不使用现成的Queue呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
从一个全局的池中返回一个Message实例。在很多情况下可以避免分配新的对象。
*/

public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
sPoolSize--;
return m;
}
}
return new Message();
}

public静态方法,加上同步块保证线程安全,sPool不为空的时候,声明一个引用指向它,然后将它的下一个message赋给sPool,这时候sPool指向链表的第二个,把将要取出的m的下一个next置空,池大小减1,然后返回m。(这时候sPool有可能变为null)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/**
和obtain()方法类似,只是复制这个messge到一个新的里边
*/

public static Message obtain(Message orig) {
Message m = obtain();
m.what = orig.what;
m.arg1 = orig.arg1;
m.arg2 = orig.arg2;
m.obj = orig.obj;
m.replyTo = orig.replyTo;
if (orig.data != null) {
m.data = new Bundle(orig.data);
}
m.target = orig.target;
m.callback = orig.callback;

return m;
}

/**
返回一个message实例到全局池中。在调用这个方法之后,不能再碰这个Message,它已经有效的被释放了
*/

public void recycle() {
clearForRecycle();

synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}

void clearForRecycle() {
flags = 0;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
when = 0;
target = null;
callback = null;
data = null;
}
/**
* 设置message是否是异步的。
* Asynchronous messages represent interrupts or events that do not require global ordering
* with represent to synchronous messages. Asynchronous messages are not subject to
* the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
* 异步消息表示不需要全局顺序的中断或事件来表示同步消息。
*

*
* @hide
*/

public void setAsynchronous(boolean async) {
if (async) {
flags |= FLAG_ASYNCHRONOUS;
} else {
flags &= ~FLAG_ASYNCHRONOUS;
}
}

Messenger

/*
它引用了一个Handler对象,以便others能够向它发送消息.该类允许跨进程间基于Message的通信,通过创建一个Messenger指向一个进程中的Handler,然后在另一个进程中操作那个Messenger.
/
private final IMessenger mTarget;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
* @param target 接收发送的messages
创建一个新的Messenger指向给定的Handler.任何通过这个Messenger发送的Message对象会出现在Handler中,就像Handler中sendMessage(Message)被直接调用
*/

public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
/**
给Messenger的Handler发送一个Message,
*/

public void send(Message message) throws RemoteException {
mTarget.send(message);
}

/**
* 两个Messenger的mTarget.asBinder()指向相同内容即为相同
*/

public boolean equals(Object otherObj) {
if (otherObj == null) {
return false;
}
try {
return mTarget.asBinder().equals(((Messenger)otherObj)
.mTarget.asBinder());
} catch (ClassCastException e) {
}
return false;
}

MessageQueue

/**
Low-level的类持有通过Looper来分发的message列表。Messages不要直接添加到MessageQueue中,而是通过和Looper相关联的Handler对象

在当前线程可以通过Looper.myQueue()来检索MessageQueue.
*/

// 表明next()是否在pollOnce()中阻塞等待一个非0的超时时间
private boolean mBlocked;

// 下一个barrier token
// Barriers这样被声明:message的target是null,而且arg1域保存着token值
private int mNextBarrierToken;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
/**
当一个线程将要阻塞等待更多messages的时候回调此接口
*/

public static interface IdleHandler {
/**
当message queue运行完messages后等待更多信息时调用这个接口。返回true来保持你的idle handler激活状态,返回false移除激活状态。如果仍然有pending 的messages在queue中,但是他们都是在当前时间之后才会被调度分配的,这个就有可能会被调用
*/

boolean queueIdle();
}

/**
在messge queue中添加一个新的IdleHandler。如果从IdleHandler.queueIdle()中返回false会自动移除,或者使用removeIdleHandler来明确移除。

线程安全的
*/

public void addIdleHandler(IdleHandler handler) {
if (handler == null) {
throw new NullPointerException("Can't add a null IdleHandler");
}
synchronized (this) {
mIdleHandlers.add(handler);
}
}
/**
从queue中移除先前调用addIdleHandler添加的IdleHandler。
*
* @param handler The IdleHandler to be removed.
*/

public void removeIdleHandler(IdleHandler handler) {
synchronized (this) {
mIdleHandlers.remove(handler);
}
}

MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
然而对消息队列而言,在摘取消息时还要考虑更多技术细节。它关心的细节有:

1)如果消息队列里目前没有合适的消息可以摘取,那么不能让它所属的线程“傻转”,而应该使之阻塞;
2)队列里的消息应该按其“到时”的顺序进行排列,最先到时的消息会放在队头,也就是mMessages域所指向的消息,其后的消息依次排开;
3)阻塞的时间最好能精确一点儿,所以如果暂时没有合适的消息节点可摘时,要考虑链表首个消息节点将在什么时候到时,所以这个消息节点距离当前时刻的时间差,就是我们要阻塞的时长。
4)有时候外界希望队列能在即将进入阻塞状态之前做一些动作,这些动作可以称为idle动作,我们需要兼顾处理这些idle动作。一个典型的例子是外界希望队列在进入阻塞之前做一次垃圾收集。
Message next() {
int pendingIdleHandlerCount = -1; // 只有在第一次迭代中为-1
int nextPollTimeoutMillis = 0;
for (;;) {//死循环
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}

//我们可以假设mPtr != 0 因为loop显然还在运行。
//looper在loop退出之后不会调用这个方法
nativePollOnce(mPtr, nextPollTimeoutMillis);

synchronized (this) {
//尝试检索下一个message,找着就返回
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
//习惯将类变量赋值给局部变量再进行操作。
Message msg = mMessages;
if (msg != null && msg.target == null) {
// 如果从队列里拿到的msg是个“同步分割栏”,那么就寻找其后第一个“异步消息”
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
//下一个message还没有准备好,设置一个超时时间当它准备好之后唤醒
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
msg.markInUse();
return msg;
}
} else {
// 没有messges了
nextPollTimeoutMillis = -1;
}

//既然所有的messagess已经被处理完毕那就处理退出message
if (mQuitting) {
dispose();
return null;
}

// 如果第一时间空闲,获取到闲置的数量来运行
// 闲置的handles只有在queue是空的时候或者queue里第一个message(也许是个barrier)定于一段时间之后执行。
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// 没有闲置的handler。loop并等待更多的
mBlocked = true;
continue;
}

if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}

// 运行空闲的handlers.只在第一个迭代中,我们才会运行到这段代码块
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // 释放handler引用
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf("MessageQueue", "IdleHandler threw exception", t);
}

if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}

// 重新设置闲置handler数量为0,我们不再运行他们
pendingIdleHandlerCount = 0;

// 当调用一个闲置的handler时,一条新的message可能已经传递到,所以go back,立刻看一下那条消息
nextPollTimeoutMillis = 0;
}
}
这个函数里的for循环并不是起循环摘取消息节点的作用,而是为了连贯“当前时间点”和“处理下一条消息的时间点”。简单地说,当“定时机制”触发“摘取一条消息”的动作时,会判断事件队列的首条消息是否真的到时了,如果已经到时了,就直接返回这个msg,而如果尚未到时,则会努力计算一个较精确的等待时间(nextPollTimeoutMillis),计算完后,那个for循环会掉过头再次调用到nativePollOnce(mPtr, nextPollTimeoutMillis),进入阻塞状态,从而等待合适的时长。

next()里另一个要说的是那些Idle Handler,当消息队列中没有消息需要马上处理时,会判断用户是否设置了Idle Handler,如果有的话,则会尝试处理mIdleHandlers中所记录的所有Idle Handler,此时会逐个调用这些Idle Handler的queueIdle()成员函数。我们举一个例子,在ActivityThread中,在某种情况下会在消息队列中设置GcIdler,进行垃圾收集,其定义如下:

final class GcIdler implements MessageQueue.IdleHandler {
@Override
public final boolean queueIdle() {
doGcIfNeeded();
return false;
}
}
一旦队列里设置了这个Idle Handler,那么当队列中没有马上需处理的消息时,就会进行垃圾收集。


void quit(boolean safe) {
if (!mQuitAllowed) {
throw new RuntimeException("Main thread not allowed to quit.");
}

synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;

if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}

// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr);
}
}

private void removeAllMessagesLocked() {
Message p = mMessages;
while (p != null) {//将所有message清空
Message n = p.next;
p.recycle();
p = n;
}
mMessages = null;
}

private void removeAllFutureMessagesLocked() {
final long now = SystemClock.uptimeMillis();
Message p = mMessages;
if (p != null) {
if (p.when > now) {//队列中下一个要执行的都在当前时间之后才执行,直接移除。
removeAllMessagesLocked();
} else {//否则将执行时间大于当前时间之后的message都清空。
Message n;
for (;;) {
n = p.next;
if (n == null) {
return;
}
if (n.when > now) {
break;
}
p = n;
}
p.next = null;
do {
p = n;
n = p.next;
p.recycle();
} while (n != null);
}
}
}

/*所谓“同步分割栏”,可以被理解为一个特殊Message,它的target域为null。它不能通过sendMessageAtTime()等函数打入到消息队列里,而只能通过调用Looper的postSyncBarrier()来打入。

“同步分割栏”是起什么作用的呢?它就像一个卡子,卡在消息链表中的某个位置,当消息循环不断从消息链表中摘取消息并进行处理时,一旦遇到这种“同步分割栏”,那么即使在分割栏之后还有若干已经到时的普通Message,也不会摘取这些消息了。请注意,此时只是不会摘取“普通Message”了,如果队列中还设置有“异步Message”,那么还是会摘取已到时的“异步Message”的。

在Android的消息机制里,“普通Message”和“异步Message”也就是这点儿区别啦,也就是说,如果消息列表中根本没有设置“同步分割栏”的话,那么“普通Message”和“异步Message”的处理就没什么大的不同了。
*/

int enqueueSyncBarrier(long when) {
// 插入一个新的同步barrier token
// 我们不需要唤醒queue,因为barrier的目的是暂缓它
synchronized (this) {
final int token = mNextBarrierToken++;
final Message msg = Message.obtain();
msg.when = when;
msg.arg1 = token;

Message prev = null;
Message p = mMessages;
if (when != 0) {
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
}
if (prev != null) { // invariant: p == prev.next
msg.next = p;
prev.next = msg;
} else {
msg.next = p;
mMessages = msg;
}
return token;
}
}

void removeSyncBarrier(int token) {
// 从queue中移除同步barrier
// 如果queue不再需要用barrier停滞那么唤醒它。
synchronized (this) {
Message prev = null;
Message p = mMessages;
while (p != null && (p.target != null || p.arg1 != token)) {
prev = p;
p = p.next;
}
if (p == null) {
throw new IllegalStateException("The specified message queue synchronization "
+ " barrier token has not been posted or has already been removed.");
}
final boolean needWake;
if (prev != null) {
prev.next = p.next;
needWake = false;
} else {
mMessages = p.next;
needWake = mMessages == null || mMessages.target != null;
}
p.recycle();

// If the loop is quitting then it is already awake.
// We can assume mPtr != 0 when mQuitting is false.
if (needWake && !mQuitting) {
nativeWake(mPtr);
}
}
}

boolean enqueueMessage(Message msg, long when) {
if (msg.isInUse()) {
throw new AndroidRuntimeException(msg + " This message is already in use.");
}
if (msg.target == null) {
throw new AndroidRuntimeException("Message must have a target.");
}

synchronized (this) {
if (mQuitting) {
RuntimeException e = new RuntimeException(
msg.target + " sending message to a Handler on a dead thread");
return false;
}

msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// 插到第一个位置,如果是阻塞状态唤醒event queue
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// 插到queue中间。通常我们不必唤醒event queue除非有个barrier在queue的开始位置并且the message在queue里是最早的异步message
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}

// We can assume mPtr != 0 because mQuitting is false.
//
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}


boolean hasMessages(Handler h, int what, Object object) {
if (h == null) {
return false;
}

synchronized (this) {
Message p = mMessages;
while (p != null) {
if (p.target == h && p.what == what && (object == null || p.obj == object)) {
return true;
}
p = p.next;
}
return false;
}
}
void removeMessages(Handler h, int what, Object object) {
if (h == null) {
return;
}

synchronized (this) {
Message p = mMessages;

// Remove all messages at front.
while (p != null && p.target == h && p.what == what
&& (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
p.recycle();
p = n;
}

// Remove all messages after front.
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && n.what == what
&& (object == null || n.obj == object)) {
Message nn = n.next;
n.recycle();
p.next = nn;
continue;
}
}
p = n;
}
}
}

Looper

/**
这个类用来给一个线程运行一个message loop.线程默认没有和它们相关联的message loop。创建:在那个准备run the loop的线程中调用prepare,然后调用loop来处理进程message直到这个loop停止。

  • class LooperThread extends Thread {
  • public Handler mHandler;
    *
  • public void run() {
  • Looper.prepare();
    *
  • mHandler = new Handler() {
  • public void handleMessage(Message msg) {
  • // process incoming messages here
  • }
  • };
    *
  • Looper.loop();
  • }
  • }
    */
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
// sThreadLocal.get() 会返回null,除非我们已经调用了prepare()
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // 由 Looper.class管理

/**
初始化当前线程为一个looper,这个函数给你一个创建引用这个looper的handlers的机会
在真正开始loop之前,请确保调用
*/

public static void prepare() {
prepare(true);//默认是允许退出loop的
}

private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {//确保一个线程只有一个Looper
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}

private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}

/**
初始化当前线程为一个looper,并且让它做为一个应用的主looper. 应用的主looper是被Android环境创建,所以你永远不需要调用这个方法,
*/

public static void prepareMainLooper() {
prepare(false);//主looper是不允许退出的。
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}

/**
返回当前线程相关联的Looper对象,如果调用这个方法的线程没有关联一个Looper返回null
*/

public static Looper myLooper() {
return sThreadLocal.get();
}

/**
* 返回和当前线程相关联的MessageQueue.必须在运行Looper的线程调用,否则抛出空指针异常。
*/

public static MessageQueue myQueue() {
return myLooper().mQueue;
}

/**
返回应用的主looper,这个looper存在于应用的主线程
*/

public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
/**
在这个线程运行message queue。确定调用quit来终止loop
*/

public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;


// 确保这个线程的身份是本地进程的。并且跟踪身份的token值的真实值
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();

for (;;) {
Message msg = queue.next(); // 有可能阻塞
if (msg == null) {
// 没有message表明message queue正在退出
return;
}

// 这必须是个本地变量,防止一个UI事件设置logger.
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}

msg.target.dispatchMessage(msg);

if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}

// 确保这调度过程中,确保线程的身份没有被损坏
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}

msg.recycle();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
提交一个同步的barrier到Looper的message queue
message的处理像平常一样发生直到message queue遇到同步的barrier被提交.当遇到barrier,后来的queue中同步的messages会被暂缓(防止被执行),直到调用remveSyncBarrier释放barrier并在释放的时候指定能够识别同步barrier的token
age的执行直到释放barrier.异步的messages不受影响,继续按通常一样运行。

这次必须和调用removeSyncBarrier配对调用,而且使用相同的token来确保message queue回复正常运行。否则应用有可能会挂起
返回唯一的标示barrier的taken
* @hide
*/

public int postSyncBarrier() {
return mQueue.enqueueSyncBarrier(SystemClock.uptimeMillis());
}


/**
* @hide
*/

public void removeSyncBarrier(int token) {
mQueue.removeSyncBarrier(token);
}

简单来说首先需要Looper.prepare()来初始化当前线程中的Looper,并放置到Looper的静态ThreadLocal中,并初始化一个空的MessageQueue。然后新建一个Handler,在Handler的构造过程中,获取到该线程的Looper和Looper相对应的MessageQueue。然后调用Looper.loop()。这时候从Handler 通过MessageQueue的enqueueMessage提交message,并设置message的target为本Handler。然后在loop()中调用MessageQueue的next()获取到下一个该处理的message,调用message的target来执行最后操作,完毕之后msg被回收。

本代码基于sdk4.0

AsyncTask适合在UI线程中使用并且非常简单,这个类允许执行后台操作并且在UI线程发布结果,不必直接操作线程或者handler

AsyncTask被设计为一个Thread和Handler的帮助类,不用构成一个通用线程框架。AsyncTasks理论上是用来进行短时间的操作(最多几秒钟,生命周期一般要与activity或fragment绑定)。如果想使线程长时间执行操作,强烈建议使用java.util.concurrent包比如Executor,ThreadPoolExecutor和FutureTask.

一个异步任务被设想设计为在后台运行的线程而且结果会发布在UI线程。
三种类型 Params,Progress,Result,4个方法onPreExecute,doInBackground,onProgressUpdate
,onPostExecute

一个简单的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) 100));//发布进度
if (isCancelled()) break;//检查是否应该取消
}
return totalSize;
}

protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}

protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}

如何开始一个任务

new DownloadFilesTask().execute(url1, url2, url3);

AsyncTask通常的三个类型

  • Params参数类型
  • Progress在后台计算过程中发布的进度单位类型
  • Result后台计算的结果类型

以上三种类型通常都会被在异步任务中使用,通过设置为Void标记为不使用

private class MyTask extends AsyncTask<Void, Void, Void> { … }

四个步骤

  • onPreExecute()}在任务执行之前在UI线程调用,通常为任务做些准备比如显示一个进度条
  • doInBackground在onPreExecute之后立刻在后台线程中运行,参数会被传到这个方法 ,计算结果必须返回,而且最终会传递到最后一步 ,这一步可以使用publishProgress来发布一次或多次进度 ,这些进度值都会被发布到UI线程(在onProgressUpdate这步)
  • onProgressUpdate在pulishProgress之后在UI线程调用,这个方法用来当后台计算还在执行的时候在UI线程展示进度 ,比如可以改变进度条进度或者在一个text域展示日志
  • onPostExecute后台计算完成之后在UI线程调用,后台计算的结果会以参数形式传到这一步

取消一个任务

一个任务可以随时通过调用cancel(boolean)来取消,调用这个方法会是接下来的isCancelled返回true,调用这个方法之后onCancelled(Object)会替代onPostExecute(Object)在doInBackgroud(Object[])返回之后执行。为了确保一个任务能尽快被取消,应该在doInBackgroud(Object[])中周期的检查isCancelled()的值(比如说在循环中)

线程规则

为了使任务更好的工作,必须遵循以下规则

  • AsyncTask必须在UI线程加载,在JELLY_BEAN版本会被自动完成。
  • 任务实例必须在UI线程创建
  • execute必须在UI线程调用
  • 不要手动调用onPreExecute,onPostExecute,doInBackground,onProgressUpdate
  • 任务只能执行一次,否则会抛出一个异常

AsyncTask确保所有的回调都是同步的,在没有显示同步情况下是安全的

执行顺序

一开始AsyncTasks是在一个单独的后台线程中执行,在DONUT版本之后,变为在一个允许多个任务并行运行的线程池中。在HONEYCOMB版本之后,任务会在一个单独的线程中来避免并行执行引起的应用错误

如果确实想要并行的执行,调用executeOnExecutor(java.util.concurrent.Executor, Object[])和THREAD_POOL_EXECUTOR

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//获取cpu数量
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;

//提供的默认线程池
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

//最大支持128个长度
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
/*
在同一时间按序执行。对某一个进程来说这个串行时全局的。
*/

public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

SerialExecutor的实现如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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);
}
}
}
1
2
3
4
5
6
7
8
/*@hide 强制创建静态的handle */
public static void init() {
sHandler.getLooper();
}

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
private final WorkerRunnable<Params, Result> mWorker;
private final FutureTask<Result> mFuture;

其中sThreadFactory的实现

1
2
3
4
5
6
7
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());
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/*
构造函数,必须在UI线程调用
*/

public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);

Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
return postResult(doInBackground(mParams));
}
};

mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
try {
postResultIfNotInvoked(get());
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occured while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}

WorkerRunnable静态抽象内部类

1
2
3
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
1
2
3
4
5
6
/* 
这个方法依据平台的版本在一个单独后台线程或线程池中安排队列中的任务
*/

public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
1
2
3
4
5
6
7
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
1
2
3
4
5
6
7
8
9
private static class AsyncTaskResult<Data> {
final AsyncTask mTask;
final Data[] mData;

AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
1
2
3
4
5
protected abstract Result doInBackground(Params... params);
protected void onPreExecute() {
}
protected void onPostExecute(Result result) {
}
1
2
3
4
5
6
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}

私有静态final类
private static final InternalHandler sHandler = new InternalHandler();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private static class InternalHandler extends Handler {
@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;
}
}
}
1
2
3
4
5
6
7
8
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
1
2
3
4
5
6
/*
如果调用了cancel(boolean)这个方法,应该在doInBackground(Object[])中周期性的检查isCancelled()的返回值来尽早结束任务
*/

public final boolean isCancelled() {
return mCancelled.get();
}
1
2
3
4
5
6
7
8
/* 
在cancel(boolean)被调用和doInBackgroud(Object[])完成之后在UI线程执行
默认的实现只是调用了onCancelled()同时忽略了结果。如果自己实现这个方法不要调用super.onCancelled(result)
*/
@SuppressWarnings({"UnusedParameters"})
protected void onCancelled(Result result) {
onCancelled();
}
1
2
3
4
/*应用最好重写onCannelled(object)。这个方法默认是被onCancelled(object)方法调用
*/

protected void onCancelled() {
}
1
2
3
4
5
6
/*  
在publishProgress执行之后在UI线程运行,参数值是从publishProgress中穿过来的
*/

@SuppressWarnings({"UnusedDeclaration"})
protected void onProgressUpdate(Progress... values) {
}
1
2
3
4
5
6
7
8
9
/*
尝试取消任务,如果任务已经完成或已经取消,或因为某些其他的原因不能取消都会导致这次尝试失败。如果成功了而且任务当被调用cancel的时候还没有开始,那么这个任务将不再执行。如果任务已经开始,那么mayInterruptIfRunning这个参数决定在这次停掉任务的尝试中是否使执行任务的线程中断。
调用这个方法的结果将传递给在doInBackground(Object[])返回之后的UI线程中被调用的onCancelled(Object)。调用这个方法保证onPostExecute(Object)不被调用。
调用这个方法之后,应该在doInBackground(Object[])中周期性的检查isCancelled()的返回值来尽早结束任务
*/

public final boolean cancel(boolean mayInterruptIfRunning) {
mCancelled.set(true);
return mFuture.cancel(mayInterruptIfRunning);
}
1
2
3
4
5
6
7
8
/*当后台计算还在运行时在doInBackground中被调用来更新UI线程。每次调用这个方法都会触发UI线程的onProgressUpdate被执行
*/

protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
1
2
3
4
5
6
/*  
execute(Object...)的一个方便版本,参数是一个简单的Runnable对象,
*/

public static void execute(Runnable runnable) {
sDefaultExecutor.execute(runnable);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/*  
这个方法通常使用THREAD_POOL_EXECUTOR在AsyncTask管理的线程池中并行的运行多个任务,但是也可以使用自定义的Executor
注意:允许多个任务在一个线程池中并行通常不是你想要的,因为他们操作的顺序没有定义。比如如果这些线程用来修改通用的状态(比如由于按钮点击写一个文件),修改的顺序没有保证。
如果不仔细对待这个问题,在最新版本中极少情况下数据将会被一个按顺序的重写,导致晦涩数据丢失和稳定性问题。
所以这些修改最好串行来执行,如果不管平台的版本为保证这个任务是串行的,可以使用SERIAL_EXECUTOR作为参数
必须在UI线程执行
THREAD_POOL_EXECUTOR作为一个方便的全程的线程池对那些松耦合的任务是可用的
*/

public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
if (mStatus != Status.PENDING) {//所以只能运行一次呢。那把这个status判断去掉,就可以实现多次执行?
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;
}
1
2
3
4
5
6
7
/*  
在最需要的时间等待计算完成,然后检索结果
*/

public final Result get(long timeout, TimeUnit unit) throws InterruptedException,
ExecutionException, TimeoutException {

return mFuture.get(timeout, unit);
}
1
2
3
public final Result get() throws InterruptedException, ExecutionException {
return mFuture.get();
}

**综上,AsyncTask的流程:在构造函数里初始化一个可以返回结果的future,(future中处理和handle相关的操作)在调用execute时,调用默认的SerialExecutor(静态,该应用公用)在线程池中来线性执行添加的future。调用executeOnExecutor(Executor,Params)可以传入一个Executor来修改线程执行方式。

###之前实现方式

下面是基于sdk1.5 asyncTask的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
private static final int CORE_POOL_SIZE = 1;
private static final int MAXIMUM_POOL_SIZE = 10;
private static final int KEEP_ALIVE = 10;
private static final BlockingQueue<Runnable> sWorkQueue =
new LinkedBlockingQueue<Runnable>(MAXIMUM_POOL_SIZE);
private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);
public final AsyncTask<Params, Progress, Result> execute(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;
sExecutor.execute(mFuture);

return this;
}

以下是基于sdk2.2 asyncTask的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;
private static final int KEEP_ALIVE = 10;
private static final BlockingQueue<Runnable> sWorkQueue =
new LinkedBlockingQueue<Runnable>(10);
private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);

public final AsyncTask<Params, Progress, Result> execute(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;
sExecutor.execute(mFuture);

return this;
}

关于corePoolSize和maximumPoolSize,queue和是否新建线程的关系:

当一个新的任务通过execute(Runnable)提交,如果小于运行着的corePoolSize线程数量,会创建一个新的线程来处理请求,即使其他任务线程是闲置的。
如果大于corePoolSize但是小于运行的maximumPoolSize线程,并且queue满了,就会新建一个线程。

以上都是基于一个Executor来完成的。

所以一开始AsyncTasks是在一个单独的后台线程中执行,在DONUT版本之后,变为在一个允许多个任务并行运行的线程池中。在HONEYCOMB版本之后,任务会在一个单独的线程中。
**

IntentService

IntentService继承自Service,可以处理异步的请求(通过intent传递参数).客户端通过startService(intent)来发送请求,service开始之后在线程里按顺序处理每一个intent,当它运行完所有任务之后会自动停止。

如何使用:继承IntentService,实现onHandleIntent(Intent)这个方法,intentService会接受intents,启动一个工作线程,在合适的时候停止这个service。

所有的请求都在一个工作线程里边被处理,他们可以长时间运行而且不会阻塞应用的主线程,但是同时只能处理一个请求。

首先来看onCreate方法
onCreate里生成一个HandlerThread,并通过start()启动该线程,然后生成一个ServiceHandler

@Override
public void onCreate() {
    /* TODO:最好在这有一个处理部分wakelock(这个坑先留着)的选项,
    而且应该有一个静态的startService(context,intent)方法启动service同时切换wakelock */
    super.onCreate();
    HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
    thread.start();
    mServiceLooper = thread.getLooper();
    mServiceHandler = new ServiceHandler(mServiceLooper);
}

这是生成的线程中处理消息的Handler(私有final内部类)

private final class ServiceHandler extends Handler {
    public ServiceHandler(Looper looper) {
        super(looper);
    }

    @Override
    public void handleMessage(Message msg) {
        onHandleIntent((Intent)msg.obj);
        /*通过这里可以看到,当声明的线程里边相关联的MessageLooper里边message被处理完毕之后就会停掉整个service*/
        stopSelf(msg.arg1);
    }
}

onHandleIntent是个抽象方法需要被子类实现,来进行那些需要在非UI线程执行的代码

/**
这个方法是在工作线程中被调用,并且传递了相关的请求参数,同一时间只有一个intent被处理,
但是这个过程是在一个单独的工作线程中运行,所以,如果这些代码长时间运行的话,它会阻塞其他发送到这个intentservice中的请求,
当所有请求都被处理之后intentserice会停掉自己,所以不要手动调动stopSelf.
这个方法中的intent参数就是startService(intent)中的参数
*/
protected abstract void onHandleIntent(Intent intent);`

在onStart里边将intent和startId发送到MessageLooper里边处理,也就是在onHandleIntent中处理

@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;
}

/**设置为true,onStartCommand()会返回START_REDELIVER_INTENT,
然后如果进程在onHandleIntent()返回之前死掉了,进程会重新启动同时intent会被重新传入,
如果提交了多个intents,只有最近的那个可以保证重新传入
设置为false,onStartCommand()返回START_NOT_STICKY,如果进程死掉,intent也就陪葬了
*/
public void setIntentRedelivery(boolean enabled) {
    mRedelivery = enabled;
}

onStartCommand中返回值含义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/*
START_STICKY的兼容版本,不保证进程被杀掉之后onStartCommand会被再次调用
*/

public static final int START_STICKY_COMPATIBILITY = 0;

/**
如果服务进程被杀掉,当它启动后(在onStartCommand返回后)会处于started状态而不重新持有传入的intent,
之后系统会尝试重新生成service.因为它处于started状态,它会保证在生成新的service实例之后调用onstartCommand,
如果在此期间没有任何启动命令被传递到,它被调用的时候会被传入一个null的intent,所以得小心。
这种模式对那些任意时候明确开始或停止的有意义,比如执行背景音乐重复的service
*/


public static final int START_STICKY = 1;

/**
如果服务进程被杀掉,当它启动后(在onStartCommand返回后)没有新的start intents传递给它,
然后使service处于非started状态而且不会重启直到startService(intent)明确的被调用,
这个service不会调用参数为null的intent的onStartCommand方法,
因为如果没有pending intent传入的话,它不会重启。

这种模式对要做一些工作来作为开始的结果是有意义的,
但是当内存不足的时候有可能停止并且会在过后明确的开始他们来做更多的工作。
一个从service获取数据例子:可以schedule一个alarm每隔N分钟通过alarm启动它的servide来获取数据,
当它的onStartCommand从alarm调用,它会schedules一个新的N分钟之后响起的alarm,并且产生一个线程来做网络操作。
当检查的时候如果它的进程被杀掉,service不会重启直到alarm响起。
*/


public static final int START_NOT_STICKY = 2;

/**
如果服务进程被杀掉,当它启动后(在onStartCommand返回后)它会被有计划的重启,
而且最后传入的intent会在onStartComman中重新传入。
如果这个service的进程当他开始之后(在onStartCommand返回之后)被杀死,
然后它会scheduled一个重启并且最后传入的Intent会通过onStartCommand被重新传入.
这个Intent会依然保留scheduled重传直到service调用带有由onStartCommand提供的start ID作为参数的stopSelf。
service不会收到一个带有Intent值为null的onStartComman(Intent, int, int)
因为他只会因为它还没有结束处理发给它的所有Intents而重启(而且任何pending events都会在重新开始的时候传入)
*/


public static final int START_REDELIVER_INTENT = 3;

IntentService的onDestroy退出looper

@Override
public void onDestroy() {
    //Looper退出
    mServiceLooper.quit();
}

HandlerThread

在IntentService中的工作线程是通过HandlerThread实现,HanderThread是一个拥有looper的线程,这个looper可以用来创建Handler类,start()方法必须被调用。

public HandlerThread(String name) {
    super(name);
    //赋予默认的线程优先级
    mPriority = Process.THREAD_PRIORITY_DEFAULT;
}

/**
这个优先级必须是来自Process,不能是Thread
*/
public HandlerThread(String name, int priority) {
    super(name);
    mPriority = priority;
}

@Override
public void run() {
    mTid = Process.myTid();
    Looper.prepare();
    synchronized (this) {//做了同步处理
        mLooper = Looper.myLooper();
        //这个notifyAll会唤醒等待获取looper的方法(getLooper()中)
        notifyAll();
    }
    Process.setThreadPriority(mPriority);
    onLooperPrepared();
    Looper.loop();
    mTid = -1;
}

在run里边将该线程初始化为Looper,设置优先级,然后循环message队列

/**
回调方法:在looper loops之前的一些准备操作可以通过重写这个方法来完成
*/
protected void onLooperPrepared() {    
}

Handler退出Looper

/**
退出handler线程的looper
调用这个方法会中断handler thread的looper,使message queue里边的所有message都不再运行
在looper被停止之后,任何尝试提交给queue的messages都会失败
调用这个方法有时不安全,因为有些message在looper中断之前不会再被传递,
考虑使用quitSafely来代替以确保所有待执行的任务有序的执行
*/
public boolean quit() {
    Looper looper = getLooper();
    if (looper != null) {
        looper.quit();
        return true;
    }
    return false;
}`

/**
安全的退出handler线程的looper
当所有在messagequeue里边的messages都被执行之后handler线程的looper才会中断,
那些延迟执行messages的都不会再执行
*/
public boolean quitSafely() {
    Looper looper = getLooper();
    if (looper != null) {
        looper.quitSafely();
        return true;
    }
    return false;
}

/**
返回这个线程关联的looper
如果线程没有开始或因为某些原因isAlive()returns false,这个方法会返回null,
如果这个线程已经开始,这个方法会阻塞直到looper被初始化
*/
public Looper getLooper() {
    if (!isAlive()) {
        return null;
    }
    // 如果这个线程已经开始,这个方法会阻塞直到looper被初始化
    synchronized (this) {
        while (isAlive() && mLooper == null) {
            try {
                wait();
                } catch (InterruptedException e) {
            }
        }
    }
    return mLooper;
}

综上呢,IntentService继承制Service,内部通过HandlerThread来创建线程和在该线程中生成的Looper完成Handler的消息处理,处理完毕所有通过startService中传入的intent之后就会结束自己。可以通过重写IntentService的onStart方法来改变handler处理message的方式,比如延时。