Service是什麼?Service又不是什麼?

来源:http://www.cnblogs.com/his365/archive/2016/11/16/6071370.html
-Advertisement-
Play Games

在Android王國中,Service是一個勞動模範,總是默默的在後臺運行,無怨無悔,且總是乾最臟最累的活,比如下載文件,傾聽音樂,網路操作等這些耗時的操作,所以我們請尊重的叫他一聲:"勞模,您辛苦了". 帶著這份好尊重,我又重新研讀了API的文檔,發現老外寫東西還是很靠譜的,人家在文檔中告訴你Se ...


   在Android王國中,Service是一個勞動模範,總是默默的在後臺運行,無怨無悔,且總是乾最臟最累的活,比如下載文件,傾聽音樂,網路操作等這些耗時的操作,所以我們請尊重的叫他一聲:"勞模,您辛苦了".

    帶著這份好尊重,我又重新研讀了API的文檔,發現老外寫東西還是很靠譜的,人家在文檔中告訴你Service是什麼,又告訴你Service又不是什麼,我覺得這種思路不錯,那就從這兩個個方面開始談起吧:
  1. Service是什麼?
    1. A Service is an application component. ☆ Service 是一個應用程式組件
    2. that can perform long-running operations in the background. ☆ 它能在後臺執行一些耗時較長的操作.
    3. and does not provide a user interface. ☆ 並且不提供用戶界面
    4. Another application component can start a service and it will continue to run in the background event if the user switches to another application.  服務能被其它的應用程式組件啟動,即使用戶切換到其他的應用程式時還能保持在後臺運行.
    5. Additionally,a component can bind to a service to interact with it and even perform interprocess communcation(IPC).  此外,組件還能綁定服務,並與服務交互,甚至執行進程間通信(IPC).
    6. For example,a service might handle network transactions,play music,perform file I/O,or interact with a content provider,all from the background.  比如,一個服務可以處理網路傳輸,聽音樂,執行文件操作,或者與內容提供者進行交互,所有這些都在後臺進行.
    7. A service can essentially tack two forms. 服務有以下兩種基本類型
      1. Started --> startService()
      2. Bound --> bindService()
  2. Service又不是什麼?
    1. A service is not a separate process. 服務不是一個單獨的進程.
    2. A service is not a thread.it runs in the main thread of its hosting process.  服務不是一個線程,它運行在主線程.
    3. the service does not create its own thread and does not run in a separate process(unless you specify otherwise).  服務不能自己創建並且不能運行在單獨的進程中(除非你明確指定).
    4. This means that, if your service is going to do any CPU intensive work ot blocking operations(such as MP3 playback or network).  這意味著如果你的服務要執行一些很耗CUP的工作或者阻塞的操作(比如播放mp3或網路操作),you should create a new thread within the service to do that work.  你應該在服務中創建一個新的線程來執行這些工作.
    5. By using a separate thread, you will reduce the risk of Application Not Responding(ANR) errors and the application's main thread can remain dedicated to user interaction with your activities.  利用一個分離的進程,將減少你的activities發生應用程式停止響應(ANR)錯誤的風險.
  3. 如何創建一個Started服務
    1. 繼承service
      1. publicclassFirstServiceextendsService{
      2. privatestaticfinalString TAG ="--FirstService-->";
      3. publicFirstService(){
      4. Log.i(TAG,"Service is running.");
      5. }
      6. @Override
      7. publicvoid onCreate(){
      8. Log.i(TAG,"onCreate is running.");
      9. super.onCreate();
      10. }
      11. @Override
      12. publicint onStartCommand(Intent intent,int flags,int startId){
      13. Log.i(TAG,"onStartCommand is running.");
      14. returnsuper.onStartCommand(intent, flags, startId);
      15. }
      16. @Override
      17. publicIBinder onBind(Intent intent){
      18. Log.i(TAG,"IBinder is running.");
      19. returnnull;
      20. }
      21. }
       
    2. 四大組件都需要在manifests.xml中註冊,這個也不例外.
    3. 如何啟動它
      1. Intent intent =newIntent(ServiceActivity.this,FirstService.class);
      2. startService(intent);
       
    4. 生命周期onCreate(), onStartCommand(), onDestory()就這三個生命周期
      1. --FirstService-->:Service is running.
      2. --FirstService-->: onCreate is running.
      3. --FirstService-->: onStartCommand is running.
       
    5. 我們在onStartCommand方法中列印下當前線程
      1. @Override
      2. publicint onStartCommand(Intent intent,int flags,int startId){
      3. Log.i(TAG,"onStartCommand is running.Thread:"+Thread.currentThread());
      4. returnsuper.onStartCommand(intent, flags, startId);
      5. }
      列印結果如下:
      1. onStartCommand is running.Thread:Thread[main,5,main]
      驗證了兩點:①由於是第二次運行,構造方法和onStart都沒有列印,說明服務一旦啟動是默默運行在後臺的;②服務是運行在主線程的 
    6. 如何結束服務:①調用stopService()方法 ,會回調service的onDestory()方法;
      1. Intent intent2 =newIntent(ServiceActivity.this,FirstService.class);
      2. stopService(intent2);
      還可以在Android系統設置-->應用-->正在運行-->找到後是如下樣式,會告訴我們有一個服務在運行;
    7. onStartCommand的返回值:
      1. START_STICKY:粘性的,被意外中止後自動重啟,重新調用onStartCommand(),但會丟失原來激活它的Intent,會用一個null intent來調用onStartCommand(),可以用於播放器.值為1
      2. START_NOT_STICKY:非粘性的,被意外中止後不會重啟,除非還存在未發送的Intent,這是避免服務運行的最安全選項; 值為2
      3. START_REDELIVER_INTENT:粘性的且重新發送Intent,被意外中止後重新啟動,且該service組件將得到用於激活它的Intent對象,這中服務適用於需要立即恢復工作的活躍服務,比如下載文件; 值為3
    8. onStartCommand的參數:
      1. @Override //第一個參數:為我們傳入的intent;第二個flags:啟動服務的方式,與返回值有關;第三個為我們啟動service的次數.
      2. publicint onStartCommand(Intent intent,int flags,int startId){
      3. Log.i(TAG,"onStartCommand is running.Thread:"+Thread.currentThread());
      4. Log.i(TAG,"flags:"+flags);
      5. Log.i(TAG,"startId:"+startId);
      6. returnsuper.onStartCommand(intent, flags, startId);
      7. }
      因為前面服務已經啟動了,這次我們連續點了三次啟動服務的按鈕,列印日誌如下:
      1. 11-1602:56:28.3859039-9039/com.wanghx.androidstudy I/--FirstService-->: onStartCommand is running.Thread:Thread[main,5,main]
      2. 11-1602:56:28.3859039-9039/com.wanghx.androidstudy I/--FirstService-->: flags:0
      3. 11-1602:56:28.3859039-9039/com.wanghx.androidstudy I/--FirstService-->: startId:2
      4. 11-1602:56:33.9859039-9039/com.wanghx.androidstudy I/--FirstService-->: onStartCommand is running.Thread:Thread[main,5,main]
      5. 11-1602:56:33.9859039-9039/com.wanghx.androidstudy I/--FirstService-->: flags:0
      6. 11-1602:56:33.9859039-9039/com.wanghx.androidstudy I/--FirstService-->: startId:3
      7. 11-1602:56:35.5359039-9039/com.wanghx.androidstudy I/--FirstService-->: onStartCommand is running.Thread:Thread[main,5,main]
      8. 11-1602:56:35.5359039-9039/com.wanghx.androidstudy I/--FirstService-->: flags:0
      9. 11-1602:56:35.5359039-9039/com.wanghx.androidstudy I/--FirstService-->: startId:4
      我們發現flags的值沒有發生改變,而startId再按順序增加.
  4. 如何啟動一個綁定服務
    1. 在activity中創建一個內部類,繼承ServiceConnection.
      1. classMyServiceConnectionimplementsServiceConnection{
      2. @Override
      3. publicvoid onServiceConnected(ComponentName name,IBinder service){
      4. Log.i(TAG,"onServiceConnected");
      5. }
      6. @Override
      7. publicvoid onServiceDisconnected(ComponentName name){
      8. Log.i(TAG,"onServiceDisconnected");
      9. }
      10. }
       
    2. 在activity中定義一個成員connection
      1. privateMyServiceConnection connection =newMyServiceConnection();
       
    3. 在綁定服務按鈕中加入綁定代碼
      1. Intent intent3 =newIntent(ServiceActivity.this,FirstService.class);
      2. bindService(intent3, connection, BIND_AUTO_CREATE);
      按鈕點擊後列印如下日誌:
      1. I/--FirstService-->:Service is running.
      2. I/--FirstService-->: onCreate is running.
      3. I/--FirstService-->:IBinder is running.
       
    4. 在解綁服務中加入代碼,這裡的connection必須和上邊的綁定服務的connection實例一致.
      1. unbindService(connection);
       
  5. Service和Thread的關係
    1. 其實他兩個沒有一毛錢關係.只是因為service需要做耗時操作,需要重新建立一線程來處理工作,而不阻塞主線程;
    2. service是運行在主線程的;
    3. activity啟動service後,即使activity被銷毀了,如果沒有主動關閉服務,服務還是會在後臺默默運行的;
  6. 如何連接遠程的service,只需要在manifests.xml中這樣寫即可
    1. <service
    2. android:name="com.example.servicetest.MyService"
    3. android:process=":remote">
    4. </service>
    如何讓activity與遠程的service進行通信呢?這就要使用AIDL進行跨進程通信(IPC)了.
  7. AIDL:Android Interface Definition Language:Android介面定義語言,它可以用於讓多個service與多個應用程式組件之間進行跨進程通信;
  8. 這些都不是重點,我們還是弄一下在我們自己的程式中service與activity之間的通信吧;
    1. activity-->service 通過intent傳遞數據給service;
    2. activity調用onServiceConnected()中的IBind對象來訪問service中的方法;
    3. IBinder通信的關鍵是利用activity中的IBinder對象獲得service對象,然後調用方法;
      1. publicclassFirstServiceextendsService{
      2. privatestaticfinalString TAG ="FirstService-->";
      3. privateMyBinder myBinder =newMyBinder();
      4. publicFirstService(){
      5. Log.i(TAG,"Service is running.");
      6. }
      7. @Override
      8. publicvoid onCreate(){
      9. Log.i(TAG,"onCreate is running.");
      10. super.onCreate();
      11. }
      12. @Override
      13. publicint onStartCommand(Intent intent,int flags,int startId){
      14. String name = intent.getStringExtra("name");
      15. Log.i(TAG,"onStartCommand is running.Thread:"+Thread.currentThread());
      16. Log.i(TAG,"flags:"+flags);
      17. Log.i(TAG,"startId:"+startId);
      18. Log.i(TAG,"name:"+name);
      19. return START_STICKY;
      20. }
      21. @Override
      22. publicvoid onDestroy(){
      23. Log.i(TAG,"onDestroy is running.");
      24. super.onDestroy();
      25. }
      26. @Override
      27. publicIBinder onBind(Intent intent){
      28. Log.i(TAG,"IBinder is running.");
      29. return myBinder;
      30. }
      31. publicclassMyBinderextendsBinder{
      32. publicFirstService getService(){
      33. returnFirstService.this;
      34. }
      35. }
      36. publicint getRandomNumber(){
      37. returnnewRandom().nextInt(10)+1;
      38. }
      39. }
      1. publicclassServiceActivityextendsAppCompatActivityimplementsView.OnClickListener{
      2. privateMyServiceConnection connection =newMyServiceConnection();
      3. privatestaticfinalString TAG ="ServiceActivity-->";
      4. privateFirstService mFirstService;
      5. privateboolean isBinder;// 服務是否綁定
      6. @Override
      7. protectedvoid onCreate(Bundle savedInstanceState){
      8. super.onCreate(savedInstanceState);
      9. setContentView(R.layout.activity_service);
      10. findViewById(R.id.btn_start_service).setOnClickListener(this);
      11. findViewById(R.id.btn_stop_service).setOnClickListener(this);
      12. findViewById(R.id.btn_bound_service).setOnClickListener(this);
      13. findViewById(R.id.btn_unbound_service).setOnClickListener(this);
      14. findViewById(R.id.btn_get_number).setOnClickListener(this);
      15. }
      16. @Override
      17. publicvoid onClick(View v){
      18. switch(v.getId()){
      19. case R.id.btn_start_service:
      20. Intent intent =newIntent(ServiceActivity.this,FirstService.class);
      21. intent.putExtra("name","Zhangsan");
      22. startService(intent);
      23. break;
      24. case R.id.btn_stop_service:
      25. Intent intent2 =newIntent(ServiceActivity.this,FirstService.class);
      26. stopService(intent2);
      27. break;
      28. case R.id.btn_bound_service:
      29. if(!isBinder){
      30. Intent intent3 =newIntent(ServiceActivity.this,FirstService.class);
      31. bindService(intent3, connection, BIND_AUTO_CREATE);
      32. isBinder =true;
      33. }
      34. break;
      35. case R.id.btn_unbound_service:
      36. if(isBinder){
      37. unbindService(connection);
      38. isBinder =false;
      39. }
      40. break;
      41. case R.id.btn_get_number:
      42. if(mFirstService ==null){
      43. Toast.makeText(getApplicationContext(),"請先綁定服務",Toast.LENGTH_SHORT).show();
      44. }else{
      45. Toast.makeText(getApplicationContext(),"得到的隨機數為:"+ mFirstService.getRandomNumber(),Toast
      46. .LENGTH_SHORT).show();
      47. }
      48. break;
      49. }
      50. }
      51. classMyServiceConnectionimplementsServiceConnection{
      52. @Override
      53. publicvoid onServiceConnected(ComponentName name,IBinder service){
      54. Log.i(TAG,"onServiceConnected");
      55. FirstService.MyBinder myBinder =(FirstService.MyBinder) service;
      56. mFirstService = myBinder.getService();
      57. }
      58. @Override
      59. publicvoid onServiceDisconnected(ComponentName name){
      60. Log.i(TAG,"onServiceDisconnected");
      61. }
      62. }
      63. }
      這裡有一個小插曲:一起寫出來大家分享下:記得以前學java基礎時,老師曾說過一個java文件中只能有一個public類,類名稱必須與java文件名相同,為什麼這個FirstService中有兩個public類,只是因為MyBinder雖然是一個public class,但是MyBinder是一個內部類,這裡必須要用public修飾,否則其他包就訪問不到這個內部類了;



