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
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...