什么是服務
服務是一個沒有可視化界面的組件,它可以在后台長期運行並進行各種操作。
服務的創建
我們只需要繼承Service類並實現相應的方法即可創建服務
要想啟動服務,還得在AndroidManifest中注冊服務
服務類的示例代碼
package com.whathecode.servicedemo; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.widget.Toast; public class ExtendsionService extends Service { /** * 當服務第一次被創建的時候調用此方法 */ @Override public void onCreate() { super.onCreate(); Toast.makeText(getBaseContext(), "服務被創建了", Toast.LENGTH_SHORT).show(); } /** * 當通過startService方法啟動服務時此方法被調用 */ @Override public int onStartCommand(Intent intent, int flags, int startId) { Toast.makeText(getBaseContext(), "服務被啟動了", Toast.LENGTH_SHORT).show(); return super.onStartCommand(intent, flags, startId); } @Override public IBinder onBind(Intent intent) { return null; } @Override public void onDestroy() { super.onDestroy(); } }
使用startService啟動服務
主界面的邏輯代碼:
package com.whathecode.servicedemo; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; public class MainActivity extends Activity { Intent service = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //創建服務 service = new Intent(this, ExtendsionService.class); } public void start(View view) { //啟動服務 startService(service); } public void stop(View view) { //停止服務 stopService(service); } }
注冊服務:
<service android:name="com.whathecode.servicedemo.BackgroundService"></service>
運行效果:
注意:
當我們第一次點擊啟動服務按鈕的時候,onCreate方法和onStartCommand方法依次執行,
但在第二次點擊啟動服務按鈕的時候,這個服務已經處於運行狀態,onCreate方法不再執行第二次,
而onStartCommand方法總是在調用startService啟動服務的時候執行。
onDestroy方法在stopService方法被調用后執行。
除了使用startService方法啟動服務外,我們還可以使用Bind的方式啟動服務。
前者和后者的不同在於:
服務的生命周期不依賴於啟動者。服務被啟動后一直在后台運行直到調用stopService被停止。
使用Bind方式啟動服務,服務的生命周期依賴於啟動者。即服務在啟動者退出后自動銷毀。
使用Bind方式啟動服務
主要使用bindService方法啟動服務,unbindService方法銷毀服務。
使用此方式啟動服務的好處是,bind定成功的時候服務返回一個IBinder對象,
我們可以通過在服務類里面實現這個對象,從而訪問服務里面的具體方法。
從而達到和服務溝通的目的。
注意:
我們不能以直接實例化服務的方式調用里面的方法。
另外:
如果在退出服務的時候沒有解綁,那么程序就會拋出異常IllegalArgumentException異常。
因此,每次調用bindService啟動服務,完成后需要退出服務都需要使用unbindService 解綁。
示例代碼:
package com.whathecode.servicedemo; import android.app.Activity; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.view.View; public class MainActivity extends Activity { Intent service = null; IReceptionist rpst; /** * bindService和unbindService方法使用的參數 */ private ServiceConnection conn = new ServiceConnection() { //此方法在服務連接被意外終止的時候被調用, @Override public void onServiceDisconnected(ComponentName name) { } //當服務被連接上的時候自動調用這個方法,第二個參數是服務類onBind方法中返回的對象 @Override public void onServiceConnected(ComponentName name, IBinder service) { rpst = (IReceptionist) service; rpst.callExtendsionNumber(); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //創建服務 service = new Intent(this, ExtendsionService.class); } public void start(View view) { //啟動服務 startService(service); } public void stop(View view) { //停止服務 stopService(service); } public void bind(View view) { //綁定服務 bindService(service, conn , BIND_AUTO_CREATE); } public void unBind(View view) { //解綁服務 unbindService(conn); } }
繼承ServiceBinder對象,並實現自定義接口:
通過這個方式,我們可以暴露只需要的方法,實現代碼的保護。
IReceptionist接口代碼:
package com.whathecode.servicedemo; public interface IReceptionist { public void callExtendsionNumber(); }
ExtendsionService服務類代碼:
package com.whathecode.servicedemo; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.util.Log; import android.widget.Toast; public class ExtendsionService extends Service { private static final String TAG = "ExtendsionService"; /** * 當服務第一次被創建的時候調用此方法 */ @Override public void onCreate() { super.onCreate(); Toast.makeText(getBaseContext(), "服務被創建了", Toast.LENGTH_SHORT).show(); } /** * 當通過startService方法啟動服務時此方法被調用 */ @Override public int onStartCommand(Intent intent, int flags, int startId) { Toast.makeText(getBaseContext(), "服務被啟動了", Toast.LENGTH_SHORT).show(); return super.onStartCommand(intent, flags, startId); } @Override public IBinder onBind(Intent intent) { return new ServiceBinder(); } @Override public void onDestroy() { Toast.makeText(getBaseContext(), "服務被銷毀了", Toast.LENGTH_SHORT).show(); Log.d(TAG, "服務被銷毀了"); super.onDestroy(); } public void putExtendsion() { Toast.makeText(getBaseContext(), "正在幫你轉接分機", Toast.LENGTH_SHORT).show(); } /** * * 繼承Binder並實現IReceptionist接口 * 繼承Binder類的目的是onBind方法中需要返回這個類型的對象 * * 實現IReceptionist接口是暴露方法的需要 */ private class ServiceBinder extends Binder implements IReceptionist { public void callExtendsionNumber() { putExtendsion(); } private void otherMethod() { } } }
運行效果:
注意看上圖,我們在按下返回鍵的時候,Activity被銷毀,由它啟動的服務也跟着被銷毀。
這樣的服務貌似作用不大,有沒有辦法在退出Activity的時候不退出服務呢?
答案是有的:Android允許我們先啟動一個服務,然后再調用bindService綁定到服務,
這樣,我們既可以達到和服務溝通的目的,也可以使服務長期在后台運行。
看下圖:
通過下面的圖,就可以更清楚地理解上面代碼的工作原理: