https://www.jianshu.com/p/4c798c91a613
Android Service兩種啟動方式詳解(總結版)

第一種方式:通過StartService啟動Service
通過startService啟動后,service會一直無限期運行下去,只有外部調用了stopService()或stopSelf()方法時,該Service才會停止運行並銷毀。
要創建一個這樣的Service,你需要讓該類繼承Service類,然后重寫以下方法:
-
onCreate()
1.如果service沒被創建過,調用startService()后會執行onCreate()回調;
2.如果service已處於運行中,調用startService()不會執行onCreate()方法。
也就是說,onCreate()只會在第一次創建service時候調用,多次執行startService()不會重復調用onCreate(),此方法適合完成一些初始化工作。 -
onStartCommand()
如果多次執行了Context的startService()方法,那么Service的onStartCommand()方法也會相應的多次調用。onStartCommand()方法很重要,我們在該方法中根據傳入的Intent參數進行實際的操作,比如會在此處創建一個線程用於下載數據或播放音樂等。 -
onBind()
Service中的onBind()方法是抽象方法,Service類本身就是抽象類,所以onBind()方法是必須重寫的,即使我們用不到。 -
onDestory()
在銷毀的時候會執行Service該方法。
這幾個方法都是回調方法,且在主線程中執行,由android操作系統在合適的時機調用。
startService代碼實例
創建TestOneService,並在manifest里注冊。
在MainActivty中操作TestOneService,code如下:
/** * Created by Kathy on 17-2-6. */ public class TestOneService extends Service{ @Override public void onCreate() { Log.i("Kathy","onCreate - Thread ID = " + Thread.currentThread().getId()); super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i("Kathy", "onStartCommand - startId = " + startId + ", Thread ID = " + Thread.currentThread().getId()); return super.onStartCommand(intent, flags, startId); } @Nullable @Override public IBinder onBind(Intent intent) { Log.i("Kathy", "onBind - Thread ID = " + Thread.currentThread().getId()); return null; } @Override public void onDestroy() { Log.i("Kathy", "onDestroy - Thread ID = " + Thread.currentThread().getId()); super.onDestroy(); } }
在MainActivity中三次startService,之后stopService。
/** * Created by Kathy on 17-2-6. */ public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.i("Kathy", "Thread ID = " + Thread.currentThread().getId()); Log.i("Kathy", "before StartService"); //連續啟動Service Intent intentOne = new Intent(this, TestOneService.class); startService(intentOne); Intent intentTwo = new Intent(this, TestOneService.class); startService(intentTwo); Intent intentThree = new Intent(this, TestOneService.class); startService(intentThree); //停止Service Intent intentFour = new Intent(this, TestOneService.class); stopService(intentFour); //再次啟動Service Intent intentFive = new Intent(this, TestOneService.class); startService(intentFive); Log.i("Kathy", "after StartService"); } }
打印出的Log如下:
02-06 15:19:45.090 8938-8938/? I/Kathy: Thread ID = 1
02-06 15:19:45.090 8938-8938/? I/Kathy: before StartService
02-06 15:19:45.233 8938-8938/? I/Kathy: onCreate - Thread ID = 1
02-06 15:19:45.234 8938-8938/? I/Kathy: onStartCommand - startId = 1, Thread ID = 1
02-06 15:19:45.234 8938-8938/? I/Kathy: onStartCommand - startId = 2, Thread ID = 1
02-06 15:19:45.235 8938-8938/? I/Kathy: onStartCommand - startId = 3, Thread ID = 1
02-06 15:19:45.236 8938-8938/? I/Kathy: onDestroy - Thread ID = 1
02-06 15:19:45.237 8938-8938/? I/Kathy: onCreate - Thread ID = 1
02-06 15:19:45.237 8938-8938/? I/Kathy: onStartCommand - startId = 1, Thread ID = 1
02-06 15:19:45.238 8938-8938/? I/Kathy: after StartService
分析:
1.主線程打印出是1,所有回調方法中打印出的執行線程ID都是1,證明回調方法都是在主線程中執行的。
2.三次調用startService,只觸發一次onCreate回調,觸發了三次onStartCommand回調,且startId分別為1,2,3。證明 多次startService不會重復執行onCreate回調,但每次都會執行onStartCommand回調。
第二種方式:通過bindService啟動Service
bindService啟動服務特點:
1.bindService啟動的服務和調用者之間是典型的client-server模式。調用者是client,service則是server端。service只有一個,但綁定到service上面的client可以有一個或很多個。這里所提到的client指的是組件,比如某個Activity。
2.client可以通過IBinder接口獲取Service實例,從而實現在client端直接調用Service中的方法以實現靈活交互,這在通過startService方法啟動中是無法實現的。
3.bindService啟動服務的生命周期與其綁定的client息息相關。當client銷毀時,client會自動與Service解除綁定。當然,client也可以明確調用Context的unbindService()方法與Service解除綁定。當沒有任何client與Service綁定時,Service會自行銷毀。
bindService代碼實例
交互界面設計如下:


