1. 程式人生 > >Android四大基本元件-Service詳解

Android四大基本元件-Service詳解

一、官方文件

Class Overview
A Service is an application component representing either an application’s desire to perform a longer-running operation while not interacting with the user or to supply functionality for other applications to use. Each service class must have a corresponding declaration in its package’s AndroidManifest.xml. Services can be started with Context.startService() and Context.bindService().


服務是一種應用程式元件代表應用程式的意圖,而不是與使用者或其他應用程式使用電源的功能執行更長的執行操作。每個服務類必須有一個相應的服務宣告在其AndroidManifest.xml。啟動服務的方法有startservice(), bindservice()。後面會有具體事例測試這兩種方法的使用。

Note that services, like other application objects, run in the main thread of their hosting process. This means that, if your service is going to do any CPU intensive (such as MP3 playback) or blocking (such as networking) operations, it should spawn its own thread in which to do that work. More information on this can be found in Application Fundamentals: Processes and Threads. The IntentService class is available as a standard implementation of Service that has its own thread where it schedules its work to be done.


注意,服務是執行在他們的主程序的主執行緒。這意味著,如果你的服務是要做任何CPU消耗大的操作(如MP3播放)或阻塞(如網路)的操作,它會以它自己的執行緒去做這項工作。關於這方面的更多資訊可以在應用基礎:程序和執行緒。intentservice類可以作為一個標準的服務實現,可以排程自己的執行緒去工作。

What is a Service?
Most confusion about the Service class actually revolves around what it is not:

  • A Service is not a separate process. The Service object itself does not imply it is running in its own process; unless otherwise specified, it runs in the same process as the application it is part of.
  • A Service is not a thread. It is not a means itself to do work off of the main thread (to avoid Application Not Responding errors).
    這裡要說的是我們不僅要知道service是什麼,還要知道它不是什麼.
  • 服務不是一個單獨的程序。服務物件本身並不意味著它是在它自己的程序中執行;除非另有規定,它執行在同一程序中的應用就是它的一部分。
  • 服務不是一個執行緒。這並不意味著主執行緒去完成相應工作(避免應用程式無響應的錯誤)

    Thus a Service itself is actually very simple, providing two main features:

  • A facility for the application to tell the system about something it wants to be doing in the background (even when the user is not directly interacting with the application). This corresponds to calls to Context.startService(), which ask the system to schedule work for the service, to be run until the service or someone else explicitly stop it.

  • A facility for an application to expose some of its functionality to other applications. This corresponds to calls to Context.bindService(), which allows a long-standing connection to be made to the service in order to interact with it.
  • 用於告訴系統什麼要在後臺執行(即使用者不直接與應用程式互動),呼叫Context.startService() 啟動服務,這要求系統來管理該服務,該服務會一直執行到知道明確停止它為止,即stopService()。
  • 一個應用程式提供它的一些功能給其他的應用。可以呼叫Context.bindService()來繫結服務,它允許一個長期的連線是為了服務與它進行互動。(操作中會獲得service的binder物件,通過binder來呼叫相關的服務)

    When a Service component is actually created, for either of these reasons, all that the system actually does is instantiate the component and call its onCreate() and any other appropriate callbacks on the main thread. It is up to the Service to implement these with the appropriate behavior, such as creating a secondary thread in which it does its work.
    Note that because Service itself is so simple, you can make your interaction with it as simple or complicated as you want: from treating it as a local Java object that you make direct method calls on (as illustrated by Local Service Sample), to providing a full remoteable interface using AIDL.
    當一個服務元件被創造時,系統都會呼叫它的oncreate()和主執行緒的任何其他適當的回撥。它是由服務來實現這些與適當的行為,如建立一個輔助執行緒來完成它的工作。
    值得注意的是,由於服務本身那麼簡單,你可以用service與其他應用或其他元件實現一些或簡單或複雜的互動:比如要為本地Java物件你直接呼叫方法,也可以呼叫AIDL介面進行程序間操作。

Service Lifecycle 服務的生命週期

There are two reasons that a service can be run by the system. If someone calls Context.startService() then the system will retrieve the service (creating it and calling its onCreate() method if needed) and then call its onStartCommand(Intent, int, int) method with the arguments supplied by the client. The service will at this point continue running until Context.stopService() or stopSelf() is called. Note that multiple calls to Context.startService() do not nest (though they do result in multiple corresponding calls to onStartCommand()), so no matter how many times it is started a service will be stopped once Context.stopService() or stopSelf() is called; however, services can use their stopSelf(int) method to ensure the service is not stopped until started intents have been processed.
有兩個理由可以說明服務可以被系統執行。如果有人Context.startService()來啟動服務。然後系統會檢索服務(創造它,如果需要呼叫它的oncreate()方法)然後呼叫onStartCommand(Intent, int, int) 方法。然後該服務將一直執行,直到stopservice()或stopself()被呼叫。請注意,當服務啟動後,再呼叫Context.startService() 方法時,(onstartcommand()會被呼叫oncreate()方法不會再次被呼叫,也就是說服務只會被建立一次,然呼叫stopservice()或stopself()會停止服務;然而,服務可以用stopSelf(int)來保證服務直到成功開啟意圖之後才停止。

For started services, there are two additional major modes of operation they can decide to run in, depending on the value they return from onStartCommand(): START_STICKY is used for services that are explicitly started and stopped as needed, while START_NOT_STICKY or START_REDELIVER_INTENT are used for services that should only remain running while processing any commands sent to them.
為啟動的服務,有兩個主要的操作模式,他們可以決定執行,取決於他們的回報onstartcommand()價值:start_sticky用於顯式啟動和停止所需要的服務,而start_not_sticky或start_redeliver_intent用於服務,應執行在處理任何命令傳送給他們。

Clients can also use Context.bindService() to obtain a persistent connection to a service. This likewise creates the service if it is not already running (calling onCreate() while doing so), but does not call onStartCommand(). The client will receive the IBinder object that the service returns from its onBind(Intent) method, allowing the client to then make calls back to the service. The service will remain running as long as the connection is established (whether or not the client retains a reference on the service’s IBinder). Usually the IBinder returned is for a complex interface that has been written in aidl.
客戶端也可以使用Context.bindService() 獲得持久連線到服務。這同樣造成服務如果它沒有執行(雖然這樣叫oncreate()),但不呼叫onstartcommand()。客戶端將從onBind(Intent)方法得到IBinder物件,讓繫結者可以呼叫相關服務。該服務被建立後將和繫結者保持連線(不管客戶端是否仍保留服務的IBinder)。通常返回的是一個複雜的介面,這個已經在AIDL中實現。

A service can be both started and have connections bound to it. In such a case, the system will keep the service running as long as either it is started or there are one or more connections to it with the Context.BIND_AUTO_CREATE flag. Once neither of these situations hold, the service’s onDestroy() method is called and the service is effectively terminated. All cleanup (stopping threads, unregistering receivers) should be complete upon returning from onDestroy().
對於一個服務的繫結者,服務既可以被開啟,也可以被連線。在這種情況下,系統會保持服務的執行只要是開始或有一個或多個連線到它的context.bind_auto_create標識。一旦這些情況都存在,服務的ondestroy()方法被呼叫後,服務才會有效終止。這樣,所有的清理(停止執行緒,登出接收器)等方法都可以解除安裝ondestroy()中。

Process Lifecycle 程序週期

The Android system will attempt to keep the process hosting a service around as long as the service has been started or has clients bound to it. When running low on memory and needing to kill existing processes, the priority of a process hosting the service will be the higher of the following possibilities:
Android系統會試圖讓程序託管服務當這個服務被開啟或被繫結時。在低記憶體的時候需要殺死現有的程序,一個託管了服務將的程序優先順序更高:

If the service is currently executing code in its onCreate(), onStartCommand(), or onDestroy() methods, then the hosting process will be a foreground process to ensure this code can execute without being killed.
如果服務是目前正在執行oncreate()、onstartcommand()或ondestroy()方法,然後宿主程序將變成前臺程序以確保這些方法能被執行而不被殺死。

If the service has been started, then its hosting process is considered to be less important than any processes that are currently visible to the user on-screen, but more important than any process not visible. Because only a few processes are generally visible to the user, this means that the service should not be killed except in extreme low memory conditions.
如果此服務已被啟動,任何可見程序都比它的宿主程序更重要,但比那些不可見的程序都要重要。因為只有很少的程序是可見程序,這表明服務應該不會在極端低記憶體情況下被殺死。

If there are clients bound to the service, then the service’s hosting process is never less important than the most important client. That is, if one of its clients is visible to the user, then the service itself is considered to be visible.
如果有客戶端繫結到服務,那麼服務的宿主程序比這些重要的客戶端還重要。也就是說,如果繫結它的一個客戶端是使用者可見的,那麼服務本身是可見的。

A started service can use the startForeground(int, Notification) API to put the service in a foreground state, where the system considers it to be something the user is actively aware of and thus not a candidate for killing when low on memory. (It is still theoretically possible for the service to be killed under extreme memory pressure from the current foreground application, but in practice this should not be a concern.)
一個啟動的服務可以使用startForeground(int, Notification) API把服務設定為前臺狀態,系統認為是使用者的主動意識,所以在記憶體不足時,該服務並不是被殺候選人。(這仍然是理論上可能的,在記憶體極端不足時,即便是前臺service也有可能被殺。)

Note this means that most of the time your service is running, it may be killed by the system if it is under heavy memory pressure. If this happens, the system will later try to restart the service. An important consequence of this is that if you implement onStartCommand() to schedule work to be done asynchronously or in another thread, then you may want to use START_FLAG_REDELIVERY to have the system re-deliver an Intent for you so that it does not get lost if your service is killed while processing it.
注意,大部分時間你的服務一直在執行,在記憶體壓力非常大的時候它也會被殺死。如果發生這種情況,系統將嘗試重新啟動服務。這是一個重要的結果,如果你實現onstartcommand()安排工作要在另一個執行緒非同步完成,那麼你可能想使用start_flag_redelivery讓系統為你提供一個意圖使它不會丟失之前的服務。

二、具體例項

1.最基本的用法

package com.servicedetail;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void StartService(View v) {
        Intent startIntent = new Intent(this, MyService.class);
        startService(startIntent);

    }

    public void StopService(View v) {
        Intent startIntent = new Intent(this, MyService.class);
        stopService(startIntent);
    }
}
package com.servicedetail;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

