詳解Android中Service服務(wù)的基礎(chǔ)知識(shí)及編寫方法
首先,讓我們確認(rèn)下什么是service?
service就是android系統(tǒng)中的服務(wù),它有這么幾個(gè)特點(diǎn):它無法與用戶直接進(jìn)行交互、它必須由用戶或者其他程序顯式的啟動(dòng)、它的優(yōu)先級(jí)比較高,它比處于前臺(tái)的應(yīng)用優(yōu)先級(jí)低,但是比后臺(tái)的其他應(yīng)用優(yōu)先級(jí)高,這就決定了當(dāng)系統(tǒng)因?yàn)槿鄙賰?nèi)存而銷毀某些沒被利用的資源時(shí),它被銷毀的概率很小哦。
那么,什么時(shí)候,我們需要使用service呢?
我們知道,service是運(yùn)行在后臺(tái)的應(yīng)用,對(duì)于用戶來說失去了被關(guān)注的焦點(diǎn)。這就跟我們打開了音樂播放之后,便想去看看圖片,這時(shí)候我們還不想音樂停止,這里就會(huì)用到service;又例如,我們打開了一個(gè)下載鏈接之后,我們肯定不想瞪著眼睛等他下載完再去做別的事情,對(duì)吧?這時(shí)候如果我們想手機(jī)一邊在后臺(tái)下載,一邊可以讓我去看看新聞啥的,就要用到service。
service分類:
一般我們認(rèn)為service分為兩類,本地service和遠(yuǎn)程service。
1. 本地service:顧名思義,那就是和當(dāng)前應(yīng)用在同一個(gè)進(jìn)程中的service,彼此之間擁有共同的內(nèi)存區(qū)域,所以對(duì)于某些數(shù)據(jù)的共享特別的方便和簡單;
2. 遠(yuǎn)程service:主要牽扯到不同進(jìn)程間的service訪問。因?yàn)閍ndroid的系統(tǒng)安全的原因?qū)е铝宋覀冊(cè)诓煌倪M(jìn)程間無法使用一般的方式共享數(shù)據(jù)。在這里android為我們提供了一個(gè)AIDL工具。(android interface description language)android接口描述語言。在后邊我們將會(huì)對(duì)其進(jìn)行詳細(xì)的介紹。
Service啟動(dòng)流程
context.startService() 啟動(dòng)流程:
context.startService() -> onCreate() -> onStart() -> Service running -> context.stopService() -> onDestroy() -> Service stop
如果Service還沒有運(yùn)行,則android先調(diào)用onCreate(),然后調(diào)用onStart();
如果Service已經(jīng)運(yùn)行,則只調(diào)用onStart(),所以一個(gè)Service的onStart方法可能會(huì)重復(fù)調(diào)用多次。
如果stopService的時(shí)候會(huì)直接onDestroy,如果是調(diào)用者自己直接退出而沒有調(diào)用stopService的話,Service會(huì)一直在后臺(tái)運(yùn)行,該Service的調(diào)用者再啟動(dòng)起來后可以通過stopService關(guān)閉Service。
所以調(diào)用startService的生命周期為:onCreate --> onStart (可多次調(diào)用) --> onDestroy
context.bindService()啟動(dòng)流程:
context.bindService() -> onCreate() -> onBind() -> Service running -> onUnbind() -> onDestroy() -> Service stop
onBind()將返回給客戶端一個(gè)IBind接口實(shí)例,IBind允許客戶端回調(diào)服務(wù)的方法,比如得到Service的實(shí)例、運(yùn)行狀態(tài)或其他操作。這個(gè)時(shí)候把調(diào)用者(Context,例如Activity)會(huì)和Service綁定在一起,Context退出了,Srevice就會(huì)調(diào)用onUnbind->onDestroy相應(yīng)退出。
所以調(diào)用bindService的生命周期為:onCreate --> onBind(只一次,不可多次綁定) --> onUnbind --> onDestory。
在Service每一次的開啟關(guān)閉過程中,只有onStart可被多次調(diào)用(通過多次startService調(diào)用),其他onCreate,onBind,onUnbind,onDestory在一個(gè)生命周期中只能被調(diào)用一次。
service生命周期:
和Activity相比,service的生命周期已經(jīng)簡單的不能再簡單了,只有onCreate()->onStart()->onDestroy()三個(gè)方法。
Activity中和service有關(guān)的方法:
- startService(Intent intent):啟動(dòng)一個(gè)service
- stopService(Intent intent) :停止一個(gè)service
如果我們想使用service中的一些數(shù)據(jù)或者訪問其中的一些方法,那么我們就要通過下面的方法:
- public boolean bindService(Intent intent, ServiceConnection conn, int flags) ;
- public void unbindService(ServiceConnection conn);
intent是跳轉(zhuǎn)到service的intent,如 Intent intent = new Intent(); intent.setClass(this,MyService.class);
/** * 鏈接到service時(shí)觸發(fā)。 * name 鏈接到service組件的名稱 * service 在service中調(diào)用onBund時(shí)返回的IBinder,主要用來進(jìn)行信息的交流 */ @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.i("通知", "鏈接成功!"); MyBinder binder = (MyBinder)service; MyService myService = binder.getMyService(); int count = myService.getCount(); Log.i("通知", "count="+count); }
使用service的步驟:
第一步:我們要繼承service類,實(shí)現(xiàn)自己的service。
如果想要訪問service中的某些值,我們通常會(huì)提供一個(gè)繼承了Binder的內(nèi)部類,通過onBund()方法返回給service請(qǐng)求。這里實(shí)際上巧妙的利用了內(nèi)部類能夠訪問外部類屬性的特點(diǎn)。
第二步:在androidManifest.xml中進(jìn)行注冊(cè),如:
<!-- service配置開始 --> <service android:name="MyService"></service> <!-- service配置結(jié)束 -->
第三步:在activity中進(jìn)行啟動(dòng)、綁定、解綁或者停止service。
(很多書上說,service與用戶是不能交互的,其實(shí)這話很不正確,我們完全可以通過activity與service進(jìn)行交互嘛!我覺得,確切的說法應(yīng)該是service與用戶不能進(jìn)行直接的交互)。
例子
下邊提供一個(gè)調(diào)用service聽音樂的例子:
activity代碼:
package cn.com.chenzheng_java; import cn.com.chenzheng_java.MyService.MyBinder; 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; import android.view.View.OnClickListener; import android.widget.Button; /** * @description 對(duì)service進(jìn)行簡單的應(yīng)用 */ public class ServiceActivity extends Activity implements OnClickListener{ private Button button_start ; private Button button_bind ; private Button button_destroy ; private Button button_unbind; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.service); button_start = (Button) findViewById(R.id.button1_service); button_bind = (Button) findViewById(R.id.button2_service); button_destroy = (Button) findViewById(R.id.button3_service); button_unbind = (Button) findViewById(R.id.button4_service); button_start.setOnClickListener(this); button_bind.setOnClickListener(this); button_destroy.setOnClickListener(this); button_unbind.setOnClickListener(this); } private class MyServiceConnection implements ServiceConnection{ /** * 鏈接到service時(shí)觸發(fā)。 * name 鏈接到service組件的名稱 * service 在service中調(diào)用onBund時(shí)返回的IBinder,主要用來進(jìn)行信息的交流 */ @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.i("通知", "鏈接成功!"); MyBinder binder = (MyBinder)service; MyService myService = binder.getMyService(); int count = myService.getCount(); Log.i("通知", "count="+count); } @Override public void onServiceDisconnected(ComponentName name) { Log.i("通知", "鏈接未成功!"); } } private MyServiceConnection serviceConnection = new MyServiceConnection(); @Override public void onClick(View v) { if(v == button_start){ Intent intent = new Intent(); intent.setClass(getApplicationContext(), MyService.class); startService(intent); } if(v == button_bind){ Intent intent = new Intent(); intent.setClass(getApplicationContext(), MyService.class); bindService(intent,serviceConnection , BIND_AUTO_CREATE); } if(v==button_destroy){ Intent intent = new Intent(); intent.setClass(getApplicationContext(), MyService.class); stopService(intent); } if(v==button_unbind){ unbindService(serviceConnection); } } }
繼承service的類:
package cn.com.chenzheng_java; import android.app.Service; import android.content.Intent; import android.media.MediaPlayer; import android.os.Binder; import android.os.IBinder; import android.util.Log; /** * @description 實(shí)現(xiàn)自己的service * @author chenzheng_java * @since 2011/03/18 */ public class MyService extends Service { MediaPlayer mediaPlayer; /** * 當(dāng)用戶調(diào)用bindService方法時(shí)會(huì)觸發(fā)該方法 返回一個(gè)IBinder對(duì)象,我們可以通過該對(duì)象,對(duì)service中 的某些數(shù)據(jù)進(jìn)行訪問 */ @Override public IBinder onBind(Intent intent) { Log.i("通知", "service綁定成功!"); return new MyBinder(); } @Override public void onCreate() { Log.i("通知", "service創(chuàng)建成功!"); mediaPlayer = MediaPlayer.create(this, R.raw.aiweier); mediaPlayer.setLooping(false); super.onCreate(); } @Override public void onDestroy() { mediaPlayer.stop(); Log.i("通知", "service銷毀成功!"); super.onDestroy(); } @Override public void onRebind(Intent intent) { Log.i("通知", "service重新綁定成功!"); super.onRebind(intent); } @Override public void onStart(Intent intent, int startId) { mediaPlayer.start(); Log.i("通知", "service start成功!"); super.onStart(intent, startId); } @Override public boolean onUnbind(Intent intent) { mediaPlayer.stop(); Log.i("通知", "service解綁成功!"); return super.onUnbind(intent); } private int count = 100; public int getCount() { return count; } public void setCount(int count) { this.count = count; } public class MyBinder extends Binder { /** * @return 返回一個(gè)個(gè)人的service對(duì)象 */ MyService getMyService() { return MyService.this; } } }
service.xml代碼:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:text="啟動(dòng)" android:id="@+id/button1_service" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button> <Button android:text="綁定" android:id="@+id/button2_service" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button> <Button android:text="銷毀" android:id="@+id/button3_service" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button> <Button android:text="解綁" android:id="@+id/button4_service" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button> </LinearLayout>
androidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="cn.com.chenzheng_java" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="8" /> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name="ServiceActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <!-- service配置開始 --> <service android:name="MyService"></service> <!-- service配置結(jié)束 --> </application> </manifest>
最終效果圖:
- Android中Service服務(wù)詳解(二)
- Android中Service服務(wù)詳解(一)
- android開發(fā)教程之開機(jī)啟動(dòng)服務(wù)service示例
- Android Service 服務(wù)不被殺死的妙招
- 解析Android中如何做到Service被關(guān)閉后又自動(dòng)啟動(dòng)的實(shí)現(xiàn)方法
- Android中實(shí)現(xiàn)開機(jī)自動(dòng)啟動(dòng)服務(wù)(service)實(shí)例
- android中soap協(xié)議使用(ksoap調(diào)用webservice)
- 在Android中 獲取正在運(yùn)行的Service 實(shí)例
- Android中使用IntentService創(chuàng)建后臺(tái)服務(wù)實(shí)例
- Android中的Service相關(guān)全面總結(jié)
- Android Service服務(wù)不被停止詳解及實(shí)現(xiàn)
相關(guān)文章
Android Studio和Gradle使用不同位置JDK的問題解決
這篇文章主要介紹了Android Studio和Gradle使用不同位置JDK的問題解決,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03Android中通過反射實(shí)現(xiàn)圓角ImageView代碼實(shí)例
這篇文章主要介紹了Android中通過反射實(shí)現(xiàn)圓角ImageView代碼實(shí)例,本文直接給出核心實(shí)現(xiàn)代碼,需要的朋友可以參考下2015-04-04Flutter自定義實(shí)現(xiàn)神奇動(dòng)效的卡片切換視圖的示例代碼
這篇文章主要介紹了Flutter自定義實(shí)現(xiàn)神奇動(dòng)效的卡片切換視圖的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-04-04Android調(diào)用系統(tǒng)圖庫獲取圖片的方法
這篇文章主要為大家詳細(xì)介紹了Android調(diào)用系統(tǒng)圖庫獲取圖片,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08Android RollPagerView實(shí)現(xiàn)輪播圖
這篇文章主要介紹了Android RollPagerView實(shí)現(xiàn)輪播圖的相關(guān)資料,這里提供實(shí)例來實(shí)現(xiàn)輪播圖的簡單實(shí)例,希望能幫助到大家,需要的朋友可以參考下2017-08-08EditText限制小數(shù)點(diǎn)前后位數(shù)的實(shí)例
下面小編就為大家?guī)硪黄狤ditText限制小數(shù)點(diǎn)前后位數(shù)的實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-04-04Mac OS X 下有關(guān)Android adb用法詳解
這篇文章主要介紹了Mac OS X 下有關(guān)Android adb用法詳解的相關(guān)資料,需要的朋友可以參考下2017-04-04