大家众所周知,IntentService内置的handler只有一个线程,而AsyncTask又只适合时间至多几秒的操作,所以我们关注使用ExecutorService建立并行执行。为了确保Service一直保持活跃状态,需要调用Service.startForeground()方法。由于Service.startForeground()和Service.stopForeground()并不会叠加,所以还需要维护一个内部计数器,用来记录活跃的任务。一旦计数器为0则调用Service.stopForeground();
在这个例子中,主要介绍怎么利用Service执行并行的任务,并不是主要讲解多媒体格式文件转码的操作,所以转码操作都省略,主要实现并行执行。
public class MediaTranscoder extends Service { private static final int NOTIFICATION_ID = 1001;//定义通知的标识ID public static final String ACTION_TRANSCODE_MEDIA = "com.liyaunjinglyj.services.TRANSCODE_MEDIA"; public static final String EXTRA_OUTPUT_TYPE = "outputType";//转码的类型 private ExecutorService mExecutorService;//定义线程池 private int mRunningJobs = 0;//任务计数器 private final Object mLock = new Object();//锁 private boolean mIsForeground = false;//标志是否需要结束Service @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); this.mExecutorService = Executors.newCachedThreadPool();
//缓存型池子,先查看池中有没有以前建立的线程,如果有,就reuse.如果没有,就建一个新的线程加入池中,缓存型池子通常用于执行一些生存期很短的异步型任务,因此在一些面向连接的daemon型SERVER中用得不多。能reuse的线程,必须是timeout IDLE内的池中线程,缺省timeout是60s,超过这个IDLE时长,线程实例将被终止及移出池。 注意,放入CachedThreadPool的线程不必担心其结束,超过TIMEOUT不活动,其会自动被终止。
} @Override public int onStartCommand(Intent intent, int flags, int startId) { String action = intent.getAction(); if (ACTION_TRANSCODE_MEDIA.equals(action)) { String outputType = intent.getStringExtra(EXTRA_OUTPUT_TYPE); //启动新的作业增加计数器 synchronized (mLock) { TranscodeRunnable transcodeRunnable = new TranscodeRunnable( intent.getData(), outputType); mExecutorService.execute(transcodeRunnable);//执行当前线程 mRunningJobs++;//线程计数器加1 startForegroundIfNeeded();//创建通知,并保持活跃 } } return START_NOT_STICKY;//系统回收资源关闭了当前的Service并不会重新启动.适合执行一次性操作。 } @Override public void onDestroy() { super.onDestroy(); this.mExecutorService.shutdownNow();//shutdownNow() 方法阻止等待任务启动并试图停止当前正在执行的任务 } private class TranscodeRunnable implements Runnable { private Uri mInData; private String mOutputType; private TranscodeRunnable(Uri inData, String outputType) { this.mInData = inData; this.mOutputType = outputType; } @Override public void run() { //在这里执行转码操作 //转码完成后,计数器加1 synchronized (mLock) { mRunningJobs--; stopForegroundIfAllDone(); } } } private void stopForegroundIfAllDone() { if (mRunningJobs == 0 && mIsForeground) { stopForeground(true); this.mIsForeground = false; } } private void startForegroundIfNeeded() { if (!mIsForeground) { Notification notification = buildNotFication(); startForeground(NOTIFICATION_ID, notification); this.mIsForeground = true; } } private Notification buildNotFication() { Notification notification = null; //在这里构建通知 return notification; } }