版權聲明:本文出自汪磊的博客, 轉載請務必注明出處。
關於安卓Service相信很多安卓開發者都聽說過, 作為安卓四大元件之一, 即使不經常用也應該聽說過, 但並不是每一個人都掌握的特別詳細, 全面。 那麼今天我將帶大家全面瞭解一下Service.希望對您有所幫助。
什麼是Service?
先來看一下官方定義:
A Serviceis an application component that can perform long-running operations in the background and does not provide a user interface. Another application component can start a service and it will continue to run in the background even if the user switches to another application. Additionally, a component can bind to a service to interact with it and even perform interprocess communication (IPC). For example, a service might handle network transactions, play music, perform file I/O, or interact with a content provider, all from the background.
翻譯過來就是:Service是一個沒有使用者介面的在後臺運行執行耗時操作的應用組件。 其他應用元件能夠啟動Service,
並且當用戶切換到另外的應用場景, Service將持續在後臺運行。 另外, 一個元件能夠綁定到一個service與之交互(IPC機制),
例如,
簡單說Service就是一個不依附介面可以在後臺長期執行耗時操作的元件。
Service基本用法
接下來瞭解一下Service的啟動以及生命週期, 下面通過一個簡單實例來學習一下。
新建一個MyService繼承自Service, 並重寫父類的onCreate、onStartCommand和onDestroy方法, 如下所示:
1 public class MyService extends Service { 2 3 @Override 4 public IBinder onBind(Intent arg0) { 5 return null; 6 } 7 8 @Override 9 public void onCreate {10 Log.i("WLService", "onCreate"); 11 super.onCreate;12 }13 14 @Override15 public int onStartCommand(Intent intent, int flags, int startId) {16 Log.i("WLService", "onStartCommand"); 17 return super.onStartCommand(intent, flags, startId);18 }19 20 @Override21 public void onDestroy {22 Log.i("WLService", "onDestroy"); 23 super.onDestroy;24 }25 26 }然後打開專案佈局檔, 添加啟動, 關閉Service按鈕, 如下:
1Service作為四大元件之一, 我們還需要在清單檔中註冊一下, 如下:
1
然後我們在MainActivity中編寫啟動, 關閉服務代碼。 如下:
1 public class MainActivity extends Activity { 2 3 @Override 4 protected void onCreate(Bundle savedInstanceState) { 5 super.onCreate(savedInstanceState); 6 setContentView(R.layout.activity_main); 7 } 8 9 public void start(View view) {10 Intent intent = new Intent(this, MyService.class);11 // 通知框架開啟服務。 12 startService(intent);13 }14 15 public void stop(View view) {16 Intent intent = new Intent(this, MyService.class);17 stopService(intent);18 }19 20 @Override21 protected void onDestroy {22 Log.i("WLService", "MainActivity onDestroy"); 23 super.onDestroy;24 }25 }在Start Service按鈕的點擊事件裡, 我們構建出了一個Intent物件, 調用startService方法來啟動MyService。
然後在Stop Serivce按鈕的點擊事件裡, 我們同樣構建出了一個Intent物件,
基本的專案搭建完成, 現在我們運行專案, 點擊開啟服務按鈕, 會看到列印如下:
當我們再次點擊開啟服務按鈕, 會看到列印如下:只有"onStartCommand"會列印出來
當我們點擊停止服務按鈕, 會看到列印如下:
到現在為止相信你對Service有了最基礎的瞭解.接下來, 我們還需要瞭解怎麼調用服務裡面的方法。
調用服務裡面的方法
有些同學可能會說調用服務裡面的方法還不簡單嗎, new一個物件獲得引用, 然後不久可以調用了嗎?這樣可以嗎?我們可以自己測試一下。
首先我們在服務裡面添加一個方法, 如下:
1 public void methodInService{2 3 Toast.makeText(this, "ClearHeart", Toast.LENGTH_SHORT).show;4 }很簡單, 我們只是彈出一個吐司。
然後在佈局檔加入如下按鈕:
1接下來我們編寫代碼調用服務裡面的方法:
運行程式點擊按鈕調用服務裡面的方法我們會發現程式崩潰, 報如下錯誤:
1 08-13 10:38:41.114: D/AndroidRuntime(2431): Shutting down VM 2 08-13 10:38:41.115: E/AndroidRuntime(2431): FATAL EXCEPTION: main 3 08-13 10:38:41.115: E/AndroidRuntime(2431): Process: com.wl.service, PID: 2431 4 08-13 10:38:41.115: E/AndroidRuntime(2431): java.lang.IllegalStateException: Could not execute method of the activity 5 08-13 10:38:41.115: E/AndroidRuntime(2431): at android.view.View$1.onClick(View.java:4007) 6 08-13 10:38:41.115: E/AndroidRuntime(2431): at android.view.View.performClick(View.java:4756) 7 08-13 10:38:41.115: E/AndroidRuntime(2431): at android.view.View$PerformClick.run(View.java:19749) 8 08-13 10:38:41.115: E/AndroidRuntime(2431): at android.os.Handler.handleCallback(Handler.java:739) 9 08-13 10:38:41.115: E/AndroidRuntime(2431): at android.os.Handler.dispatchMessage(Handler.java:95)10 08-13 10:38:41.115: E/AndroidRuntime(2431): at android.os.Looper.loop(Looper.java:135)11 08-13 10:38:41.115: E/AndroidRuntime(2431): at android.app.ActivityThread.main(ActivityThread.java:5221)12 08-13 10:38:41.115: E/AndroidRuntime(2431): at java.lang.reflect.Method.invoke(Native Method)13 08-13 10:38:41.115: E/AndroidRuntime(2431): at java.lang.reflect.Method.invoke(Method.java:372)14 08-13 10:38:41.115: E/AndroidRuntime(2431): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)15 08-13 10:38:41.115: E/AndroidRuntime(2431): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)16 08-13 10:38:41.115: E/AndroidRuntime(2431): Caused by: java.lang.reflect.InvocationTargetException17 08-13 10:38:41.115: E/AndroidRuntime(2431): at java.lang.reflect.Method.invoke(Native Method)18 08-13 10:38:41.115: E/AndroidRuntime(2431): at java.lang.reflect.Method.invoke(Method.java:372)19 08-13 10:38:41.115: E/AndroidRuntime(2431): at android.view.View$1.onClick(View.java:4002)20 08-13 10:38:41.115: E/AndroidRuntime(2431): ... 10 more21 08-13 10:38:41.115: E/AndroidRuntime(2431): Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources android.content.Context.getResources' on a null object reference22 08-13 10:38:41.115: E/AndroidRuntime(2431): at android.content.ContextWrapper.getResources(ContextWrapper.java:85)23 08-13 10:38:41.115: E/AndroidRuntime(2431): at android.widget.Toast.定位到彈出吐司那一句代碼有空指標異常, 通過簡單分析可以確定this是空, 那麼為什麼this是空呢?
這裡需要解釋一下, 服務(Service)只能由系統創建, 而不能通過new MyService方式自己創建,如果我們自己創建服務物件, 這樣創建出來的只是一個普通類。 Service的創建只能由系統來創建完成, 而不能我們自己創建, 只有系統框架創建的Service才能將應用上下文傳遞給Service。
那我們如何調用Service內部方法呢?這裡我們需要另一種方式開啟服務,bind方式開啟服務。
接下來我們新建一個工程, 新建MyService類繼承系統Service類, 代碼如下:
1 public class MyService extends Service { 2 3 private static final String TAG = "WLHeart"; 4 5 @Override 6 public IBinder onBind(Intent arg0) { 7 Log.i(TAG, "onBind"); 8 return new MiddlePerson; 9 }10 11 @Override12 public boolean onUnbind(Intent intent) {13 Log.i(TAG, "onUnbind");14 return super.onUnbind(intent);15 }16 17 @Override18 public void onCreate {19 Log.i(TAG, "onCreate");20 super.onCreate;21 }22 23 @Override24 public int onStartCommand(Intent intent, int flags, int startId) {25 Log.i(TAG, "onStartCommand");26 return super.onStartCommand(intent, flags, startId);27 }28 29 @Override30 public void onDestroy {31 Log.i(TAG, "onDestroy");32 super.onDestroy;33 }34 35 /**36 * 這是服務裡面的一個方法37 */38 public void methodInService {39 Toast.makeText(this, "WLHeart", 0).show;40 }41 42 private class MiddlePerson extends Binder implements IMiddleBind {43 44 public void callMethodInService(int money) {45 46 methodInService;47 }48 }49 }可見我們新增了一個私有內部類MiddlePerson繼承Binder並且實現IMiddleBind介面,
重寫服務的onUnbind方法, 返回內部類MiddlePerson的實例物件。
IMiddleBind代碼如下:
1 public interface IMiddleBind {2 3 public void callMethodInService;4 }然後我們修改佈局檔, 很簡單不必過多解釋了, 如下:
1接下來我們修改MainActivity中代碼, 綁定服務並且調用其中代碼:
1 public class MainActivity extends Activity { 2 private static final String TAG = "WLHeart"; 3 private MyConn conn; 4 private IMiddleBind middleBinder; 5 6 @Override 7 protected void onCreate(Bundle savedInstanceState) { 8 super.onCreate(savedInstanceState); 9 setContentView(R.layout.activity_main);10 }11 12 // 綁定服務13 public void bind(View view) {14 Intent intent = new Intent(this, MyService.class);15 conn = new MyConn;16 bindService(intent, conn, BIND_AUTO_CREATE);17 }18 19 // 解除綁定服務20 public void unbind(View view) {21 unbindService(conn);22 }23 24 @Override25 protected void onDestroy {26 Log.i(TAG, "activity, onDestroy");27 middleBinder = null;28 super.onDestroy;29 }30 31 // 調用服務裡面的方法。 32 public void call(View view) {33 // 34 if(null != middleBinder){35 middleBinder.callMethodInService;36 }37 }38 39 private class MyConn implements ServiceConnection {40 //41 @Override42 public void onServiceConnected(ComponentName name, IBinder service) {43 Log.i(TAG, "onServiceConnected");44 middleBinder = (IMiddleBind) servi ce;45 }46 47 // 當服務失去連接的時候調用48 @Override49 public void onServiceDisconnected(ComponentName name) {50 51 }52 }53 }可以看到我們新建一個MyConn的內部類實現ServiceConnection介面, 在裡面重寫了onServiceConnected方法和onServiceDisconnected方法,
這兩個方法分別會在調用者與Service建立關聯和解除關聯的時候調用。 在onServiceConnected方法中我們將返回的service參數轉型為IMiddleBind類型, 這裡為什麼可以轉型呢?大家注意到在MyService的onBind方法中我們返回了其內部類MiddlePerson的實例,
MiddlePerson繼承自Binder類, Binder類點進系統源碼我們可以看到其實現IBinder介面, 而onServiceConnected(ComponentName name, IBinder service)方法第二個參數正是IBinder類型,
到此, 大家應該明白了吧。
簡單總結一下:在調用者與Service綁定成功的時候會調用onServiceConnected方法, 此方法中第二個參數就是我們在onBind方法中返回的
MiddlePerson實例, 好了到此為止我們就可以獲取Service內部類的實例引用了, 通過這個實例引用我們就可以調用其內部方法了。
我們運行程式實驗一下, 運行程式, 點擊綁定服務按鈕, 列印如下:
點擊調用服務裡面方法按鈕, 列印如下:
點擊解除綁定按鈕, 列印如下:
到此為止是不是對綁定服務方式開啟服務並且調用其中方法有了一步初步認識, 似乎過程又有些小複雜, 我們總結一下綁定本機服務調用方法的步驟:
1.在服務的內部創建一個內部類 提供一個方法,可以間接調用服務的方法
private class MiddlePerson extends Binder implements IMiddleBind
2.實現服務的onbind方法,返回的就是中間人 MiddlePerson
1 @Override2 public IBinder onBind(Intent arg0) {3 Log.i(TAG, "onBind");4 return new MiddlePerson;5 }3.在activity 綁定服務。bindService;
1 // 綁定服務2 public void bind(View view) {3 Intent intent = new Intent(this, MyService.class);4 conn = new MyConn;5 bindService(intent, conn, BIND_AUTO_CREATE);6 }4.在服務成功綁定的時候 會執行一個方法 onServiceConnected 傳遞過來一個 IBinder物件
5.強制類型轉化 調用介面裡面的方法。
1 private class MyConn implements ServiceConnection { 2 // 3 @Override 4 public void onServiceConnected(ComponentName name, IBinder service) { 5 Log.i(TAG, "onServiceConnected"); 6 middleBinder = (IMiddleBind) service; 7 } 8 9 // 當服務失去連接的時候調用10 @Override11 public void onServiceDisconnected(ComponentName name) {12 13 }14 }遵循以上5部就可以綁定本機服務並且調用服務種方法,是不是很簡單呢。
綁定服務調用服務中方法注意點
有些同學有沒有想過可不可以綁定服務之後立刻調用服務中方法呢?我們可以試驗一下,將MainActivity代碼改為如下:
1 public class MainActivity extends Activity { 2 private static final String TAG = "WLHeart"; 3 private MyConn conn; 4 private IMiddleBind middleBinder; 5 6 @Override 7 protected void onCreate(Bundle savedInstanceState) { 8 super.onCreate(savedInstanceState); 9 setContentView(R.layout.activity_main);10 }11 12 // 綁定服務13 public void bind(View view) {14 Intent intent = new Intent(this, MyService.class);15 conn = new MyConn;16 bindService(intent, conn, BIND_AUTO_CREATE);17 middleBinder.callMethodInService;18 }19 20 // 解除綁定服務21 public void unbind(View view) {22 unbindService(conn);23 }24 25 @Override26 protected void onDestroy {27 Log.i(TAG, "activity,onDestroy");28 middleBinder = null;29 super.onDestroy;30 }31 32 // 調用服務裡面的方法。33 public void call(View view) {34 // 35 36 }37 38 private class MyConn implements ServiceConnection {39 //40 @Override41 public void onServiceConnected(ComponentName name, IBinder service) {42 Log.i(TAG, "onServiceConnected");43 middleBinder = (IMiddleBind) service;44 }45 46 // 當服務失去連接的時候調用47 @Override48 public void onServiceDisconnected(ComponentName name) {49 50 }51 }52 }可見我們只是將邏輯改為綁定完服務立刻調用其方法,運行程式,點擊綁定服務按鈕會發現報如下錯誤:
1 08-14 14:47:21.311: E/AndroidRuntime(1890): FATAL EXCEPTION: main 2 08-14 14:47:21.311: E/AndroidRuntime(1890): Process: com.wl.bindservice, PID: 1890 3 08-14 14:47:21.311: E/AndroidRuntime(1890): java.lang.IllegalStateException: Could not execute method of the activity 4 08-14 14:47:21.311: E/AndroidRuntime(1890): at android.view.View$1.onClick(View.java:4007) 5 08-14 14:47:21.311: E/AndroidRuntime(1890): at android.view.View.performClick(View.java:4756) 6 08-14 14:47:21.311: E/AndroidRuntime(1890): at android.view.View$PerformClick.run(View.java:19749) 7 08-14 14:47:21.311: E/AndroidRuntime(1890): at android.os.Handler.handleCallback(Handler.java:739) 8 08-14 14:47:21.311: E/AndroidRuntime(1890): at android.os.Handler.dispatchMessage(Handler.java:95) 9 08-14 14:47:21.311: E/AndroidRuntime(1890): at android.os.Looper.loop(Looper.java:135)10 08-14 14:47:21.311: E/AndroidRuntime(1890): at android.app.ActivityThread.main(ActivityThread.java:5221)11 08-14 14:47:21.311: E/AndroidRuntime(1890): at java.lang.reflect.Method.invoke(Native Method)12 08-14 14:47:21.311: E/AndroidRuntime(1890): at java.lang.reflect.Method.invoke(Method.java:372)13 08-14 14:47:21.311: E/AndroidRuntime(1890): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)14 08-14 14:47:21.311: E/AndroidRuntime(1890): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)15 08-14 14:47:21.311: E/AndroidRuntime(1890): Caused by: java.lang.reflect.InvocationTargetException16 08-14 14:47:21.311: E/AndroidRuntime(1890): at java.lang.reflect.Method.invoke(Native Method)17 08-14 14:47:21.311: E/AndroidRuntime(1890): at java.lang.reflect.Method.invoke(Method.java:372)18 08-14 14:47:21.311: E/AndroidRuntime(1890): at android.view.View$1.onClick(View.java:4002)19 08-14 14:47:21.311: E/AndroidRuntime(1890): ... 10 more20 08-14 14:47:21.311: E/AndroidRuntime(1890): Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'void com.wl.bindservice.IMiddleBind.callMethodInService' on a null object reference21 08-14 14:47:21.311: E/AndroidRuntime(1890): at com.wl.bindservice.MainActivity.bind(MainActivity.java:28)22 08-14 14:47:21.311: E/AndroidRuntime(1890): ... 13 more報空指針異常,定位到middleBinder.callMethodInService;發生空指針,明顯是middleBinder為空,那為什麼會是空呢?我們不是已經綁定服務了嗎?
原來綁定服務的過程是非同步過程,這個過程可能持續幾十或者幾百毫秒,而middleBinder只有在調用完onServiceConnected才會初始化完成,
這樣就不難理解為什麼會報空指針異常了吧,希望各位使用過程中會注意一下這個地方。
兩種開啟服務方法的區別
start方式開啟服務。 一旦服務開啟跟調用者(開啟者)就沒有任何關係了。開啟者退出了,開啟者掛了,服務還在後臺長期的運行。開啟者沒有辦法去調用服務裡面的方法。
bind的方式開啟服務,綁定服務,調用者掛了,服務也會跟著掛掉。開啟者可以調用服務裡面的方法。
混合方式開啟服務
如果我們即想服務長期在後臺運行又想調用其中方法怎麼辦呢?很簡單,我們可以採取混合調用服務的方法開啟服務
即我們先調用start方式開啟服務保證服務在後臺長期運行,在調用bind方式綁定服務保證調用服務裡面方法,這樣子即可。
那我們如何關閉服務呢?我們知道start方式開啟服務我們只需要調用stopservice即可關閉服務,
bind方式開啟服務我們只需調用unbind即可關閉服務 ,其實混合方法開啟服務我們只需要先調用unbind解除綁定,
再調用stopservice停止服務即可。混合方式調用服務完整過程如下:
1.start方式開啟服務(保證服務長期後臺運行)
2.bind方式綁定服務(保證調用服務的方法)
3.unbind解除綁定服務
4.stopService停止服務
好了,到此為止我們算是對服務有了一個比較基礎的全面的認識,掌握這些相信能解決平時開發中大部分的問題了。
下一篇(中篇)會帶大家瞭解一下安卓IPC(處理序間通訊)機制,最後(下篇)詳細瞭解安卓Binder機制。
1.在服務的內部創建一個內部類 提供一個方法,可以間接調用服務的方法
private class MiddlePerson extends Binder implements IMiddleBind
2.實現服務的onbind方法,返回的就是中間人 MiddlePerson
1 @Override2 public IBinder onBind(Intent arg0) {3 Log.i(TAG, "onBind");4 return new MiddlePerson;5 }3.在activity 綁定服務。bindService;
1 // 綁定服務2 public void bind(View view) {3 Intent intent = new Intent(this, MyService.class);4 conn = new MyConn;5 bindService(intent, conn, BIND_AUTO_CREATE);6 }4.在服務成功綁定的時候 會執行一個方法 onServiceConnected 傳遞過來一個 IBinder物件
5.強制類型轉化 調用介面裡面的方法。
1 private class MyConn implements ServiceConnection { 2 // 3 @Override 4 public void onServiceConnected(ComponentName name, IBinder service) { 5 Log.i(TAG, "onServiceConnected"); 6 middleBinder = (IMiddleBind) service; 7 } 8 9 // 當服務失去連接的時候調用10 @Override11 public void onServiceDisconnected(ComponentName name) {12 13 }14 }遵循以上5部就可以綁定本機服務並且調用服務種方法,是不是很簡單呢。
綁定服務調用服務中方法注意點
有些同學有沒有想過可不可以綁定服務之後立刻調用服務中方法呢?我們可以試驗一下,將MainActivity代碼改為如下:
1 public class MainActivity extends Activity { 2 private static final String TAG = "WLHeart"; 3 private MyConn conn; 4 private IMiddleBind middleBinder; 5 6 @Override 7 protected void onCreate(Bundle savedInstanceState) { 8 super.onCreate(savedInstanceState); 9 setContentView(R.layout.activity_main);10 }11 12 // 綁定服務13 public void bind(View view) {14 Intent intent = new Intent(this, MyService.class);15 conn = new MyConn;16 bindService(intent, conn, BIND_AUTO_CREATE);17 middleBinder.callMethodInService;18 }19 20 // 解除綁定服務21 public void unbind(View view) {22 unbindService(conn);23 }24 25 @Override26 protected void onDestroy {27 Log.i(TAG, "activity,onDestroy");28 middleBinder = null;29 super.onDestroy;30 }31 32 // 調用服務裡面的方法。33 public void call(View view) {34 // 35 36 }37 38 private class MyConn implements ServiceConnection {39 //40 @Override41 public void onServiceConnected(ComponentName name, IBinder service) {42 Log.i(TAG, "onServiceConnected");43 middleBinder = (IMiddleBind) service;44 }45 46 // 當服務失去連接的時候調用47 @Override48 public void onServiceDisconnected(ComponentName name) {49 50 }51 }52 }可見我們只是將邏輯改為綁定完服務立刻調用其方法,運行程式,點擊綁定服務按鈕會發現報如下錯誤:
1 08-14 14:47:21.311: E/AndroidRuntime(1890): FATAL EXCEPTION: main 2 08-14 14:47:21.311: E/AndroidRuntime(1890): Process: com.wl.bindservice, PID: 1890 3 08-14 14:47:21.311: E/AndroidRuntime(1890): java.lang.IllegalStateException: Could not execute method of the activity 4 08-14 14:47:21.311: E/AndroidRuntime(1890): at android.view.View$1.onClick(View.java:4007) 5 08-14 14:47:21.311: E/AndroidRuntime(1890): at android.view.View.performClick(View.java:4756) 6 08-14 14:47:21.311: E/AndroidRuntime(1890): at android.view.View$PerformClick.run(View.java:19749) 7 08-14 14:47:21.311: E/AndroidRuntime(1890): at android.os.Handler.handleCallback(Handler.java:739) 8 08-14 14:47:21.311: E/AndroidRuntime(1890): at android.os.Handler.dispatchMessage(Handler.java:95) 9 08-14 14:47:21.311: E/AndroidRuntime(1890): at android.os.Looper.loop(Looper.java:135)10 08-14 14:47:21.311: E/AndroidRuntime(1890): at android.app.ActivityThread.main(ActivityThread.java:5221)11 08-14 14:47:21.311: E/AndroidRuntime(1890): at java.lang.reflect.Method.invoke(Native Method)12 08-14 14:47:21.311: E/AndroidRuntime(1890): at java.lang.reflect.Method.invoke(Method.java:372)13 08-14 14:47:21.311: E/AndroidRuntime(1890): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)14 08-14 14:47:21.311: E/AndroidRuntime(1890): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)15 08-14 14:47:21.311: E/AndroidRuntime(1890): Caused by: java.lang.reflect.InvocationTargetException16 08-14 14:47:21.311: E/AndroidRuntime(1890): at java.lang.reflect.Method.invoke(Native Method)17 08-14 14:47:21.311: E/AndroidRuntime(1890): at java.lang.reflect.Method.invoke(Method.java:372)18 08-14 14:47:21.311: E/AndroidRuntime(1890): at android.view.View$1.onClick(View.java:4002)19 08-14 14:47:21.311: E/AndroidRuntime(1890): ... 10 more20 08-14 14:47:21.311: E/AndroidRuntime(1890): Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'void com.wl.bindservice.IMiddleBind.callMethodInService' on a null object reference21 08-14 14:47:21.311: E/AndroidRuntime(1890): at com.wl.bindservice.MainActivity.bind(MainActivity.java:28)22 08-14 14:47:21.311: E/AndroidRuntime(1890): ... 13 more報空指針異常,定位到middleBinder.callMethodInService;發生空指針,明顯是middleBinder為空,那為什麼會是空呢?我們不是已經綁定服務了嗎?
原來綁定服務的過程是非同步過程,這個過程可能持續幾十或者幾百毫秒,而middleBinder只有在調用完onServiceConnected才會初始化完成,
這樣就不難理解為什麼會報空指針異常了吧,希望各位使用過程中會注意一下這個地方。
兩種開啟服務方法的區別
start方式開啟服務。 一旦服務開啟跟調用者(開啟者)就沒有任何關係了。開啟者退出了,開啟者掛了,服務還在後臺長期的運行。開啟者沒有辦法去調用服務裡面的方法。
bind的方式開啟服務,綁定服務,調用者掛了,服務也會跟著掛掉。開啟者可以調用服務裡面的方法。
混合方式開啟服務
如果我們即想服務長期在後臺運行又想調用其中方法怎麼辦呢?很簡單,我們可以採取混合調用服務的方法開啟服務
即我們先調用start方式開啟服務保證服務在後臺長期運行,在調用bind方式綁定服務保證調用服務裡面方法,這樣子即可。
那我們如何關閉服務呢?我們知道start方式開啟服務我們只需要調用stopservice即可關閉服務,
bind方式開啟服務我們只需調用unbind即可關閉服務 ,其實混合方法開啟服務我們只需要先調用unbind解除綁定,
再調用stopservice停止服務即可。混合方式調用服務完整過程如下:
1.start方式開啟服務(保證服務長期後臺運行)
2.bind方式綁定服務(保證調用服務的方法)
3.unbind解除綁定服務
4.stopService停止服務
好了,到此為止我們算是對服務有了一個比較基礎的全面的認識,掌握這些相信能解決平時開發中大部分的問題了。
下一篇(中篇)會帶大家瞭解一下安卓IPC(處理序間通訊)機制,最後(下篇)詳細瞭解安卓Binder機制。