Service基礎使用(一)

来源:http://www.cnblogs.com/qifengshi/archive/2016/04/27/5440607.html
-Advertisement-
Play Games

Service基礎使用(一) 之前的文章一直介紹Activity的使用,很多知識和用法單一的配合Activity使用,這次將總結Android四大組件之二—— . 本文將要介紹以下內容: 1. Service是什麼 2. 兩種Service啟動 3. Service 前臺服務與Notificatio ...


Service基礎使用(一)

之前的文章一直介紹Activity的使用,很多知識和用法單一的配合Activity使用,這次將總結Android四大組件之二——Service.
本文將要介紹以下內容:

  1. Service是什麼
  2. 兩種Service啟動
  3. Service 前臺服務與Notification

由於篇幅可能過長,這篇就寫這個三個,下篇將介紹後臺服務,IntentService等知識。

Service是什麼

Service 是一個可以在後臺執行長時間運行操作而不使用用戶界面的應用組件。服務可由其他應用組件啟動,而且即使用戶切換到其他應用,服務仍將在後臺繼續運行。 此外,組件可以綁定到服務,以與之進行交互,甚至是執行進程間通信 (IPC)。 例如,服務可以處理網路事務、播放音樂,執行文件 I/O 或與內容提供程式交互,而所有這一切均可在後臺進行。

上面說了這麼多可以做的耗時操作,但不要真的認為Service預設會運行在子線程中,他也不運行在一個獨立的進程中,他同樣執行在UI線程中,因此,不要在Service中執行耗時操作,除非你在Service中創建了子線程來完成耗時操作。
Service不因程式切換到後臺或者用戶切換到另一個APP而停止,但如果應用程式被殺死,他當然就也消失了。

兩種Service的啟動

服務啟動分為兩種形式,一種是通過StartService()啟動Service,另一種是通過BindService(),至於先啟動在綁定這個我們最後再說。本文主要介紹的就是這兩種,這兩種有什麼區別呢?我們先看一張他們的生命周期圖片,然後在慢慢細說。
網路找的流程圖

StartService()

當應用組件(如 Activity)通過調用 startService() 啟動服務時,服務即處於“啟動”狀態。一旦啟動,服務即可在後臺無限期運行,即使啟動服務的組件已被銷毀也不受影響。 已啟動的服務通常是執行單一操作,而且不會將結果返回給調用方。例如,它可能通過網路下載或上傳文件。 操作完成後,服務會自行停止運行。

通過上面的生命周期圖也可以看出來首次啟動會創建一個Service的實例,然後依次調用onCreate()和onStartCommand(),此時Service進入運行狀態,即使你多次調用StartService()啟動Service,也不會創建新的Service對象,而是直接復用前面創建的Service對象,調用它的startCommand()方法。下麵介紹一下startService各個回調方法,我們該做什麼

onCreate():首次創建服務,系統將調用此方法來執行一次性設置程式,如果服務已經運行,則不會調用此方法
onStartCommand():啟動服務的時候,系統將會調用此方法。如果實現了此方法,則在服務工作完成後,需要主動調用stopSelf()或者stopService()來停止服務。
onDestroy(),當服務不再使用且將被銷毀時,系統將會調用此方法,服務應該實現此方法來清理所有資源。這是服務接受的最後一個調用。

下麵我將通過一個實例展示這個service的實現,以及方法調用的順序。註意,通過AS新建一個Service則不需要配置mainfest文件,否則需要加入service聲明,大概如下麵這樣。且註意始終通過顯示Intent啟動或者綁定Service,不要為他設置intent-filter

 <application ... >
      <service android:name=".ExampleService" />

  </application>

Service代碼如下:

public class TestService extends Service {
    public TestService() {
    }

    @Override
    public void onCreate() {
        super.onCreate();
        //處理一次性設置
        Log.i("TestService","onCreate被調用");
    }
    
    //必須要有這個方法
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public void onDestroy() {
        Log.i("TestService","onDestroy被調用");
        super.onDestroy();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        //處理Service邏輯
        Log.i("TestService","onStartCommand被調用");
        return super.onStartCommand(intent, flags, startId);
    }
}