public class MyService extends Service {

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i("--","onCreate");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i("--","onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }


    @Override
    public IBinder onBind(Intent intent) {
        Log.i("--","onBind");
        return null;
    }

    @Override
    public void onDestroy() {
        Log.i("--","onDestroy");
        super.onDestroy();
    }
    @Override
    public boolean onUnbind(Intent intent) {
        Log.i("--","onUnbind");
        return super.onUnbind(intent);
    }

    @Override
    public void onRebind(Intent intent) {
        Log.i("--","onRebind");
        super.onRebind(intent);
    }

}

—–>最簡單的startService, stopService
第一次點選startService,stopService:
這裡寫圖片描述
在destroy之前點選兩次startService,只會呼叫一次onCreate方法
這是由於onCreate()方法只會在Service第一次被建立的時候呼叫,如果當前Service已經被建立過了,不管怎樣呼叫startService()方法,onCreate()方法都不會再執行。因此你可以再多點選幾次StartService按鈕試一次,每次都只會有onStartCommand()方法中的列印日誌
這裡寫圖片描述

2.Service和Activity通訊

上面我們學習了Service的基本用法,啟動Service之後,就可以在onCreate()或onStartCommand()方法裡去執行一些具體的邏輯了。不過這樣的話Service和Activity的關係並不大,只是Activity通知了Service一下:“你可以啟動了。”然後Service就去忙自己的事情了。那麼有沒有什麼辦法能讓它們倆的關聯更多一些呢?比如說在Activity中可以指定讓Service去執行什麼任務。當然可以,只需要讓Activity和Service建立關聯就好了。
觀察MyService中的程式碼,你會發現一直有一個onBind()方法我們都沒有使用到,這個方法其實就是用於和Activity建立關聯的,修改MyService中的程式碼,如下所示:

package com.servicedetail;
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.util.Log;
import android.view.View;

public class MainActivity extends Activity {

    private MyService.MyBinder myBinder;

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.i("--", "MainActivity-->onServiceConnected");
            myBinder = (MyService.MyBinder) service;
            myBinder.conServer();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.i("--", "MainActivity-->onServiceDisconnected");
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void StartService(View v) {
        Intent startIntent = new Intent(this, MyService.class);
        startService(startIntent);

    }

    public void StopService(View v) {
        Intent startIntent = new Intent(this, MyService.class);
        stopService(startIntent);
    }

    public void BindService(View v) {
        Intent bindIntent = new Intent(this, MyService.class);
        bindService(bindIntent, connection, BIND_AUTO_CREATE);
    }

