標籤:android java service 並存執行
大家眾所周知,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;
}
}
並存執行的Service,以媒體轉碼成新格式為例