12.Android学习之Service应用(一)
目錄
12.Service應(yīng)用(一)
1.Service概述
1-1.Service 的分類
1-2.Service的生命周期
2.Service 的基本用法
2-1.創(chuàng)建與配置Service
2-2.啟動和停止Service
12.Service應(yīng)用(一)
1.Service概述
Service (服務(wù))是能夠在后臺長時間運行,并且不提供用戶界面的應(yīng)用程序組件。其他應(yīng)用程序組件能啟動Service,并且即便用戶切換到另一個應(yīng)用程序,Service 還可以在后臺運行。此外,組件能夠綁定到Service并與之交互,甚至執(zhí)行進程間通信(IPC)。例如,Service 能在后臺處理網(wǎng)絡(luò)事務(wù)、播放音樂、執(zhí)行文件操作或者與Content Provider通信。
1-1.Service 的分類
Service按照啟動方式可以分為以下兩種類型。
◆Started Service:當(dāng)應(yīng)用程序組件(如Activity)通過調(diào)用startService() 方法啟動Service時,Service處于啟動狀態(tài)。一旦啟動, Service 能在后臺無限期運行。
◆Bound Service:當(dāng)應(yīng)用程序組件通過調(diào)用bindService()方法綁定到Service時,Service處于綁定狀態(tài)。多個組件可以同時綁定到一個Service 上,當(dāng)它們都解除綁定時,Service 被銷毀。
Started Service與Bound Service的區(qū)別如表12.1所示。
表12.1 Started Service與Bound Service的區(qū)別
| 使用startService()方法啟動 | 調(diào)用bindService()方法綁定 |
| 通常只啟動,不返回值 | 發(fā)送請求,得到返回值 |
| 啟動Service的組件與Service之間沒有關(guān)聯(lián),即使關(guān)閉該組件,Service也會一直運行 | 啟動Service的組件與Service綁定在一起, 如果關(guān)閉該組件,Service就會停止運行。 |
| 回調(diào)onStartCommand()方法,允許組件啟動Service | 目調(diào)onBind()方法,允許組件綁定Service |
注:Service可以同時屬于這兩種類型,既可以啟動(無限期運行)又能綁定。不管應(yīng)用程序是否為啟動狀態(tài)、綁定狀態(tài)或者兩者兼有,都能通過Intent對象使用Service,就像使用Activity那樣。然而,開發(fā)人員可以在配置文件中將Service聲明為私有的,從而阻止其他應(yīng)用程序訪問。
1-2.Service的生命周期
Service的生命周期比Activity簡單很多,但是卻需要開發(fā)人員更加關(guān)注Service如何創(chuàng)建和銷毀,因為Service可能在用戶不知情的情況下在后臺運行。
Service的生命周期可以分成兩個不同的路徑:
◆通過startService()方法啟動Service
當(dāng)其他組件調(diào)用startService()方法時,Service 被創(chuàng)建,并且無限期運行,其自身必須調(diào)用stopSelf()方法或者其他組件調(diào)用stopService()方法來停止Service。當(dāng)Service停止時,系統(tǒng)將其銷毀。
◆通過bindService()方法啟動Service
當(dāng)其他組件調(diào)用bindService()方法時,Service 被創(chuàng)建,接著客戶端通過IBinder接口與Service通信,客戶端通過unbindService()方法關(guān)閉連接。多個客戶端能綁定到同一個Service,并且當(dāng)它們都解綁定時,系統(tǒng)銷毀Service (Service 不需要被停止)。
這兩條路徑并非完全獨立,即開發(fā)人員可以綁定已經(jīng)使用startService()方法啟動的Service。例如,后臺音樂Service能使用包含音樂信息的Intent 通過調(diào)用startService()方法啟動。當(dāng)用戶需要控制播放器或者獲得當(dāng)前音樂信息時,可以調(diào)用bindService()方法綁定Activity到Service。此時,只有stopService()和stopSelf()方法全部被客戶端解綁定時才能停止Service。
為了創(chuàng)建Service,開發(fā)人員需要創(chuàng)建Service類或其子類的子類。在實現(xiàn)類中,需要重寫一些處理Service生命周期重要方面的回調(diào)方法,并根據(jù)需要提供組件綁定到Service的機制。需要重寫的重要回調(diào)方法如表12.2所示。
| void onCreate() | 當(dāng)Service第一次創(chuàng)建時, 系統(tǒng)調(diào)用該方法執(zhí)行一次性建立過程(在系統(tǒng)調(diào)用onStartCommand() 或onBind()方法前)。如果Service已經(jīng)運行,該方法不被調(diào)用 |
| void onStartCommand(Intent intent, int flags, int startld) | 當(dāng)其他組件(如Activity)調(diào)用startService()方法請求Service啟動時,系統(tǒng)調(diào)用該方法。一且該方法執(zhí)行,Service 就啟動并在后臺無限期運行 |
| IBinder onBind(Intent intent) | 該方法是Service子類必須實現(xiàn)的方法,該方法返回一個IBinder對象,應(yīng)用程序可以通過該對象與Service組件進行通信 |
| void onDestroy() | 當(dāng)Service不再使用并即將銷毀時,系統(tǒng)調(diào)用該方法 |
2.Service 的基本用法
應(yīng)用程序組件(如Activity)能通過調(diào)用startService() 方法和傳遞Intent對象來啟動Service。在Intent對象中指定了Service 并且包含Service 需要使用的全部數(shù)據(jù)。Service 使用onStartCommand() 方法接收Intent。
Android提供了兩個類供開發(fā)人員繼承用于創(chuàng)建和啟動Service。
◆Service:這是所有Service 的基類。當(dāng)繼承該類時,創(chuàng)建新線程來執(zhí)行Service的全部工作是非常重要的。因為Service默認使用應(yīng)用程序主線程,這可能降低應(yīng)用程序Activity 的運行性能。
◆IntentService:這是Service 類的子類,它每次使用一個Worker線程來處理全部啟動請求。在不必同時處理多個請求時,這是最佳選擇。開發(fā)人員僅需要實現(xiàn)onHandleIntent() 方法,該方法接收每次啟動請求的Intent以便完成后臺任務(wù)。
2-1.創(chuàng)建與配置Service
使用Android Studio可以很方便地創(chuàng)建并配置Service,具體步驟如下:
在Module的包名(如com.example)節(jié)點上單擊鼠標右鍵,然后依次選擇New->Service->Service菜單項。
?注:如果選擇New->Service->Service(IntentService)菜單項,可以創(chuàng)建繼承IntentService的Service。
創(chuàng)建完成Service后,通常情況下,經(jīng)常會重寫以下3個方法:
◆onCreate():在Service創(chuàng)建時調(diào)用。
◆onStartCommand():在每次啟動Service時調(diào)用。
◆onDestroy():在Service銷毀時調(diào)用。
例如,在創(chuàng)建的MyService中重寫這3個方法,實現(xiàn)開啟新線程模擬一段耗時操作,同時監(jiān)控Service的狀態(tài),具體代碼如下:
package com.example.demo01; ? import android.app.ActivityManager; import android.app.Service; import android.content.Context; import android.content.Intent; import android.os.IBinder; import android.util.Log; ? import java.util.ArrayList; ? public class MyService extends Service { ?public MyService() {} ?@Overridepublic IBinder onBind(Intent intent) {// TODO: Return the communication channel to the service.throw new UnsupportedOperationException("Not yet implemented");} ?@Overridepublic void onCreate() {Log.i("Service","Service已創(chuàng)建");super.onCreate();} ?@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {new Thread(new Runnable() {@Overridepublic void run() {Log.i("Service","Service已開啟");//模擬一段耗時任務(wù)long endTime=System.currentTimeMillis()+5*1000;while (System.currentTimeMillis()<endTime){synchronized (this){try {wait(endTime-System.currentTimeMillis());} catch (InterruptedException e) {e.printStackTrace();}}}stopSelf();//停止Service}}).start();return super.onStartCommand(intent, flags, startId);} ?@Overridepublic void onDestroy() {Log.i("Service","Service已停止");super.onDestroy();} }在創(chuàng)建Service之后,系統(tǒng)會自動在AndroidManifest.xml文件中配置Service,配置Service使用<service></service>標記。
?其中,enabled、exported兩個屬性的說明如下:
◆android:enabled
用于指定Service能否被實例化,true表示能,false表示不能,默認值是true。<application>標記也有自己的enabled屬性,適用于應(yīng)用中所有的組件。當(dāng)Service被啟用時,只有<application>和<service>標記的enabled屬性同時設(shè)置為true(兩者的默認值都是true)時,才能讓S<service>可用,非且能被實例化;任何一個是false,Service 都將被禁用。
◆android:exported
用于指定其他應(yīng)用程序組件能否調(diào)用Service或者與其交互,true 表示能,false 表示不能。當(dāng)該值是false時,只有同一個應(yīng)用程序的組件或者具有相同用戶ID的應(yīng)用程序啟動或者綁定到Service。
android:exported屬性的默認值依賴于Service是否包含Intent過濾器。若沒有過濾器,說明Service僅能通過精確類名調(diào)用,這意味著Service僅用于應(yīng)用程序內(nèi)部(因為其他程序可能不知道類名)。此時,默認值是false;若存在至少一個過濾器,暗示Service可以用于外部,因此默認值是true。
2-2.啟動和停止Service
1.啟動Service
可以通過Activity或者其他應(yīng)用程序組件將Intent對象(要啟動的Service)傳遞到startService()方法中來啟動Service。Android 系統(tǒng)調(diào)用Service的onStartCommand()方法并將Intem傳遞給它。
例如,Activity 能使用顯式Intent和startService()方法啟動2-1小節(jié)中創(chuàng)建的Service(MyService),其代碼如下:
Intent Intent = new Intent(this,Myservice.class); ? startService(Intent);啟動MyService后,在Logcat中會輸出如圖所示的日志信息。
?在執(zhí)行startService()方法后,Android 系統(tǒng)調(diào)用Service的onStartCommand()方法。如果Service還沒有運行,系統(tǒng)首先調(diào)onCreate()方法,接著調(diào)用onStartCommand()方法。
如果Service沒有提供綁定,startService() 方法發(fā)送的Intent 是應(yīng)用程序組件和Service之間唯一的通信模式。然而,如果需要Service返回結(jié)果,則啟動該Service的客戶端能為廣播創(chuàng)建PendingIntent(使用getBradcast()方法)并通過啟動Service的Intent進行發(fā)送。Service接下來便能使用廣播來發(fā)送結(jié)果。
多次啟動Service的請求會導(dǎo)致Service的onStartCommand()方法被多次調(diào)用。
2.停止Service
已啟動的Service必須管理自己的生命周期,系統(tǒng)不會停止或銷毀Service,除非系統(tǒng)必須回收系統(tǒng)內(nèi)存而且在onStartCommand()方法返回后Service繼續(xù)運行。因此,Service 必須調(diào)用stopSelf() 方法停止自身,或者其他組件調(diào)用stopService()方法停止Service。當(dāng)多次啟動Service后,僅需要一個停止方法來停止Service。
當(dāng)使用stopSelf()或stopService()方法請求停止時,系統(tǒng)會盡快銷毀Service。
注:應(yīng)用程序應(yīng)該在任務(wù)完成后停止Service,來避免系統(tǒng)資源浪費和電池消耗。即便是綁定Service,如果調(diào)用了onStartCommand()方法也必須停止Service。
例:
?MusicService.java
package com.example.backgroundmusicservice; ? import android.app.Service; import android.content.Intent; import android.media.MediaPlayer; import android.os.IBinder; ? public class MusicService extends Service {public MusicService() {}static boolean isplay;//定義當(dāng)前播放狀態(tài)MediaPlayer mediaPlayer;//聲明MediaPlayer對象 ?@Overridepublic IBinder onBind(Intent intent) {// TODO: Return the communication channel to the service.throw new UnsupportedOperationException("Not yet implemented");} ?@Overridepublic void onCreate() {super.onCreate();//創(chuàng)建MediaPlayer對象并加載播放的音樂文件mediaPlayer=MediaPlayer.create(this,R.raw.music);} ?/******************實現(xiàn)音樂播放********************/@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {if(!mediaPlayer.isPlaying()){//如果沒有播放音樂mediaPlayer.start();//播放音樂isplay=mediaPlayer.isPlaying();//當(dāng)前狀態(tài)為正在播放音樂}return super.onStartCommand(intent, flags, startId);}/************************************************/ ?@Overridepublic void onDestroy() {mediaPlayer.stop();//停止音樂播放isplay=mediaPlayer.isPlaying();//當(dāng)前狀態(tài)為沒有播放音樂mediaPlayer.release();//釋放資源super.onDestroy();} }MainActivity.java
package com.example.backgroundmusicservice; ? import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AppCompatActivity; ? import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.ImageButton; ? public class MainActivity extends AppCompatActivity { ?@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ActionBar actionBar=getSupportActionBar();actionBar.hide(); ?ImageButton imageButton=findViewById(R.id.main_ib1);Intent intent=new Intent(MainActivity.this,MusicService.class); ?imageButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {//啟動和停止MusicServiceif(MusicService.isplay==false){startService(intent);//啟動Service((ImageButton)view).setImageDrawable(getResources().getDrawable(R.drawable.play,null));}else {stopService(intent);//停止Service((ImageButton)view).setImageDrawable(getResources().getDrawable(R.drawable.stop,null));}}});} ?@Overrideprotected void onStart() {startService(new Intent(MainActivity.this,MusicService.class));//設(shè)置進入頁面默認啟動Servicesuper.onStart();} }注:如果沒有停止Service,即使關(guān)閉當(dāng)前應(yīng)用,音樂也將繼續(xù)播放。
總結(jié)
以上是生活随笔為你收集整理的12.Android学习之Service应用(一)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何进行WEB安全测试
- 下一篇: 【计算机毕业设计】交通事故档案管理系统