    public void UnbindService(View v) {
        if (connection != null)
            unbindService(connection);
    }
}

執行效果:
(1):點選BindService
這裡寫圖片描述
再點選UnbindService
這裡寫圖片描述
—>可以看到activity和service建立連線了,而且這種步驟會destroy掉service。

(2):點選startService,在點選BindService ,再點選UnbindService,可以看到不會destroy掉service
這裡寫圖片描述
如果再點選stopService就會destroy service。

3.如何銷燬Service

在Service的基本用法這一部分,我們介紹了銷燬Service最簡單的一種情況,點選Start Service按鈕啟動Service,再點選Stop Service按鈕停止Service,這樣MyService就被銷燬了,可以看到列印日誌如下所示:

Service-->onCreateService
Service-->onStartCommand
Service-->onDestroy

那麼如果我們是點選的Bind Service按鈕呢?由於在繫結Service的時候指定的標誌位是BIND_AUTO_CREATE,說明點選Bind Service按鈕的時候Service也會被建立,這時應該怎麼銷燬Service呢?其實也很簡單,點選一下Unbind Service按鈕,將Activity和Service的關聯解除就可以了。
先點選一下Bind Service按鈕,再點選一下Unbind Service按鈕,列印日誌如下所示:

Service-->onCreate
Service-->onBind
Service-->onUnbind
Service-->onDestroy

以上這兩種銷燬的方式都很好理解。那麼如果我們既點選了Start Service按鈕,又點選了Bind Service按鈕會怎麼樣呢?這個時候你會發現,不管你是單獨點選Stop Service按鈕還是Unbind Service按鈕,Service都不會被銷燬,必要將兩個按鈕都點選一下,Service才會被銷燬。也就是說,點選Stop Service按鈕只會讓Service停止,點選Unbind Service按鈕只會讓Service和Activity解除關聯,一個Service必須要在既沒有和任何Activity關聯又處理停止狀態的時候才會被銷燬。

4.建立前臺Service

Service幾乎都是在後臺執行的,一直以來它都是默默地做著辛苦的工作。但是Service的系統優先順序還是比較低的,當系統出現記憶體不足情況時,就有可能會回收掉正在後臺執行的Service。如果你希望Service可以一直保持執行狀態,而不會由於系統記憶體不足的原因導致被回收,就可以考慮使用前臺Service。前臺Service和普通Service最大的區別就在於,它會一直有一個正在執行的圖示在系統的狀態列顯示,下拉狀態列後可以看到更加詳細的資訊,非常類似於通知的效果。當然有時候你也可能不僅僅是為了防止Service被回收才使用前臺Service,有些專案由於特殊的需求會要求必須使用前臺Service,比如QQ或微信等聊天的會在通知欄提示收到資訊。

在onCreate()方法中或onBind()方法中新增如下程式碼:

Notification notification = new Notification(R.drawable.ic_launcher,    "有通知到來", System.currentTimeMillis());
        Intent notificationIntent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
                notificationIntent, 0);
        notification.setLatestEventInfo(this, "通知標題", "通知內容", pendingIntent);
        startForeground(1, notification);

在開啟服務要呼叫startService()後,在通知欄會保持一個通知(只要不呼叫stopService(),就會一直處在通知欄);,這是即使程式關閉,都不會消失。 如果呼叫bindService,程式關閉,服務就會關閉。
這裡寫圖片描述

最後需要注意的是:
上面的官方文件已經說了,service不是一個單獨的執行緒,也就是說service就在主執行緒中,所以如果要處理耗時操作的話,主執行緒肯定會卡。所以,在service中處理耗時操作也要新開一個執行緒。那為什麼不直接在activity中開一個執行緒來處理呢?

原因有:
1.activity難以控制執行緒,一旦activity銷燬後,之前建立的程序就無法再次獲得。
2.在一個activity中建立的執行緒無法被另一個activity操作。
3.Service可以很好的管理執行緒,即使activity銷燬了,只要再次繫結service還可以通過service操作處理事務的執行緒。

原始碼

相關推薦

Android四大基本元件-Service

一、官方文件 Class Overview A Service is an application component representing either an application’s desire to perform a longer-runn

Android四大元件--Service

Service 作為 Android 四大元件之一,可以說是一個合格的 Android 應用的基石。它主要用於在後臺處理一些耗時的邏輯,或者去執行某些需要長期執行的任務。必要的時候我們甚至可以在程式退出的情況下,依然讓 Service 在後臺保持執行狀態。

[Android]Android四大基本元件介紹與生命週期

http://www.cnblogs.com/bravestarrhu/archive/2012/05/02/2479461.html Android四大基本元件介紹與生命週期 Android四大基本元件分別是Activity,S

Android四大基本元件介紹與生命週期

Android四大基本元件分別是Activity,Service服務,Content Provider內容提供者,BroadcastReceiver廣播接收器。 一:瞭解四大基本元件 Activity : 應用程式中,一個Activity通常就是一個單獨的螢幕,它上面可

Android四大基本元件介紹以及四大元件的生命週期