來自為知筆記(Wiz)




您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 學習資料 :http://www.cnblogs.com/wkylin/archive/2011/05/12/2044328.html 元素是文檔結構的基礎,在css裡面,每個元素生成了包含內容的框(box),大家都叫“盒子”。但是不同的元素顯示方式是不同的,有占據一整行的,有水平一個挨著一個的。比... ...
  • 今天學了跨域,迫不及待想跟大家分享!不妥之處希望大家指正。 首先來明確一下“跨域”這個概念。 跨域指的是,到外域去取數據。那什麼是“外域”呢?我們先來瞭解同域。同域指的是,同協議、同功能變數名稱、同埠。如果兩個URL,協議相同,功能變數名稱相同,埠號相同,那麼這兩個URL就屬於同域。那麼外域就是,協議不同,或者 ...
  • 先上代碼: 代碼挺簡單的,但是這一點代碼也有可能達不到預期效果。 一開始,在readWrite()函數中,我用的是註釋掉的那些代碼,沒有用紅色部分代碼,結果點擊“讀寫”按鈕後,還是不可編輯。於是就改成了紅色部分代碼,結果再點擊“讀寫”按鈕就可以編輯了。 總結了一下,當達不到預期效果時,可以使用以下幾 ...
  • 關於列表中checkbox選中,全選設置 以上代碼主要處理 1.在列表中如果選中行則選中這行的checkbox,如果再次點擊則取消選中 2.在列表中包含全選checkbox 下麵我自己加入的一段全選和反選的代碼: ...
  • 一、前言: 有時候,我們需要對一些字元串中的字元進行位置變化處理。如 “2016-11-16” 需要調整為 “16/11/2016”。我們知道有很多方法可以使用,比如split()拆分成數組後在進行拼接,也可以使用正則表達式的分組機制來進行處理。下麵我們就將這種方法進行實例對比: 二、split() ...
  • 第一步:到官網下載第三方包,拷貝到自己的項目中 https://github.com/Maxwin-z/XListView-Android 第二步:xml文件 第三步:java代碼 ...
  • 嗨!各位,小編又和大家分享知識啦,在昨天的博客筆記中小編給大家講解瞭如何去配置Android工具以及SDK中的一些配置,那在今天的學習小編會帶給大家哪些Android知識呢?首先我們看一下今天的學習目錄吧。 知識一:瞭解Android項目目錄結構 知識二:Android的配置文件(清單文件) 知識三 ...
  • 這篇博客是關於如何搭建eclipse的android開發環境, 與網上的其他博客不同,我的方法比他們簡單的多,所 以推薦給大家。 搭建eclipse的android開發環境步驟: 1.配置JDK(Java Development Kit,Java開發工具包) (因為android是基於Java語言開 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...