Service爲Android四大組件之一,和Activity同樣,都是Context的子類,只是它沒有界面,Service很適合去執行那些長時間運行又不須要和用戶交互的任務。因爲Service自己是在主線程運行的,因此若是須要執行耗時操做仍是須要另外開啓子線程,不然會出現ANR錯誤。java
Service包含三種類型:服務器
Service 有兩種啓動方式,startService() 和 bindService()。多線程
startService() 啓動的生命週期如上圖左邊所示。特別的,會回調 onStartCommand()方法異步
bindService()啓動的生命週期如上圖右邊所示。特別的,會調用 onBind() 和 onUnbind()ide
onStartCommand() 方法返回一個整數值,讓系統在系統殺死此 Service 的時候如何處理此 Serviceui
不可交互的後臺服務的啓動方式爲 startService(),this
public class MyService extends Service{
public static final String TAG = "MyService";
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG,"onBind");
return null;
}
@Override
public void onCreate() {
Log.e(TAG,"onCreate");
super.onCreate();
runAfterStop();
}
private void runAfterStop(){
new Thread(){
@Override
public void run() {
try {
Thread.sleep(5000);
Log.e(TAG,"stopSelf()");
stopSelf();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG,"onStartCommand");
return START_NOT_STICKY;
}
@Override
public boolean onUnbind(Intent intent) {
Log.e(TAG,"onUnbind");
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
Log.e(TAG,"onDestroy");
super.onDestroy();
}
}
複製代碼
啓動服務spa
public class BaseActivity extends AppCompatActivity{
...
Intent intent = new Intent(this, MyService.class);
startService(intent);
...
}
複製代碼
前臺服務會在通知欄/狀態欄上顯示,而且此時的 Service 的優先級比較高,線程
public class ForegroundService extends Service{
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
//id不能爲0,不然通知欄/狀態欄不會顯示
int id = 1;
startForeground(id,createNotification());
}
private Notification createNotification(){
Intent notifiIntent = new Intent(this, FirstActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,0,notifiIntent,0);
Notification.Builder builder = new Notification.Builder(this)
.setContentTitle("title")
.setContentText("Content")
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentIntent(pendingIntent);
return builder.build();
}
}
...
//啓動服務
public class BaseActivity extends AppCompatActivity{
...
Intent intent = new Intent(this, MyService.class);
startService(intent);
...
}
複製代碼
若是要取消前臺服務,能夠調用 stopForeground(boolean removeNotification) ,代理
參數 removeNotification 爲 true 表示取消前臺服務通知也移除掉通知欄/狀態欄的圖標,false 表示不移除
調用此方法不會致使服務中止,只是把前臺轉到後臺
當服務中止的時候,通知欄/狀態欄的圖標也會同時被移除
綁定服務(Bound Services)爲客戶端-服務器模式。因爲須要交互,因此須要有一箇中間代理對象,此對象須要服務端建立而後返回給客戶端持有,類型爲 Binder,由 onBind() 進行返回。
服務端代碼:
public class BoundService extends Service {
private IBinder mBinder = new LocalBinder();
public class LocalBinder extends Binder{
public int add(int a,int b){
return BoundService.this.add(a,b);
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
private int add(int a,int b){
return a + b;
}
}
複製代碼
客戶端代碼:
public class BoundActivity extends Activity{
//持有綁定服務返回的 Binder 對象
private BoundService.LocalBinder mBinder;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
serviceBind();
}
@Override
protected void onStop() {
super.onStop();
unbindService(mServiceConn );
}
//綁定服務
private void serviceBind() {
Intent intent = new Intent(this, MyService.class);
bindService(intent, mServiceConn, Context.BIND_AUTO_CREATE);
}
//點擊事件
public void addClick(View view){
add(2,3);
}
//調用綁定服務的方法
private void add(int a,int b){
Log.(TAG,mBinder.add(a,b));
}
//綁定服務後的回調接口
private ServiceConnection mServiceConn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e(TAG,"bing Service Connected");
mBinder = (BoundService.LocalBinder) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e(TAG,"unBind Service disConnected");
mBinder = null;
}
};
}
複製代碼
這個只是基於簡單相同進程內調用,若是在 Manifest 文件中給 BoundService 添加上 process=":remote" 變成遠處服務,則上面的代碼就會報錯,拋出 java.lang.ClassCastException 異常,由於此種狀況下返回的是 Binder 的代理對象 BInderProxy,因此拋出類型轉換錯誤。進程間的通訊要用到 AIDL ,這個只能另外寫篇回顧了。
IntentService 是 Service 的子類,用來處理異步請求 特色: 一、會建立一個默認的工做子線程處理全部的請求 二、會有一個隊列逐個處理全部的 Intent 並會在 onHandleIntent() 實現 三、當 Service 處理全部的工做後會自動結束 Service,不須要手動調用 stopSelf() 四、默認實現返回值爲 null 的 onBind() 方法 五、默認實現 onStartCommand(),會把請求的 Intent 放到工做隊列裏
因此咱們不須要去管理 IntentService 的生命週期和管理線程。而且 IntentService 在處理完因此任務後會自動關閉。當業務不須要涉及到多線程任務時,IntentService 就可以知足大多數的需求了。
實現 IntentService 的方式很簡單,只須要提供一個構造方法和實現 onHandleIntent() 方法
public class TestIntentService extends IntentService {
publicTestIntentService() {
super("TestIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
//模擬耗時操做
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
複製代碼
IntentService 的是使用 HandlerThread + Handler 來實現的。HandlerThread 爲Thread的子類,Handler 運行在 HandlerThread 線程中,處理耗時操做。
Service 是 Android 的一種機制,運行在主線程中,若是進行耗時操做,須要建立一個子線程執行。
Service 的優先級高於後臺掛起的 Activity 和其所建立的子線程 Thread。系統可能會在內存不足的時候,優先殺死後臺掛起的 Activity 或 Thread,而不會輕易殺死 Service。
Thread 的運行是獨立於 Activity 的,當 Activity 被 finish 掉的時候,若是沒有主動中止 Thread 或未執行完任務,那麼它還會繼續執行。此時程序將再也不持有這個 Thread 的引用,此時將控制不了此 Thread。
因此當須要長期穩定的在後臺運行某個任務時,須要使用 Service,而當 Service 在運行這個任務時要處理耗時操做時,要另外建立子線程來執行。