Activity中佈局文件放置了一個啟動按鈕,一個停止按鈕,在onCreate()方法,實現startService,代碼如下:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        stop = (Button)findViewById(R.id.stop);
        start = (Button) findViewById(R.id.start);
        final Intent intent = new Intent(this, TestService.class);
        start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startService(intent);
            }
        });
        stop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                stopService(intent);
            }
        });

    }

調用的結果如下:

點擊啟動service按鈕後
I/TestService: onCreate被調用
I/TestService: onStartCommand被調用
點擊停止service按鈕後
I/TestService: onDestroy被調用

bindService()

當應用組件通過調用 bindService() 綁定到服務時,服務即處於“綁定”狀態。綁定服務提供了一個客戶端-伺服器介面,允許組件與服務進行交互、發送請求、獲取結果,甚至是利用進程間通信 (IPC) 跨進程執行這些操作。 僅當與另一個應用組件綁定時,綁定服務才會運行。 多個組件可以同時綁定到該服務,但全部取消綁定後,該服務即會被銷毀。

startService()一樣,首次使用bindService時綁定一個Service時,系統會實例化一個Service實例,並調用onCreate()和onBind()方法,此後如果再次使用bindService綁定Service,系統不會創建新的Service實例,也不會再調用onBInd()方法,只是會直接把IBinder對象傳遞給其他後來增加的客戶端。 如果我們解除與服務的綁定,只需調用unbindService(),此時onUnbind和onDestory方法將會被調用!這是一個客戶端的情況,假如是多個客戶端綁定同一個Service的話,情況如下 當一個客戶完成和service之間的互動後,它調用 unbindService() 方法來解除綁定。當所有的客戶端都和service解除綁定後,系統會銷毀service。(除非service也被startService()方法開啟)。但一旦調用者銷毀,Service也立即終止。下麵主要說一下onBInd這個回調方法。
第一種啟動方式並沒有直接提供Service與Activity的交互方式。第二種啟動方式即用bindService提供了Service與Activity交互方式,可以很方便的利用Ibinder實現Service與Activity的通信。關鍵在onBind方法
onBind()方法返回值是一個IBinder 對象,這個方法必須實現,通過startService返回為null,表示不調用,bindService則返回一個擴展Binder類的對象。
步驟如下:

  1. 定義一個繼承Binder類的類,在類裡面編寫想要Activity調用的方法.
  2. 生成一個該類的對象,放到onBInd()方法中返回。
    代碼例子如下:
public class TestService2 extends Service {
    public TestService2() {
    }

    public Mybinder mybinder = new Mybinder();

    public int getInfo() {
        return 123;
    }

    public class Mybinder extends Binder {
        public TestService2 getService() {
            return TestService2.this;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        Log.i("TS","onbind被調用");
        return mybinder;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i("TS","onDestory被調用");
    }

    @Override
    public void onRebind(Intent intent) {
        super.onRebind(intent);
        Log.i("TS","onRebind被調用");
    }
}

這個例子Mybinder對象中getService方法,得到這個Service對象,從而調用Service中所有方法。
在Activity中的代碼,要實現ServiceConnection類中的onServiceDisconnected和onServiceConnected方法,並且通過bindService來綁定服務,unbindService來解綁服務。
主要代碼如下:

 TestService2.Mybinder binder;
    private ServiceConnection conn = new ServiceConnection() {

        //Activity與Service斷開連接時回調該方法
        @Override
        public void onServiceDisconnected(ComponentName name) {
            System.out.println("------Service DisConnected-------");
        }

        //Activity與Service連接成功時回調該方法
        @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
            //將Service強制轉換類型為Binder,這種用法在回調中很常見。
            System.out.println("------Service Connected-------");
            binder = (TestService2.Mybinder) service;
        }
    };
    
   ...
   
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
         start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                bindService(intent, conn, Service.BIND_AUTO_CREATE);
            }
        });

        stop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                unbindService(conn);
            }
        });
        //通過binder對象就可以對我們綁定的Service進行各種操作
        status.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this,binder.getService().getInfo() + "",Toast.LENGTH_SHORT).show();
            }
        });
    }

至於調用順序,還是和流程圖一樣,就不一一詳說了。這裡已經說明瞭2種啟動Service的方式和區別。下麵將介紹一個很流行的Service應用,前臺服務。