這次認真閱讀了別人寫的Android四大基本元件的介紹以及四大元件的生命週期。別人寫得真的是很好。所以把連結記錄下來,以後可以再次的複習。http://www.cnblogs.com/bravestarrhu/archive/2012/05/02/2479461.html;

Android原生控制元件---ActionBar

昨天去面試了,第一次出去面試,被問到好幾個我不好回答上來的題,例如OOM的處理啊,AndroidStudio的gradle配置,actionBar的使用,ViewPager 巢狀ViewPager等等

Android開發之基本控制元件四種佈局方式

Android中的控制元件的使用方式和iOS中控制元件的使用方式基本相同,都是事件驅動。給控制元件新增事件也有介面回撥和委託代理的方式。今天這篇部落格就總結一下Android中常用的基本控制元件以及佈局方式。說到佈局方式Android和iOS還是區別挺大的,在iOS中有F

Android開發的之基本控制元件四種佈局方式

Android中的控制元件的使用方式和iOS中控制元件的使用方式基本相同,都是事件驅動。給控制元件新增事件也有介面回撥和委託代理的方式。今天這篇部落格就總結一下Android中常用的基本控制元件以及佈局方式。說到佈局方式Android和iOS還是區別挺大的,在iOS中有Frame絕對佈局和AutoL

學習筆記之Android四大核心元件

概述 Android四大核心元件指的是Activity,Service,ContentProvider,BroadCastReceiver,核心元件都是由Android系統進行管理和維護的,一般都要在清單檔案中進行註冊或者在程式碼中動態註冊。 Activ

Android四大元件--Activity

本文的主要內容包括1、activity的建立、配置和使用;2、activity的跳轉和傳值;3、startActivityForResult;4、activity的生命週期。 1、activity的建立、配置和使用 Activity是一個應用中的元件,它為使用者提供一個可視

Android中的Service

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

Android架構元件WorkManager

       WorkManager架構元件是用來管理後臺工作任務。這個時候你可能會奇怪了Android不是已經 有很多管理後臺任務的類了麼,比如JobScheduler, AlarmManger、在比如AsyncTask, ThreadPool。Wo

Android Service

各位肯定知道 Service 作為 Android 的四大元件之一是非常重要的。不過說實話,我實際開發專案中服務用的並不多,(可能和需求有關吧)但是筆試的時候,幾乎是必出的題目了,所以我們今天就來仔細的回顧一下 Service 。 1. 什麼是服務? Service 

android開發之wheel控制元件使用

出門在外生不起病呀,隨便兩盒藥60多塊錢。好吧,不廢話了,今天我們來看看wheel控制元件的使用,這是GitHub上的一個開源控制元件,用起來十分方便,我們可以用它做許多事情,比如做一個自定義的datepicker,在一些電商App中,經常用它來做省市縣三級聯動,總之用途還是

阿里Android開發規範:四大基本元件

以下內容摘自 阿里巴巴Android開發手冊 我們的目標是: 防患未然,提升質量意識,降低故障率和維護成本; 標準統一,提升協作效率; 追求卓越的工匠精神,打磨精品程式碼。 【強制】必須遵守,違反本約定或將會引起嚴重的後果; 【推薦】儘量遵守,長期遵守有助

Android 五大基本元件Service

 把service的一些特性總結一下,基本知識就不介紹了.   1、主要在後臺執行。   2、分兩種型別:   remote和location(遠端和本地)   區別:遠端的可以用在不同程序間訪問,通過aidl實現(aidl以後介紹),當訪問的程序結束掉後,還可以在後臺繼續

android自定義控制元件屬性

1. reference:參考某一資源ID。      (1)屬性定義:               <declare-styleable name = "名稱">                    <attr name = "background"

AndroidService

1. 簡介 與前一篇Android之Activity的細枝末節是同一系列的文章,是自己在學習和研發過程中,對Service的一些知識點的總結,彙總得到這篇文章。 這篇文章會從Service的一些小知識點,延伸到Android中幾種常用程序間通訊方法。

Android Studio使用教程圖文

識別 由於 group 之前 而是 ces doc java代碼 風格 Android Studio是一款非常專業的Android集成開發環境工具,那麽,Android Studio怎麽用呢?針對不知道Android Studio怎麽使用的朋友們,本文就為大家圖文詳細介紹A

Android中的windowSoftInputMode屬性

stun -h oid 中文意思 ecif andro 標題 進行 模式 如何實現軟鍵盤不自動彈出,使用的方法是設置android:windowSoftInputMode屬性。那麽,這個屬性到底是幹什麽的,他有什麽作用呢?今天這篇文章,就是探索android:win