├── .gitignore
├── LICENSE.txt
├── README.md
├── jars
└── lite-async-1.0.0.jar
├── library
├── AndroidManifest.xml
├── project.properties
└── src
│ └── com
│ └── litesuits
│ └── android
│ └── async
│ ├── ArrayDequeCompat.java
│ ├── ArraysCompat.java
│ ├── AsyncTask.java
│ ├── CachedTask.java
│ ├── Log.java
│ ├── SafeTask.java
│ ├── SimpleCachedTask.java
│ ├── SimpleSafeTask.java
│ ├── SimpleTask.java
│ └── TaskExecutor.java
└── sample
├── AndroidManifest.xml
├── project.properties
├── res
├── drawable-xxhdpi
│ └── ic_launcher.png
├── drawable
│ ├── ic_launcher.png
│ └── selector_button.xml
├── layout
│ └── act_list_btn.xml
├── values-zh
│ └── strings.xml
└── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
└── src
└── com
└── litesuits
└── android
└── samples
├── BaseActivity.java
└── LiteAsyncSamplesActivity.java
/.gitignore:
--------------------------------------------------------------------------------
1 | # built application files
2 | *.apk
3 | *.ap_
4 |
5 | # files for the dex VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # generated files
12 | bin/
13 | gen/
14 | out/
15 |
16 | # Local configuration file (sdk path, etc)
17 | *.properties
18 | proguard-project.txt
19 |
20 | # Eclipse project files
21 | .classpath
22 | .project
23 | .settings
24 |
25 | # Proguard folder generated by Eclipse
26 | proguard/
27 |
28 | # Intellij project files
29 | *.iml
30 | *.ipr
31 | *.iws
32 | .idea/
33 |
34 | .DS_Store
35 |
36 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | android-lite-async
2 | ==================
3 |
4 | An ameliorative, enhanced AsyncTask for Android. LiteAsync provides SimpleTask, SafeTask, CachedTask, etc, for rapid development. More convenient is, it has a TaskExecutor which can executes ordered, cyclicbarrier, delayed and timer Task.
5 |
6 | #同学们在日常开发中有没有遇到以下场景:
7 | 1. 两个原子任务,任务2需要等待任务1完成了才能进行。
8 | 2. 任务3需要等任务1和任务2都完成了才能进行,但是1和2可以并发以节省时间。看起来要写很多代码来调度任务。
9 | 3. 服务器接口压力过大,要被你的调用频度调戏到down机啦!
10 | 4. 系统的异步任务类AsyncTask要用的泛型太多太重啦,并且只能在主线程使用,不爽!
11 | 5. 要么大量并发使手机cpu吃紧卡到爆,要么不能真正(Android系统自带AsyncTask)并发执行。不爽!
12 |
13 | OK,如果你都遇到过,恭喜你,说明你的应用对开发者要求还是挺碉的。
14 | 那么是不是需要很多的代码才能完成这种和谐并发和任务调度呢?nooooo!有了Crossbow,我们只要一行代码。
15 | 比方说场景2, Task3要等待Task1,Task2执行完才能执行,我们使用LiteAsync可以这样做:
16 |
17 | ```java
18 | TaskExecutor.newCyclicBarrierExecutor().put(task1).put(task2).start(task3);
19 | ```
20 |
21 | 这么一行代码,低调,内敛,而又充满能量,再多的任务可以执行,Task1,Task2并发执行,且随时可取消执行,结束(或取消)时会自动调度Task3执行。
22 |
23 | #关于android并发
24 | 来谈谈并发,研究过Android系统源码的同学会发现:AsyncTask在android2.3的时候线程池是一个核心数为5线程,队列可容纳10线程,最大执行128个任务,这存在一个问题,当你真的有138个并发时,即使手机没被你撑爆,那么超出这个指标应用绝对crash掉。
25 | 后来升级到4.0,为了避免并发带来的一些列问题,AsyncTask竟然成为序列执行器了,也就是你即使你同时execute N个AsyncTask,它也是挨个排队执行的。
26 | 这一点请同学们一定注意,AsyncTask在4.0以后,是异步的没错,但不是并发的。
27 |
28 | 言归正传,我们来看看LiteAsync能做些什么吧:
29 |
30 | #异步任务AsyncTask
31 | 1. Ameliorative AsyncTask:真正可并发,均衡手机能力与开销,针对短时间大量并发有调控策略,可在子线程执行。
32 | 2. SimpleTask:具备Ameliorative AsyncTask所有特性,简化了使用方法,仅设置一个泛型(结果类)即可。
33 | 3. SafeTask:具备Ameliorative AsyncTask所有特性,但是各个环节是安全的,能捕获任何异常,并传递给开发者。
34 | 4. CachedTask:具备Ameliorative AsyncTask所有特性,增加了对结果的缓存,可设置一个超时时间,只有在超时后才去异步执行,否则取缓存结果返回。
35 |
36 | #任务调度器TaskExecutor
37 | 1. 顺序执行器,使一系列异步任务按序执行,非并发
38 | 2. 关卡执行器,使一系列异步任务并发执行,最后会调度执行一个终点任务
39 | 3. 延迟执行器,使一个异步任务延迟开发者指定的时间后执行
40 | 4. 心跳执行器,是一个异步任务按执行的间隔持续执行
41 |
42 | 恩,全部介绍完了,它很简单,却是最贴心的异步&并发爱心天使。
43 | 我在github工程里各自都谢了demo和案例,约10来个,足够你起步啦,现在就用起来吧骚年!
44 |
45 |
46 | 关于作者(About Author)
47 | -----
48 | 我的博客 :[http://vmatianyu.cn](http://vmatianyu.cn/)
49 |
50 | 我的开源站点 :[http://litesuits.com](http://litesuits.com/)
51 |
52 | 点击加入QQ群:
53 | [42960650](http://jq.qq.com/?_wv=1027&k=cxjcDa)
54 |
55 | [47357508](http://jq.qq.com/?_wv=1027&k=Z7l0Av)
56 |
57 | 我的论坛帖子
58 | -----
59 | [LiteHttp:极简且智能的 android HTTP 框架库 (专注于网络)](http://www.eoeandroid.com/thread-326584-1-1.html)
60 |
61 | [LiteOrm:极简且智能的 android ORM 框架库 (专注数据库)](http://www.eoeandroid.com/thread-538203-1-1.html)
62 |
63 | [LiteAsync:强势的 android 异步 框架库 (专注异步与并发)](http://www.eoeandroid.com/thread-538212-1-1.html)
64 |
65 | [LiteCommon:丰富通用的android工具类库(专注于基础组件)](http://www.eoeandroid.com/thread-557246-1-1.html)
66 |
67 | 我的博客帖子
68 | -----
69 | [关于java的线程并发和锁的总结](http://www.vmatianyu.cn/summary-of-the-java-thread-concurrency-and-locking.html)
70 |
71 | [android开发技术经验总结60条](http://www.vmatianyu.cn/summarization-of-technical-experience.html)
72 |
73 | [聚划算android客户端1期教训总结](http://www.vmatianyu.cn/poly-effective-client-1-issues-lessons.html)
74 |
75 | [移动互联网产品设计小结](http://www.vmatianyu.cn/summary-of-mobile-internet-product-design.html)
76 |
--------------------------------------------------------------------------------
/jars/lite-async-1.0.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/litesuits/android-lite-async/203736b3013e6f9cea1c150d2d03351cec1a5adf/jars/lite-async-1.0.0.jar
--------------------------------------------------------------------------------
/library/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/library/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-19
15 | android.library=true
16 |
--------------------------------------------------------------------------------
/library/src/com/litesuits/android/async/ArrayDequeCompat.java:
--------------------------------------------------------------------------------
1 | package com.litesuits.android.async;
2 |
3 | import java.util.ArrayDeque;
4 |
5 | /**
6 | * 精简版{@link ArrayDeque}实现。
7 | * 兼容旧版本Android的{@link ArrayDeque},高性能Stack和Queue。
8 | * @author MaTianyu
9 | * 2014-1-31上午12:37:26
10 | */
11 | public class ArrayDequeCompat {
12 | private transient E[] elements;
13 | private transient int head;
14 | private transient int tail;
15 | private static final int MIN_INITIAL_CAPACITY = 8;
16 |
17 | // ****** Array allocation and resizing utilities ******
18 | private void allocateElements(int numElements) {
19 | int initialCapacity = MIN_INITIAL_CAPACITY;
20 | // Find the best power of two to hold elements.
21 | // Tests "<=" because arrays aren't kept full.
22 | if (numElements >= initialCapacity) {
23 | initialCapacity = numElements;
24 | initialCapacity |= (initialCapacity >>> 1);
25 | initialCapacity |= (initialCapacity >>> 2);
26 | initialCapacity |= (initialCapacity >>> 4);
27 | initialCapacity |= (initialCapacity >>> 8);
28 | initialCapacity |= (initialCapacity >>> 16);
29 | initialCapacity++;
30 |
31 | if (initialCapacity < 0) // Too many elements, must back off
32 | initialCapacity >>>= 1;// Good luck allocating 2 ^ 30 elements
33 | }
34 | elements = (E[]) new Object[initialCapacity];
35 | }
36 |
37 | /**
38 | * Double the capacity of this deque. Call only when full, i.e.,
39 | * when head and tail have wrapped around to become equal.
40 | */
41 | private void doubleCapacity() {
42 | assert head == tail;
43 | int p = head;
44 | int n = elements.length;
45 | int r = n - p; // number of elements to the right of p
46 | int newCapacity = n << 1;
47 | if (newCapacity < 0) throw new IllegalStateException("Sorry, deque too big");
48 | Object[] a = new Object[newCapacity];
49 | System.arraycopy(elements, p, a, 0, r);
50 | System.arraycopy(elements, 0, a, r, p);
51 | elements = (E[]) a;
52 | head = 0;
53 | tail = n;
54 | }
55 |
56 | public ArrayDequeCompat() {
57 | elements = (E[]) new Object[16];
58 | }
59 |
60 | public ArrayDequeCompat(int numElements) {
61 | allocateElements(numElements);
62 | }
63 |
64 | public void addFirst(E e) {
65 | if (e == null) throw new NullPointerException("e == null");
66 | elements[head = (head - 1) & (elements.length - 1)] = e;
67 | if (head == tail) doubleCapacity();
68 | }
69 |
70 | public void addLast(E e) {
71 | if (e == null) throw new NullPointerException("e == null");
72 | elements[tail] = e;
73 | if ((tail = (tail + 1) & (elements.length - 1)) == head) doubleCapacity();
74 | }
75 |
76 | public boolean offer(E e) {
77 | return offerLast(e);
78 | }
79 |
80 | public boolean offerFirst(E e) {
81 | addFirst(e);
82 | return true;
83 | }
84 |
85 | public boolean offerLast(E e) {
86 | addLast(e);
87 | return true;
88 | }
89 |
90 | public E poll() {
91 | return pollFirst();
92 | }
93 |
94 | public E pollFirst() {
95 | int h = head;
96 | @SuppressWarnings("unchecked")
97 | E result = (E) elements[h];
98 | // Element is null if deque empty
99 | if (result == null) return null;
100 | elements[h] = null; // Must null out slot
101 | head = (h + 1) & (elements.length - 1);
102 | return result;
103 | }
104 |
105 | public E pollLast() {
106 | int t = (tail - 1) & (elements.length - 1);
107 | @SuppressWarnings("unchecked")
108 | E result = (E) elements[t];
109 | if (result == null) return null;
110 | elements[t] = null;
111 | tail = t;
112 | return result;
113 | }
114 |
115 | /**
116 | * Returns the number of elements in this deque.
117 | *
118 | * @return the number of elements in this deque
119 | */
120 | public int size() {
121 | return (tail - head) & (elements.length - 1);
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/library/src/com/litesuits/android/async/ArraysCompat.java:
--------------------------------------------------------------------------------
1 | package com.litesuits.android.async;
2 |
3 | import java.lang.reflect.Array;
4 | import java.util.Arrays;
5 |
6 | /**
7 | * 兼容旧版本Android的 {@link Arrays}。
8 | *
9 | * @author MaTianyu
10 | * 2014-1-31下午6:12:32
11 | */
12 | public class ArraysCompat {
13 |
14 | @SuppressWarnings("unchecked")
15 | public static T[] copyOf(T[] original, int newLength) {
16 | return (T[]) copyOf(original, newLength, original.getClass());
17 | }
18 |
19 | public static T[] copyOf(U[] original, int newLength, Class extends T[]> newType) {
20 | @SuppressWarnings("unchecked")
21 | T[] copy = ((Object) newType == (Object) Object[].class) ? (T[]) new Object[newLength] : (T[]) Array
22 | .newInstance(newType.getComponentType(), newLength);
23 | System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
24 | return copy;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/library/src/com/litesuits/android/async/AsyncTask.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 litesuits.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.litesuits.android.async;
17 |
18 | import android.os.Handler;
19 | import android.os.Looper;
20 | import android.os.Message;
21 | import android.os.Process;
22 | import android.widget.ListView;
23 |
24 | import java.util.Stack;
25 | import java.util.concurrent.*;
26 | import java.util.concurrent.atomic.AtomicBoolean;
27 | import java.util.concurrent.atomic.AtomicInteger;
28 |
29 | /**
30 | * see {@link android.os.AsyncTask}
31 | *
max(base*16): 64 80 96 112 176 304 560
121 | */
122 | private static int serialMaxCount;
123 | private int cpuCount = CPU_COUNT;
124 |
125 | private void reSettings(int cpuCount) {
126 | this.cpuCount = cpuCount;
127 | serialOneTime = cpuCount;
128 | serialMaxCount = (cpuCount + 3) * 16;
129 | }
130 |
131 | public SmartSerialExecutor() {
132 | reSettings(CPU_COUNT);
133 | }
134 |
135 | @Override
136 | public synchronized void execute(final Runnable command) {
137 | Runnable r = new Runnable() {
138 | @Override
139 | public void run() {
140 | command.run();
141 | next();
142 | }
143 | };
144 | if (mCachedSerialExecutor.getActiveCount() < serialOneTime) {
145 | // 小于单次并发量直接运行
146 | mCachedSerialExecutor.execute(r);
147 | } else {
148 | // 如果大于并发上限,那么移除最老的任务
149 | if (mQueue.size() >= serialMaxCount) {
150 | mQueue.pollFirst();
151 | }
152 | // 新任务放在队尾
153 | mQueue.offerLast(r);
154 |
155 | // 动态获取目前cpu处理器数目,并调整设置。
156 | // int proCount = Runtime.getRuntime().availableProcessors();
157 | // if (proCount != cpuCount) {
158 | // cpuCount = proCount;
159 | // reSettings(proCount);
160 | // }
161 | }
162 |
163 | }
164 |
165 | public synchronized void next() {
166 | Runnable mActive;
167 | switch (mStrategy) {
168 | case LIFO :
169 | mActive = mQueue.pollLast();
170 | break;
171 | case FIFO :
172 | mActive = mQueue.pollFirst();
173 | break;
174 | default :
175 | mActive = mQueue.pollLast();
176 | break;
177 | }
178 | if (mActive != null) mCachedSerialExecutor.execute(mActive);
179 | }
180 | }
181 |
182 | /*********************************** 其他 *******************************/
183 |
184 | private static final int MESSAGE_POST_RESULT = 0x1;
185 | private static final int MESSAGE_POST_PROGRESS = 0x2;
186 |
187 | protected static final InternalHandler sHandler;
188 | static {
189 | if (Looper.myLooper() != Looper.getMainLooper()) {
190 | sHandler = new InternalHandler(Looper.getMainLooper());
191 | } else {
192 | sHandler = new InternalHandler();
193 | }
194 | }
195 |
196 | private static volatile Executor sDefaultExecutor = mCachedSerialExecutor;
197 | private final WorkerRunnable mWorker;
198 | private final FutureTask mFuture;
199 |
200 | private volatile Status mStatus = Status.PENDING;
201 |
202 | private final AtomicBoolean mCancelled = new AtomicBoolean();
203 | private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
204 | private FinishedListener finishedListener;
205 |
206 | /**
207 | * Indicates the current status of the task. Each status will be set only once
208 | * during the lifetime of a task.
209 | */
210 | public enum Status {
211 | /**
212 | * Indicates that the task has not been executed yet.
213 | */
214 | PENDING,
215 | /**
216 | * Indicates that the task is running.
217 | */
218 | RUNNING,
219 | /**
220 | * Indicates that {@link AsyncTask#onPostExecute} has finished.
221 | */
222 | FINISHED,
223 | }
224 |
225 | /** @hide Used to force static handler to be created. */
226 | public static void init() {
227 | sHandler.getLooper();
228 | }
229 |
230 | /** @hide */
231 | public static void setDefaultExecutor(Executor exec) {
232 | sDefaultExecutor = exec;
233 | }
234 |
235 | /**
236 | * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
237 | */
238 | public AsyncTask() {
239 | mWorker = new WorkerRunnable() {
240 | public Result call() throws Exception {
241 | mTaskInvoked.set(true);
242 | Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
243 | return postResult(doInBackground(mParams));
244 | }
245 | };
246 |
247 | mFuture = new FutureTask(mWorker) {
248 | @Override
249 | protected void done() {
250 | try {
251 | postResultIfNotInvoked(get());
252 | } catch (InterruptedException e) {
253 | android.util.Log.w(LOG_TAG, e);
254 | } catch (ExecutionException e) {
255 | throw new RuntimeException("An error occured while executing doInBackground()", e.getCause());
256 | } catch (CancellationException e) {
257 | postResultIfNotInvoked(null);
258 | }
259 | }
260 | };
261 | }
262 |
263 | private void postResultIfNotInvoked(Result result) {
264 | final boolean wasTaskInvoked = mTaskInvoked.get();
265 | if (!wasTaskInvoked) {
266 | postResult(result);
267 | }
268 | }
269 |
270 | private Result postResult(Result result) {
271 | @SuppressWarnings("unchecked")
272 | Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult(this, result));
273 | message.sendToTarget();
274 | return result;
275 | }
276 |
277 | /**
278 | * Returns the current status of this task.
279 | *
280 | * @return The current status.
281 | */
282 | public final Status getStatus() {
283 | return mStatus;
284 | }
285 |
286 | /**
287 | * Override this method to perform a computation on a background thread. The
288 | * specified parameters are the parameters passed to {@link #execute}
289 | * by the caller of this task.
290 | *
291 | * This method can call {@link #publishProgress} to publish updates
292 | * on the UI thread.
293 | *
294 | * @param params The parameters of the task.
295 | *
296 | * @return A result, defined by the subclass of this task.
297 | *
298 | * @see #onPreExecute()
299 | * @see #onPostExecute
300 | * @see #publishProgress
301 | */
302 | protected abstract Result doInBackground(Params... params);
303 |
304 | /**
305 | * Runs on the UI thread before {@link #doInBackground}.
306 | *
307 | * @see #onPostExecute
308 | * @see #doInBackground
309 | */
310 | protected void onPreExecute() {}
311 |
312 | /**
313 | *
Runs on the UI thread after {@link #doInBackground}. The
314 | * specified result is the value returned by {@link #doInBackground}.
315 | *
316 | *
This method won't be invoked if the task was cancelled.
317 | *
318 | * @param result The result of the operation computed by {@link #doInBackground}.
319 | *
320 | * @see #onPreExecute
321 | * @see #doInBackground
322 | * @see #onCancelled(Object)
323 | */
324 | @SuppressWarnings({"UnusedDeclaration"})
325 | protected void onPostExecute(Result result) {}
326 |
327 | /**
328 | * Runs on the UI thread after {@link #publishProgress} is invoked.
329 | * The specified values are the values passed to {@link #publishProgress}.
330 | *
331 | * @param values The values indicating progress.
332 | *
333 | * @see #publishProgress
334 | * @see #doInBackground
335 | */
336 | @SuppressWarnings({"UnusedDeclaration"})
337 | protected void onProgressUpdate(Progress... values) {}
338 |
339 | /**
340 | *
Runs on the UI thread after {@link #cancel(boolean)} is invoked and
341 | * {@link #doInBackground(Object[])} has finished.
342 | *
343 | *
The default implementation simply invokes {@link #onCancelled()} and
344 | * ignores the result. If you write your own implementation, do not call
345 | * super.onCancelled(result).
Applications should preferably override {@link #onCancelled(Object)}.
360 | * This method is invoked by the default implementation of
361 | * {@link #onCancelled(Object)}.
362 | *
363 | *
Runs on the UI thread after {@link #cancel(boolean)} is invoked and
364 | * {@link #doInBackground(Object[])} has finished.
365 | *
366 | * @see #onCancelled(Object)
367 | * @see #cancel(boolean)
368 | * @see #isCancelled()
369 | */
370 | protected void onCancelled() {}
371 |
372 | /**
373 | * Returns true if this task was cancelled before it completed
374 | * normally. If you are calling {@link #cancel(boolean)} on the task,
375 | * the value returned by this method should be checked periodically from
376 | * {@link #doInBackground(Object[])} to end the task as soon as possible.
377 | *
378 | * @return true if task was cancelled before it completed
379 | *
380 | * @see #cancel(boolean)
381 | */
382 | public final boolean isCancelled() {
383 | return mCancelled.get();
384 | }
385 |
386 | /**
387 | *
Attempts to cancel execution of this task. This attempt will
388 | * fail if the task has already completed, already been cancelled,
389 | * or could not be cancelled for some other reason. If successful,
390 | * and this task has not started when cancel is called,
391 | * this task should never run. If the task has already started,
392 | * then the mayInterruptIfRunning parameter determines
393 | * whether the thread executing this task should be interrupted in
394 | * an attempt to stop the task.
395 | *
396 | *
Calling this method will result in {@link #onCancelled(Object)} being
397 | * invoked on the UI thread after {@link #doInBackground(Object[])}
398 | * returns. Calling this method guarantees that {@link #onPostExecute(Object)}
399 | * is never invoked. After invoking this method, you should check the
400 | * value returned by {@link #isCancelled()} periodically from
401 | * {@link #doInBackground(Object[])} to finish the task as early as
402 | * possible.
403 | *
404 | * @param mayInterruptIfRunning true if the thread executing this
405 | * task should be interrupted; otherwise, in-progress tasks are allowed
406 | * to complete.
407 | *
408 | * @return false if the task could not be cancelled,
409 | * typically because it has already completed normally;
410 | * true otherwise
411 | *
412 | * @see #isCancelled()
413 | * @see #onCancelled(Object)
414 | */
415 | public final boolean cancel(boolean mayInterruptIfRunning) {
416 | mCancelled.set(true);
417 | return mFuture.cancel(mayInterruptIfRunning);
418 | }
419 |
420 | /**
421 | * Waits if necessary for the computation to complete, and then
422 | * retrieves its result.
423 | *
424 | * @return The computed result.
425 | *
426 | * @throws CancellationException If the computation was cancelled.
427 | * @throws ExecutionException If the computation threw an exception.
428 | * @throws InterruptedException If the current thread was interrupted
429 | * while waiting.
430 | */
431 | public final Result get() throws InterruptedException, ExecutionException {
432 | return mFuture.get();
433 | }
434 |
435 | /**
436 | * Waits if necessary for at most the given time for the computation
437 | * to complete, and then retrieves its result.
438 | *
439 | * @param timeout Time to wait before cancelling the operation.
440 | * @param unit The time unit for the timeout.
441 | *
442 | * @return The computed result.
443 | *
444 | * @throws CancellationException If the computation was cancelled.
445 | * @throws ExecutionException If the computation threw an exception.
446 | * @throws InterruptedException If the current thread was interrupted
447 | * while waiting.
448 | * @throws TimeoutException If the wait timed out.
449 | */
450 | public final Result get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException,
451 | TimeoutException {
452 | return mFuture.get(timeout, unit);
453 | }
454 |
455 | /**
456 | * Executes the task with the specified parameters. The task returns
457 | * itself (this) so that the caller can keep a reference to it.
458 | *
459 | *
Execute a task immediately.
460 | *
461 | *
This method must be invoked on the UI thread.
462 | *
463 | *
用于重要、紧急、单独的异步任务,该Task立即得到执行。
464 | *
加载类似瀑布流时产生的大量并发(一定程度允许任务被剔除队列)时请用{@link AsyncTask#executeAllowingLoss(Object...)}
465 | * @param params The parameters of the task.
466 | *
467 | * @return This instance of AsyncTask.
468 | *
469 | * @throws IllegalStateException If {@link #getStatus()} returns either
470 | * {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
471 | *
472 | * @see #executeOnExecutor(java.util.concurrent.Executor, Object[])
473 | * @see #execute(Runnable)
474 | */
475 | public final AsyncTask execute(final Params... params) {
476 | return executeOnExecutor(sDefaultExecutor, params);
477 | }
478 |
479 | /**
480 | *
This method execute task wisely when a large number of task will be submitted.
482 | * @param params
483 | * @return
484 | */
485 | public final AsyncTask executeAllowingLoss(Params... params) {
486 | return executeOnExecutor(mLruSerialExecutor, params);
487 | }
488 |
489 | /**
490 | * Executes the task with the specified parameters. The task returns
491 | * itself (this) so that the caller can keep a reference to it.
492 | *
493 | *
This method is typically used with {@link #mCachedSerialExecutor} to
494 | * allow multiple tasks to run in parallel on a pool of threads managed by
495 | * AsyncTask, however you can also use your own {@link Executor} for custom
496 | * behavior.
497 | *
498 | *
This method must be invoked on the UI thread.
499 | *
500 | * @param exec The executor to use. {@link #mCachedSerialExecutor} is available as a
501 | * convenient process-wide thread pool for tasks that are loosely coupled.
502 | * @param params The parameters of the task.
503 | *
504 | * @return This instance of AsyncTask.
505 | *
506 | * @throws IllegalStateException If {@link #getStatus()} returns either
507 | * {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
508 | *
509 | * @see #execute(Object[])
510 | */
511 | public final AsyncTask executeOnExecutor(Executor exec, Params... params) {
512 | if (mStatus != Status.PENDING) {
513 | switch (mStatus) {
514 | case RUNNING :
515 | throw new IllegalStateException("Cannot execute task:" + " the task is already running.");
516 | case FINISHED :
517 | throw new IllegalStateException("Cannot execute task:" + " the task has already been executed "
518 | + "(a task can be executed only once)");
519 | }
520 | }
521 |
522 | mStatus = Status.RUNNING;
523 |
524 | onPreExecute();
525 |
526 | mWorker.mParams = params;
527 | exec.execute(mFuture);
528 |
529 | return this;
530 | }
531 |
532 | /**
533 | * Convenience version of {@link #execute(Object...)} for use with
534 | * a simple Runnable object. See {@link #execute(Object[])} for more
535 | * information on the order of execution.
536 | *
This method execute runnable wisely when a large number of task will be submitted.
548 | *
任务数限制情况见{@link SmartSerialExecutor}
549 | * immediate execution for important or urgent task.
550 | * @param runnable
551 | */
552 | public static void executeAllowingLoss(Runnable runnable) {
553 | mLruSerialExecutor.execute(runnable);
554 | }
555 |
556 | /**
557 | * This method can be invoked from {@link #doInBackground} to
558 | * publish updates on the UI thread while the background computation is
559 | * still running. Each call to this method will trigger the execution of
560 | * {@link #onProgressUpdate} on the UI thread.
561 | *
562 | * {@link #onProgressUpdate} will note be called if the task has been
563 | * canceled.
564 | *
565 | * @param values The progress values to update the UI with.
566 | *
567 | * @see #onProgressUpdate
568 | * @see #doInBackground
569 | */
570 | protected final void publishProgress(Progress... values) {
571 | if (!isCancelled()) {
572 | sHandler.obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult