Android Service中方法使用詳細(xì)介紹
service作為四大組件值得我們的更多的關(guān)注
在Android中,Activity主要負(fù)責(zé)前臺(tái)頁(yè)面的展示,Service主要負(fù)責(zé)需要長(zhǎng)期運(yùn)行的任務(wù)。例如,一個(gè)從service播放音樂的音樂播放器,應(yīng)被設(shè)置為前臺(tái)運(yùn)行,因?yàn)橛脩魰?huì)明確地注意它的運(yùn)行.在狀態(tài)欄中的通知可能會(huì)顯示當(dāng)前的歌曲并且允許用戶啟動(dòng)一個(gè)activity來與音樂播放器交互。
Service的兩種實(shí)現(xiàn)形式
1.非綁定
通過調(diào)用應(yīng)用程序組件(例如Activity)的startService()方法來啟動(dòng)一個(gè)服務(wù).一旦啟動(dòng),服務(wù)就會(huì)在后臺(tái)一直運(yùn)行,即使應(yīng)用程序組件此時(shí)被關(guān)閉.通常,已經(jīng)啟動(dòng)的服務(wù)會(huì)處理一些單一功能,并且也不需要返回結(jié)果給調(diào)用者.例如,在網(wǎng)絡(luò)上下載或上傳文件.當(dāng)服務(wù)的工作處理結(jié)束,才會(huì)自己關(guān)閉服務(wù).
2.綁定(bind)
通過調(diào)用應(yīng)用程序組件的bindService()方法來綁定一個(gè)服務(wù).已綁定的服務(wù)會(huì)提供一個(gè)客戶端-服務(wù)端交互接口.該接口主要用來與應(yīng)用程序交互,發(fā)送請(qǐng)求,獲取結(jié)果,甚至通過IPC來訪問進(jìn)程.只要一個(gè)程序組件綁定服務(wù)就會(huì)運(yùn)行綁定服務(wù),多個(gè)應(yīng)用程序組件可以同時(shí)時(shí)間綁定一個(gè)服務(wù).當(dāng)所有的應(yīng)用程序組件都解除綁定,該綁定服務(wù)器就會(huì)被銷毀.
實(shí)現(xiàn)service的方法介紹
onStartCommand()
系統(tǒng)在其它組件比如activity通過調(diào)用startService()請(qǐng)求service啟動(dòng)時(shí)調(diào)用這個(gè)方法.一旦這個(gè)方法執(zhí)行,service就啟動(dòng)并且在后臺(tái)長(zhǎng)期運(yùn)行.如果你實(shí)現(xiàn)了它,你需要負(fù)責(zé)在service完成任務(wù)時(shí)停止它,通過調(diào)用stopSelf()或stopService().(如果你只想提供綁定,你不需實(shí)現(xiàn)此方法).
OnBind()
當(dāng)組件調(diào)用bindService()想要綁定到service時(shí)(比如想要執(zhí)行進(jìn)程間通訊)系統(tǒng)調(diào)用此方法.在你的實(shí)現(xiàn)中,你必須提供一個(gè)返回一個(gè)IBinder來以使客戶端能夠使用它與service通訊,你必須總是實(shí)現(xiàn)這個(gè)方法,但是如果你不允許綁定,那么你應(yīng)返回null.
OnCreate()
系統(tǒng)在service第一次創(chuàng)建時(shí)執(zhí)行此方法,來執(zhí)行只運(yùn)行一次的初始化工作(在調(diào)用它方法如onStartCommand()或onBind()之前).如果service已經(jīng)運(yùn)行,這個(gè)方法不會(huì)被調(diào)用.
OnDestroy()
系統(tǒng)在service不再被使用并要銷毀時(shí)調(diào)用此方法.你的service應(yīng)在此方法中釋放資源,比如線程,已注冊(cè)的偵聽器,接收器等等.這是service收到的最后一個(gè)調(diào)用.
如果一個(gè)組件通過調(diào)用startService()啟動(dòng)一個(gè)service(最終導(dǎo)致onStartCommand()被調(diào)用),之后service會(huì)保持運(yùn)行,直到它通過stopSelf()停止自己或另外的組件調(diào)用stopService()停止它.
service實(shí)現(xiàn)代碼
1.非綁定
新建一個(gè)MyService繼承自Service,并重寫父類的onCreate()、onStartCommand()和onDestroy()方法
public class MyIntentService extends IntentService {
public MyIntentService() {
super("MyIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
// IntentService會(huì)使用單獨(dú)的線程來執(zhí)行該方法的代碼
// 該方法內(nèi)執(zhí)行耗時(shí)任務(wù),比如下載文件,此處只是讓線程等待20秒
long endTime = System.currentTimeMillis() + 20 * 1000;
System.out.println("onStart");
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(endTime - System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println("----耗時(shí)任務(wù)執(zhí)行完成---");
}
}
我們?cè)诓季治募屑尤肓藘蓚€(gè)按鈕,一個(gè)用于啟動(dòng)Service,一個(gè)用于停止Service。
然后打開或新建MainActivity作為程序的主Activity,在里面加入啟動(dòng)Service和停止Service的邏輯,代碼如下所示:
public class MainActivity extends Activity implements OnClickListener {
private Button startService;
private Button stopService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService = (Button) findViewById(R.id.start_service);
stopService = (Button) findViewById(R.id.stop_service);
startService.setOnClickListener(this);
stopService.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.start_service:
Intent startIntent = new Intent(this, MyService.class);
startService(startIntent);
break;
case R.id.stop_service:
Intent stopIntent = new Intent(this, MyService.class);
stopService(stopIntent);
break;
default:
break;
}
}
項(xiàng)目中的每一個(gè)Service都必須在AndroidManifest.xml中注冊(cè)才行,所以還需要編輯AndroidManifest.xml文件,代碼如下所示:
<application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > …… <service android:name="com.example.servicetest.MyService" > </service> </application>
周期分析
onCreate()方法只會(huì)在Service第一次被創(chuàng)建的時(shí)候調(diào)用,如果當(dāng)前Service已經(jīng)被創(chuàng)建過了,不管怎樣調(diào)用startService()方法,onCreate()方法都不會(huì)再執(zhí)行。因此你可以再多點(diǎn)擊幾次Start Service按鈕試一次,每次都只會(huì)有onStartCommand()方法中的打印日志。
2.綁定的service
public class LocalService extends Service {
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
// Random number generator
private final Random mGenerator = new Random();
public class LocalBinder extends Binder {
LocalService getService() {
// 返回本service的實(shí)例到客戶端,于是客戶端可以調(diào)用本service的公開方法
return LocalService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/**客戶端所要調(diào)用的方法*/
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}
下面是一個(gè)綁定到LocalService并且在按鈕按下時(shí)調(diào)用getRandomNumber()的actvity的例子:
public class BindingActivity extends Activity {
LocalService mService;
boolean mBound = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
protected void onStart() {
super.onStart();
// 綁定到類LocalService的實(shí)例
Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
// 從service解除綁定
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
/** 當(dāng)按鈕按下時(shí)調(diào)用(在layout文件中定義的button并用android:onClick 屬性指定響應(yīng)到本方法) */
public void onButtonClick(View v) {
if (mBound) {
// 調(diào)用LocalService的一個(gè)方法
// 然而,如果這個(gè)調(diào)用中有掛起操作,那么這個(gè)請(qǐng)求應(yīng)發(fā)
// 生在另一個(gè)線程來避免拉低activity的性能.
int num = mService.getRandomNumber();
Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
}
}
/** 定義service綁定的回調(diào),傳給bindService() 的*/
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
//我們已經(jīng)綁定到了LocalService,把IBinder進(jìn)行強(qiáng)制類型轉(zhuǎn)換并且獲取LocalService實(shí)例.
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
service的周期函數(shù)
1、當(dāng)采用Context.startService()方法啟動(dòng)服務(wù),與之有關(guān)的生命周期方法
onCreate()–> onStart()–> onDestroy()
onCreate()該方法在服務(wù)被創(chuàng)建時(shí)調(diào)用,該方法只會(huì)被調(diào)用一次,無論調(diào)用多少次startService()或bindService()方法,服務(wù)也只被創(chuàng)建一次。
onStart() 只有采用Context.startService()方法啟動(dòng)服務(wù)時(shí)才會(huì)回調(diào)該方法。該方法在服務(wù)開始運(yùn)行時(shí)被調(diào)用。多次調(diào)用startService()方法盡管不會(huì)多次創(chuàng)建服務(wù),但onStart() 方法會(huì)被多次調(diào)用。
onDestroy()該方法在服務(wù)被終止時(shí)調(diào)用。
2、 當(dāng)采用Context.bindService()方法啟動(dòng)服務(wù),與之有關(guān)的生命周期方法
onCreate()–> onBind() –> onUnbind() –> onDestroy()
onBind()只有采用Context.bindService()方法啟動(dòng)服務(wù)時(shí)才會(huì)回調(diào)該方法。該方法在調(diào)用者與服務(wù)綁定時(shí)被調(diào)用,當(dāng)調(diào)用者與服務(wù)已經(jīng)綁定,多次調(diào)用Context.bindService()方法并不會(huì)導(dǎo)致該方法被多次調(diào)用。
onUnbind()只有采用Context.bindService()方法啟動(dòng)服務(wù)時(shí)才會(huì)回調(diào)該方法。該方法在調(diào)用者與服務(wù)解除綁定時(shí)被調(diào)用。
如果先采用startService()方法啟動(dòng)服務(wù),然后調(diào)用bindService()方法綁定到服務(wù),再調(diào)用unbindService()方法解除綁定,最后調(diào)用bindService()方法再次綁定到服務(wù),觸發(fā)的生命周期方法如下:
onCreate()–>onStart()–>onBind()–>onUnbind()[重載后的方法需返回true–>onRebind()
那么如果我們既點(diǎn)擊了Start Service按鈕,又點(diǎn)擊了Bind Service按鈕會(huì)怎么樣呢?
這個(gè)時(shí)候你會(huì)發(fā)現(xiàn),不管你是單獨(dú)點(diǎn)擊Stop Service按鈕還是Unbind Service按鈕,Service都不會(huì)被銷毀,必要將兩個(gè)按鈕都點(diǎn)擊一下,Service才會(huì)被銷毀。也就是說,點(diǎn)擊Stop Service按鈕只會(huì)讓Service停止,點(diǎn)擊Unbind Service按鈕只會(huì)讓Service和Activity解除關(guān)聯(lián),一個(gè)Service必須要在既沒有和任何Activity關(guān)聯(lián)又處理停止?fàn)顟B(tài)的時(shí)候才會(huì)被銷毀。
Service和Thread的區(qū)別
主要就是因?yàn)镾ervice的后臺(tái)概念。Thread我們大家都知道,是用于開啟一個(gè)子線程,在這里去執(zhí)行一些耗時(shí)操作就不會(huì)阻塞主線程的運(yùn)行。而Service我們最初理解的時(shí)候,總會(huì)覺得它是用來處理一些后臺(tái)任務(wù)的,一些比較耗時(shí)的操作也可以放在這里運(yùn)行,這就會(huì)讓人產(chǎn)生混淆了。但是,如果我告訴你Service其實(shí)是運(yùn)行在主線程里的,所以是沒有任何關(guān)系的。
Service又有何用呢?
其實(shí)大家不要把后臺(tái)和子線程聯(lián)系在一起就行了,這是兩個(gè)完全不同的概念。
Android的后臺(tái)就是指,它的運(yùn)行是完全不依賴UI的。即使Activity被銷毀,或者程序被關(guān)閉,只要進(jìn)程還在,Service就可以繼續(xù)運(yùn)行。
比如說一些應(yīng)用程序,始終需要與服務(wù)器之間始終保持著心跳連接,就可以使用Service來實(shí)現(xiàn)。你可能又會(huì)問,前面不是剛剛驗(yàn)證過Service是運(yùn)行在主線程里的么?在這里一直執(zhí)行著心跳連接,難道就不會(huì)阻塞主線程的運(yùn)行嗎?當(dāng)然會(huì),但是我們可以在Service中再創(chuàng)建一個(gè)子線程,然后在這里去處理耗時(shí)邏輯就沒問題了。
使用service創(chuàng)建線程和activity直接創(chuàng)建線程的區(qū)別
Activity很難對(duì)Thread進(jìn)行控制,當(dāng)Activity被銷毀之后,就沒有任何其它的辦法可以再重新獲取到之前創(chuàng)建的子線程的實(shí)例。而且在一個(gè)Activity中創(chuàng)建的子線程,另一個(gè)Activity無法對(duì)其進(jìn)行操作。但是Service就不同了,所有的Activity都可以與Service進(jìn)行關(guān)聯(lián),然后可以很方便地操作其中的方法,即使Activity被銷毀了,之后只要重新與Service建立關(guān)聯(lián),就又能夠獲取到原有的Service中Binder的實(shí)例。因此,使用Service來處理后臺(tái)任務(wù),Activity就可以放心地finish,完全不需要擔(dān)心無法對(duì)后臺(tái)任務(wù)進(jìn)行控制的情況。
IntentService介紹
IntentService是Service的子類,比普通的Service增加了額外的功能。
先看Service本身存在兩個(gè)問題:
Service不會(huì)專門啟動(dòng)一條單獨(dú)的進(jìn)程,Service與它所在應(yīng)用位于同一個(gè)進(jìn)程中;
Service也不是專門一條新線程,因此不應(yīng)該在Service中直接處理耗時(shí)的任務(wù);
二、IntentService特征
會(huì)創(chuàng)建獨(dú)立的worker線程來處理所有的Intent請(qǐng)求;
會(huì)創(chuàng)建獨(dú)立的worker線程來處理onHandleIntent()方法實(shí)現(xiàn)的代碼,無需處理多線程問題;
所有請(qǐng)求處理完成后,IntentService會(huì)自動(dòng)停止,無需調(diào)用stopSelf()方法停止Service;
為Service的onBind()提供默認(rèn)實(shí)現(xiàn),返回null;
為Service的onStartCommand提供默認(rèn)實(shí)現(xiàn),將請(qǐng)求Intent添加到隊(duì)列中;
實(shí)現(xiàn)
public class MyIntentService extends IntentService {
public MyIntentService() {
super("MyIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
// IntentService會(huì)使用單獨(dú)的線程來執(zhí)行該方法的代碼
// 該方法內(nèi)執(zhí)行耗時(shí)任務(wù),比如下載文件,此處只是讓線程等待20秒
long endTime = System.currentTimeMillis() + 20 * 1000;
System.out.println("onStart");
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(endTime - System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println("----耗時(shí)任務(wù)執(zhí)行完成---");
}
}
activity代碼
public void startIntentService(View source) {
// 創(chuàng)建需要啟動(dòng)的IntentService的Intent
Intent intent = new Intent(this, MyIntentService.class);
startService(intent);
}
以上所述是小編給大家介紹的Android Service中方法使用詳細(xì)介紹,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
相關(guān)文章
Android 服務(wù)端將位置信息發(fā)送給客戶端的實(shí)現(xiàn)
這篇文章主要介紹了Android 服務(wù)端將位置信息發(fā)送給客戶端的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01
Android實(shí)現(xiàn)GridView中的item自由拖動(dòng)效果
在前一個(gè)項(xiàng)目中,實(shí)現(xiàn)了一個(gè)功能是gridview中的item自由拖到效果,實(shí)現(xiàn)思路很簡(jiǎn)單,主要工作就是交換節(jié)點(diǎn),以及拖動(dòng)時(shí)的移動(dòng)效果,下面小編給大家分享具體實(shí)現(xiàn)過程,對(duì)gridview實(shí)現(xiàn)拖拽效果感興趣的朋友一起看看吧2016-11-11
Android編程實(shí)現(xiàn)獲得內(nèi)存剩余大小與總大小的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)獲得內(nèi)存剩余大小與總大小的方法,涉及Android基于ActivityManager實(shí)現(xiàn)內(nèi)存信息的操作技巧,需要的朋友可以參考下2015-12-12
Android實(shí)現(xiàn)瘋狂連連看游戲之加載界面圖片和實(shí)現(xiàn)游戲Activity(四)
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)瘋狂連連看游戲之加載界面圖片和實(shí)現(xiàn)游戲Activity,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03
完美解決android 項(xiàng)目jar包沖突的問題
這篇文章主要介紹了完美解決android 項(xiàng)目jar包沖突的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-03-03

