服務(wù)是一個(gè)后臺(tái)運(yùn)行的組件,執(zhí)行長(zhǎng)時(shí)間運(yùn)行且不需要用戶交互的任務(wù)。即使應(yīng)用被銷毀也依然可以工作。服務(wù)基本上包含兩種狀態(tài) -
狀態(tài) | 描述 |
---|---|
Started | Android的應(yīng)用程序組件,如活動(dòng),通過startService()啟動(dòng)了服務(wù),則服務(wù)是Started狀態(tài)。一旦啟動(dòng),服務(wù)可以在后臺(tái)無(wú)限期運(yùn)行,及時(shí)啟動(dòng)它的組件已經(jīng)被銷毀。 |
Bound | 當(dāng)Android的應(yīng)用程序組件通過bindService()綁定了服務(wù),則服務(wù)是Bound狀態(tài)。Bound狀態(tài)的服務(wù)提供了一個(gè)客戶服務(wù)器接口來(lái)允許組件與服務(wù)進(jìn)行交互,如發(fā)送請(qǐng)求,獲取結(jié)果,甚至通過IPC來(lái)進(jìn)行跨進(jìn)程通信。 |
服務(wù)擁有生命周期方法,可以實(shí)現(xiàn)監(jiān)控服務(wù)狀態(tài)的變化,可以在合適的階段執(zhí)行工作。下面的左圖展示了當(dāng)服務(wù)通過startService()被創(chuàng)建時(shí)的聲明周期,右圖則顯示了當(dāng)服務(wù)通過bindService()被創(chuàng)建時(shí)的生命周期:
要?jiǎng)?chuàng)建服務(wù),你需要?jiǎng)?chuàng)建一個(gè)繼承自Service基類或者它的已知子類的Java類。Service基類定義了不同的回調(diào)方法和多數(shù)重要方法。你不需要實(shí)現(xiàn)所有的回調(diào)方法。雖然如此,理解所有的方法還是非常重要的。實(shí)現(xiàn)這些回調(diào)能確保你的應(yīng)用以用戶期望的方式實(shí)現(xiàn)。
回調(diào) | 描述 |
---|---|
onStartCommand() | 其他組件(如活動(dòng))通過調(diào)用startService()來(lái)請(qǐng)求啟動(dòng)服務(wù)時(shí),系統(tǒng)調(diào)用該方法。如果你實(shí)現(xiàn)該方法,你有責(zé)任在工作完成時(shí)通過stopSelf()或者stopService()方法來(lái)停止服務(wù)。 |
onBind | 當(dāng)其他組件想要通過bindService()來(lái)綁定服務(wù)時(shí),系統(tǒng)調(diào)用該方法。如果你實(shí)現(xiàn)該方法,你需要返回IBinder對(duì)象來(lái)提供一個(gè)接口,以便客戶來(lái)與服務(wù)通信。你必須實(shí)現(xiàn)該方法,如果你不允許綁定,則直接返回null。 |
onUnbind() | 當(dāng)客戶中斷所有服務(wù)發(fā)布的特殊接口時(shí),系統(tǒng)調(diào)用該方法。 |
onRebind() | 當(dāng)新的客戶端與服務(wù)連接,且此前它已經(jīng)通過onUnbind(Intent)通知斷開連接時(shí),系統(tǒng)調(diào)用該方法。 |
onCreate() | 當(dāng)服務(wù)通過onStartCommand()和onBind()被第一次創(chuàng)建的時(shí)候,系統(tǒng)調(diào)用該方法。該調(diào)用要求執(zhí)行一次性安裝。 |
onDestroy() | 當(dāng)服務(wù)不再有用或者被銷毀時(shí),系統(tǒng)調(diào)用該方法。你的服務(wù)需要實(shí)現(xiàn)該方法來(lái)清理任何資源,如線程,已注冊(cè)的監(jiān)聽器,接收器等。 |
下面的主服務(wù)演示了每個(gè)方法的生命周期 -
package cn.uprogrammer.androidservices; import android.app.Service; import android.os.IBinder; import android.content.Intent; import android.os.Bundle; public class HelloService extends Service { /** 標(biāo)識(shí)服務(wù)如果被殺死之后的行為 */ int mStartMode; /** 綁定的客戶端接口 */ IBinder mBinder; /** 標(biāo)識(shí)是否可以使用onRebind */ boolean mAllowRebind; /** 當(dāng)服務(wù)被創(chuàng)建時(shí)調(diào)用. */ @Override public void onCreate() { } /** 調(diào)用startService()啟動(dòng)服務(wù)時(shí)回調(diào) */ @Override public int onStartCommand(Intent intent, int flags, int startId) { return mStartMode; } /** 通過bindService()綁定到服務(wù)的客戶端 */ @Override public IBinder onBind(Intent intent) { return mBinder; } /** 通過unbindService()解除所有客戶端綁定時(shí)調(diào)用 */ @Override public boolean onUnbind(Intent intent) { return mAllowRebind; } /** 通過bindService()將客戶端綁定到服務(wù)時(shí)調(diào)用*/ @Override public void onRebind(Intent intent) { } /** 服務(wù)不再有用且將要被銷毀時(shí)調(diào)用 */ @Override public void onDestroy() { } }
這個(gè)例子將通過簡(jiǎn)單地步驟為你展示如何創(chuàng)建自己的Android服務(wù)。按照下面的步驟來(lái)修改之前在Hello World實(shí)例章節(jié)中創(chuàng)建的Android應(yīng)用程序:
步驟 | 描述 |
---|---|
1 | 使用Android Studio IDE來(lái)創(chuàng)建Android應(yīng)用程序并在cn.uprogrammer.androidservices包下命名為androidservices。類似Hello World實(shí)例章節(jié)。 |
2 | 修改主活動(dòng)文件MainActivity.java來(lái)添加startService()和stopService()方法。 |
3 | 在包c(diǎn)n.uprogrammer.androidservices下創(chuàng)建新的Java文件MyService.java。這個(gè)文件將實(shí)現(xiàn)Android服務(wù)相關(guān)的方法。 |
4 | 在AndroidManifest.xml文件中使用<service.../>標(biāo)簽來(lái)定義服務(wù)。應(yīng)用程序可以有一個(gè)或多個(gè)服務(wù),沒有任何限制。 |
5 | 修改res/layout/activity_main.xml文件中的默認(rèn)布局,在線性布局中包含兩個(gè)按鈕。 |
6 | 不要對(duì)res/values/strings.xml文件中的任何常量進(jìn)行修改。Android Studio會(huì)注意字符串值。 |
7 | 啟動(dòng)Android模擬器來(lái)運(yùn)行應(yīng)用程序,并驗(yàn)證應(yīng)用程序所做改變的結(jié)果。 |
下面是主活動(dòng)文件src/cn.uprogrammer.androidservices/MainActivity.java文件所修改的內(nèi)容。這個(gè)文件包含所有基本的生命周期方法。我們添加了startService()和stopService()方法來(lái)啟動(dòng)和停止服務(wù)。
package cn.uprogrammer.androidservices; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.content.Intent; import android.view.View; public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_main, menu); return true; } // Method to start the service public void startService(View view) { startService(new Intent(getBaseContext(), MyService.class)); } // Method to stop the service public void stopService(View view) { stopService(new Intent(getBaseContext(), MyService.class)); } }
以下是src/cn.uprogrammer.androidservices/MyService.java的內(nèi)容。這個(gè)文件可以基于需求實(shí)現(xiàn)一個(gè)或多個(gè)服務(wù)關(guān)聯(lián)的方法。對(duì)于新人,我們只實(shí)現(xiàn)onStartCommand()和onDestroy() -
package cn.uprogrammer.androidservices; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.widget.Toast; public class MyService extends Service { @Override public IBinder onBind(Intent arg0) { return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { // Let it continue running until it is stopped. Toast.makeText(this, "服務(wù)已經(jīng)啟動(dòng)", Toast.LENGTH_LONG).show(); return START_STICKY; } @Override public void onDestroy() { super.onDestroy(); Toast.makeText(this, "服務(wù)已經(jīng)停止", Toast.LENGTH_LONG).show(); } }
下面將修改AndroidManifest.xml文件。這里添加<service.../>標(biāo)簽來(lái)包含我們的服務(wù):
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="cn.uprogrammer.androidservices" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="13" android:targetSdkVersion="22" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/title_activity_main" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <service android:name=".MyService" /> </application> </manifest>
以下是res/layout/activity_main.xml文件的內(nèi)容,包含兩個(gè)按鈕:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Android 服務(wù)實(shí)例" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:textSize="30dp" /> <TextView android:id="@+id/textView2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="www.uprogrammer.cn" android:textColor="#ff87ff09" android:textSize="30dp" android:layout_above="@+id/imageButton" android:layout_centerHorizontal="true" android:layout_marginBottom="40dp" /> <ImageButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/imageButton" android:src="@drawable/ic_launcher" android:layout_centerVertical="true" android:layout_centerHorizontal="true" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/button2" android:text="啟動(dòng)服務(wù)" android:onClick="startService" android:layout_below="@+id/imageButton" android:layout_centerHorizontal="true" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="停止服務(wù)" android:id="@+id/button" android:onClick="stopService" android:layout_below="@+id/button2" android:layout_alignLeft="@+id/button2" android:layout_alignStart="@+id/button2" android:layout_alignRight="@+id/button2" android:layout_alignEnd="@+id/button2" /> </RelativeLayout>
下面是res/values/strings.xml的內(nèi)容,來(lái)定義兩個(gè)新的常量:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">Android Services</string> <string name="title_activity_main">MainActivity</string> <string name="menu_settings">Settings</string> <string name="action_settings">Settings</string> </resources>
讓我們運(yùn)行剛剛修改的My Application應(yīng)用程序。我假設(shè)你已經(jīng)在安裝環(huán)境時(shí)創(chuàng)建了AVD。打開你的項(xiàng)目中的活動(dòng)文件,點(diǎn)擊工具欄中的圖標(biāo)來(lái)在Android Studio中運(yùn)行應(yīng)用程序。Android Studio在AVD上安裝應(yīng)用程序并啟動(dòng)它。如果一切順利,將在模擬器窗口上顯示如下:
現(xiàn)在點(diǎn)擊"啟動(dòng)服務(wù)"按鈕來(lái)啟動(dòng)服務(wù),這將執(zhí)行我們編寫的onStartCommand()方法,一條"服務(wù)已經(jīng)啟動(dòng)"的消息在模擬器的底部出現(xiàn),如下:
點(diǎn)擊底部的"停止服務(wù)"按鈕,可以停止服務(wù)。