Service 前臺服務與Notification

我們在用很多應用的時候,發現他們啟動的時候,會在通知欄生成一個和該App的通知,來繼續執行Service,比如墨跡天氣,很多音樂App.這種叫前臺服務,其實這種Service有一個很好的一點,就是不會因為Service自身的優先順序低,而被系統KILL,而前臺服務就不會。
前臺服務的寫法很容易,只需要在onCreate()中,建立一個通知,然後用startForeground()設置為前臺服務即可。
下麵直接放出代碼,結合代碼註釋看看就好了,關於通知更多的內容可以看看Notification詳解
這裡只列出Service的onCreate()部分代碼

@Override
    public void onCreate() {
        super.onCreate();
        //設定一個PendingIntent,來表示點擊通知欄時跳轉到哪裡
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), 0);
        Notification.Builder builder = new Notification.Builder(this);
        //建立一個notificationManager來管理通知的出現
        notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        //構造通知的樣式,包括圖片,標題,內容,時間。
        builder.setSmallIcon(R.mipmap.ic_launcher).
                setWhen(System.currentTimeMillis()).
                setContentTitle("我是標題").
                setContentText("我是內容").
                setTicker("在啟動時彈出一個消息").//這個Android5.0以上可能會失效
                setWhen(System.currentTimeMillis()).
                setContentIntent(contentIntent);
                //最後通過build建立好通知
        Notification notification = builder.build();
        //通過manager來顯示通知,這個1為notification的id
        notificationManager.notify(1,notification);
        //啟動為前臺服務,這個1為notification的id
        startForeground(1,notification);
    }

後續關於後臺服務和IntentService的介紹,敬請期待第二篇。


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

-Advertisement-
Play Games
更多相關文章
  • 今天,開始學習第二節!!! 工欲善其事,必先利其器 react推薦我們使用webpack來打包文件,那麼我們就用吧!(其實真心不想用啊) 至於好處網上寫的天花亂墜的,大家自行解決啊... 這節主要就學習怎麼配置webpack了,這玩意我搗鼓了整整一天才弄的一知半解,哎,腦子差就是吃虧... 1.提前 ...
  • 在寫這篇文章之前,我詢問了在唯品會和騰訊的童鞋、以及公司裡面前端大神(深哥),對於設計稿切圖的詳細方法,經過對比驗證,得出設計稿轉換頁面單位尺寸方法步驟。我分別詢問下麵四個問題: 1. 設計稿的單位是什麼,一般大小是什麼? 2. 頁面長度單位用什麼,px、em、rem,還是混合,如果用rem,htm ...
  • 查看效果:http://hovertree.com/texiao/mobile/10/或者手機掃描二維碼查看效果: 效果圖:代碼如下: 轉自:http://hovertree.com/h/bjaf/loucldil.htm 推薦:http://hovertree.com/hvtart/bjae/jf ...
  • 在我們的項目中,有大量ajax查詢表單+結果列表的頁面,由於查詢結果是ajax返回的,當用戶點擊列表的某一項進入詳情頁之後,再點擊瀏覽器回退按鈕返回ajax查詢頁面,這時大家都知道查詢頁面的表單和結果都回到了預設狀態。 如果每次返回頁面都要重新輸入查詢條件,或有甚者還得轉到列表的第幾頁,那這種體驗用 ...
  • 外部樣式為: 通過 和 是無效的 要想修改div的width,可以通過如下這種方式: 要想修改多個屬性,可以這麼做: ...
  • 當我們使用activity加fragment的時候,每個界面都要建立一個fragment,每個fragment裡面都要重寫onCreate(),onCreateView(),onActivityCreated(),方法,我們新建一個基類BaseFragment來重寫這些方法 BaseFragment ...
  • 最近開發一個項目需要用到Client(Android)透過Socket與Server通訊,網上有看到Apache封裝好的Socket通訊包,初步學習。 內容主要來源於(MINA官方教程(中文版)) 1.網路應用架構: 基於ApacheMINA的網路應用有三個層次,分別是I/O服務、I/O過濾器和I/ ...
  • Super @interface Super : NSObject @end @implementation Super (void)log{ NSLog(@"super"); } @end Child @interface Child : Super @end @implementation Ch ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...