1.創建一個TestTwoService繼承Service(Server)
2.創建ActivityA,可以通過bindService綁定服務(client)
3.創建ActivityB,可以通過bindService綁定服務(client)
4.ActivityA可以跳轉到ActivityB
TestTwoService創建如下:
要想讓Service支持bindService調用方式,需要做以下事情:
1.在Service的onBind()方法中返回IBinder類型的實例。
2.onBInd()方法返回的IBinder的實例需要能夠返回Service實例本身。通常,最簡單的方法就是在service中創建binder的內部類,加入類似getService()的方法返回Service,這樣綁定的client就可以通過getService()方法獲得Service實例了。
/** * Created by Kathy on 17-2-6. */ public class TestTwoService extends Service{ //client 可以通過Binder獲取Service實例 public class MyBinder extends Binder { public TestTwoService getService() { return TestTwoService.this; } } //通過binder實現調用者client與Service之間的通信 private MyBinder binder = new MyBinder(); private final Random generator = new Random(); @Override public void onCreate() { Log.i("Kathy","TestTwoService - onCreate - Thread = " + Thread.currentThread().getName()); super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i("Kathy", "TestTwoService - onStartCommand - startId = " + startId + ", Thread = " + Thread.currentThread().getName()); return START_NOT_STICKY; } @Nullable @Override public IBinder onBind(Intent intent) { Log.i("Kathy", "TestTwoService - onBind - Thread = " + Thread.currentThread().getName()); return binder; } @Override public boolean onUnbind(Intent intent) { Log.i("Kathy", "TestTwoService - onUnbind - from = " + intent.getStringExtra("from")); return false; } @Override public void onDestroy() { Log.i("Kathy", "TestTwoService - onDestroy - Thread = " + Thread.currentThread().getName()); super.onDestroy(); } //getRandomNumber是Service暴露出去供client調用的公共方法 public int getRandomNumber() { return generator.nextInt(); } }
client端要做的事情:
1.創建ServiceConnection類型實例,並重寫onServiceConnected()方法和onServiceDisconnected()方法。
2.當執行到onServiceConnected回調時,可通過IBinder實例得到Service實例對象,這樣可實現client與Service的連接。
3.onServiceDisconnected回調被執行時,表示client與Service斷開連接,在此可以寫一些斷開連接后需要做的處理。
創建ActivityA,代碼如下:
/** * Created by Kathy on 17-2-6. */ public class ActivityA extends Activity implements Button.OnClickListener { private TestTwoService service = null; private boolean isBind = false; private ServiceConnection conn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder binder) { isBind = true; TestTwoService.MyBinder myBinder = (TestTwoService.MyBinder) binder; service = myBinder.getService(); Log.i("Kathy", "ActivityA - onServiceConnected"); int num = service.getRandomNumber(); Log.i("Kathy", "ActivityA - getRandomNumber = " + num); } @Override public void onServiceDisconnected(ComponentName name) { isBind = false; Log.i("Kathy", "ActivityA - onServiceDisconnected"); } }; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_a); Log.i("Kathy", "ActivityA - onCreate - Thread = " + Thread.currentThread().getName()); findViewById(R.id.btnBindService).setOnClickListener(this); findViewById(R.id.btnUnbindService).setOnClickListener(this); findViewById(R.id.btnStartActivityB).setOnClickListener(this); findViewById(R.id.btnFinish).setOnClickListener(this); } @Override public void onClick(View v) { if (v.getId() == R.id.btnBindService) { //單擊了“bindService”按鈕 Intent intent = new Intent(this, TestTwoService.class); intent.putExtra("from", "ActivityA"); Log.i("Kathy", "----------------------------------------------------------------------");