大家好,又见面了,我是你们的朋友全栈君。
android异步开发
android异步开发,主要有
1.Thread+Handler进行异步处理
2.继承Thread类和实现Runnable接口
3.AsyncTask类
4.RxJava
5.AsyncQueryHandler
但是事实上AsyncTask是有缺点的。
syncTask is designed to be a helper class around Thread and Handler and does not constitute a generic threading framework. AsyncTasks should ideally be used for short operations (a few seconds at the most.) If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by the java.util.concurrent package such as Executor, ThreadPoolExecutor and FutureTask.
AsyncTask是一个帮助类,它非常适合一个后台短耗时操作(最多几秒)。如果你要使后台进程保持运行非常长的时间,强烈推荐你使用 Executor, ThreadPoolExecutor 和FutureTask。
所以下面我们就看看ThreadPoolExecutor 和FutureTask的使用方法.
ThreadPoolExecutor
我们直接查看android源码中ThreadPoolExecutor的使用情况:
grep -rni --include=*.java "ThreadPoolExecutor " ./packages/
./packages/inputmethods/LatinIME/java/src/com/android/inputmethod/dictionarypack/DictionaryService.java:113:
private ThreadPoolExecutor mExecutor;
./packages/inputmethods/LatinIME/java/src/com/android/inputmethod/dictionarypack/DictionaryService.java:124:
// Executors#newSingleThreadExecutor creates a ThreadPoolExecutor but it returns the
具体我们查看关键的源码:
packages/inputmethods/LatinIME/java/src/com/android/inputmethod/dictionarypack/DictionaryService.java
public final class DictionaryService extends Service {
/**
* An executor that serializes tasks given to it.
*/
private ThreadPoolExecutor mExecutor;
private static final int WORKER_THREAD_TIMEOUT_SECONDS = 15;
@Override
public void onCreate() {
mExecutor = new ThreadPoolExecutor(1 /* corePoolSize */, 1 /* maximumPoolSize */,
WORKER_THREAD_TIMEOUT_SECONDS /* keepAliveTime */,
TimeUnit.SECONDS /* unit for keepAliveTime */,
new LinkedBlockingQueue<Runnable>() /* workQueue */);
mExecutor.allowCoreThreadTimeOut(true);
}
@Override
public synchronized int onStartCommand(final Intent intent, final int flags,
final int startId) {
........................
mExecutor.submit(new Runnable() {
@Override
public void run() {
..........................
});
其实上面也就给出了ThreadPoolExecutor 的一个使用样例了。
我们仿照上面的例子,写一个Demo:
我们使用ThreadPoolExecutor 来实现一个后台的60秒的耗时操作,然后再通过handler更新UI界面。
public class MainActivity extends AppCompatActivity {
private final static String TAG = "MainActivity";
private final static int UPDEAT_UI =1;
private TextView textView;
private Button button_ThreadPoolExecutor;
private ThreadPoolExecutor mExecutor;
private static final int WORKER_THREAD_TIMEOUT_SECONDS = 15;
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch(msg.what){
case UPDEAT_UI:
//Toast.makeText(getApplication(),"on do long funtion",Toast.LENGTH_LONG).show();
textView.setText("UPDEAT_UI--ThreadPoolExecutor");
Log.i(TAG,"handler.handleMessage--UPDEAT_UI");
break;
default :
break;
}
}
};
private Runnable runnable = new Runnable() {
@Override
public void run() {
//on do long time function
try {
Thread.sleep(1000*60);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.i(TAG,"handler.sendEmptyMessage--UPDEAT_UI");
handler.sendEmptyMessage(UPDEAT_UI);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
private void init() {
mExecutor = new ThreadPoolExecutor(
1 /* corePoolSize */,
1 /* maximumPoolSize */,
WORKER_THREAD_TIMEOUT_SECONDS /* keepAliveTime */,
TimeUnit.SECONDS /* unit for keepAliveTime */,
new LinkedBlockingQueue<Runnable>() /* workQueue */);
mExecutor.allowCoreThreadTimeOut(true);
textView = (TextView) findViewById(R.id.textView);
button_ThreadPoolExecutor = (Button) findViewById(R.id.button_ThreadPoolExecutor);
button_ThreadPoolExecutor.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.i(TAG,"button_ThreadPoolExecutor---onClick");
//mExecutor.submit(runnable);
mExecutor.execute(runnable);
}
});
}
}
构造函数
ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
这个是ThreadPoolExecutor完整的构造器,其他的构造器其实也是在内部调用这个.
corePoolSize 核心线程数,线程池保留线程的数量,即使这些线程是空闲.除非设置了allowCoreThreadTimeOut
maximumPoolSize 线程池最大允许的线程数.
keepAliveTime 当当前的线程数大于核心线程数,那么这些多余的空闲的线程在被终止之前能等待新任务的时间.
unit keepAliveTime时间的单位
workQueue 这个是用来保留将要执行的工作队列.
threadFactory 用于创建新线程的工厂
handler 如果工作队列(workQueue)满了,那么这个handler是将会被执行.
Android中的线程池的分类
通过配置不同参数的ThreadPoolExecutor, 有4类常用的线程池, Executors类提供了4个工厂方法用于创建4种不同特性的线程池给开发者用.
FixedThreadPool
用法:
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(num);
fixedThreadPool.execute(runnable对象);
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
特点:只有核心线程数,并且没有超时机制,因此核心线程即使闲置时,也不会被回收,因此能更快的响应外界的请求.
CachedThreadPool
用法:
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
cachedThreadPool.execute(runnable对象);
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
特点:没有核心线程,非核心线程数量没有限制, 超时为60秒.
适用于执行大量耗时较少的任务,当线程闲置超过60秒时就会被系统回收掉,当所有线程都被系统回收后,它几乎不占用任何系统资源.
ScheduledThreadPool
用法:
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(int corePoolSize);
scheduledThreadPool.schedule(runnable对象, 2000, TimeUnit.MILLISECONDS);
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
特点:核心线程数是固定的,非核心线程数量没有限制, 没有超时机制.
主要用于执行定时任务和具有固定周期的重复任务.
SingleThreadExecutor
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
singleThreadExecutor.execute(runnable对象);
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
特点:只有一个核心线程,并没有超时机制.
意义在于统一所有的外界任务到一个线程中, 这使得在这些任务之间不需要处理线程同步的问题.
Android中的四种线程池的使用源码
我们在源码中搜索ExecutorService,会发现大把的使用样例。下面我们就简单的列举几个吧。
Executors.newSingleThreadExecutor
packages\apps\SnapdragonGallery\src\com\android\photos\drawables\AutoThumbnailDrawable.java
private static ExecutorService sThreadPool = Executors.newSingleThreadExecutor();
sThreadPool.execute(mLoadBitmap);
.........................................
private final Runnable mLoadBitmap = new Runnable() {
@Override
public void run() {
}
};
packages\apps\Contacts\src\com\android\contacts\vcard\VCardService.java
// Should be single thread, as we don't want to simultaneously handle import and export
// requests.
private final ExecutorService mExecutorService = Executors.newSingleThreadExecutor();
........................
Log.d(LOG_TAG, "Executor service status: shutdown: " + mExecutorService.isShutdown()
+ ", terminated: " + mExecutorService.isTerminated());
........................
/**
* Tries to call {@link ExecutorService#execute(Runnable)} toward a given processor.
* @return true when successful.
*/
private synchronized boolean tryExecute(ProcessorBase processor) {
try {
mExecutorService.execute(processor);
return true;
} catch (RejectedExecutionException e) {
Log.w(LOG_TAG, "Failed to excetute a job.", e);
return false;
}
}
........................
Log.i(LOG_TAG, "No unfinished job. Stop this service.");
mExecutorService.shutdown();
........................
if (mExecutorService.isShutdown()) {
Log.w(LOG_TAG, "MediaScanner update is requested after executor's being shut down. " +
"Ignoring the update request");
return;
}
........................
mExecutorService.shutdown();
Executors.newCachedThreadPool
packages\apps\Dialer\java\com\android\voicemail\impl\fetch\FetchVoicemailReceiver.java
private void fetchVoicemail(final Network network, final VoicemailStatus.Editor status) {
Executor executor = Executors.newCachedThreadPool();
executor.execute(
new Runnable() {
@Override
public void run() {
................................................
}
});
}
Executors.newFixedThreadPool
packages\apps\CMFileManager\src\com\cyanogenmod\filemanager\providers\SecureResourceProvider.java
private final ExecutorService mExecutorService = Executors.newFixedThreadPool(1);
...............................
mExecutorService.execute(new Runnable() {
@Override
public void run() {
....................
}
});
Executors.newScheduledThreadPool
packages\apps\Dialer\java\com\android\dialer\app\voicemail\VoicemailPlaybackPresenter.java
private static ScheduledExecutorService mScheduledExecutorService;
......................
private static synchronized ScheduledExecutorService getScheduledExecutorServiceInstance() {
if (mScheduledExecutorService == null) {
mScheduledExecutorService = Executors.newScheduledThreadPool(NUMBER_OF_THREADS_IN_POOL);
}
return mScheduledExecutorService;
}
...........................
/** Must be invoked when the parent activity is destroyed. */
public void onDestroy() {
// Clear references to avoid leaks from the singleton instance.
mActivity = null;
mContext = null;
if (mScheduledExecutorService != null) {
mScheduledExecutorService.shutdown();
mScheduledExecutorService = null;
}
}
代码最后调用跳转到这个runnable:
\packages\apps\Dialer\java\com\android\dialer\app\voicemail\VoicemailPlaybackLayout.java
/** Controls the animation of the playback slider. */
@ThreadSafe
private final class PositionUpdater implements Runnable {
/** Update rate for the slider, 30fps. */
private static final int SLIDER_UPDATE_PERIOD_MILLIS = 1000 / 30;
private final ScheduledExecutorService mExecutorService;
@GuardedBy("mLock")
private ScheduledFuture<?> mScheduledFuture;
.........................
mScheduledFuture = mExecutorService.scheduleAtFixedRate(
this, 0, SLIDER_UPDATE_PERIOD_MILLIS, TimeUnit.MILLISECONDS);
...........................
if (mScheduledFuture != null) {
mScheduledFuture.cancel(true);
mScheduledFuture = null;
}
参考资料
1.Class ThreadPoolExecutor
https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html
2.(十七)java多线程之ThreadPoolExecutor
https://segmentfault.com/a/1190000009111732
3.android中的线程池 ThreadPoolExecutor
https://www.jianshu.com/p/86eb8ea62141
4.ThreadPoolExecutor使用示例
https://cwind.iteye.com/blog/2286567
写在后面的话
为什么好久没有写博客,今天又开始写呢.
主要是最近看了一下一个Android面试一天一题,感觉这个作者android技术非常的棒,但是对技术还是这么热情.而对比自己,android技术的深度和广度都有欠缺,虽然平时开发没有什么问题,但是面试还是被别人diss.不一定别人就比我厉害,只是自己还是对一些平时有疑问的技术没有更深入的进一步了解.
就比如这个ThreadPoolExecutor 和FutureTask,其实早在几年前就想了解一下,但是就是没有进一步的去实践,那后面就再进一步把以前自己想做的事再做一次吧,去完成自己以前留下的小尾巴吧.
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/158706.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...