Android中Service的使用詳解和注意點(LocalService)
開始,先稍稍講一點android中Service的概念和用途吧~
Service分為本地服務(LocalService)和遠端服務(RemoteService):
1、本地服務依附在主程序上而不是獨立的程序,這樣在一定程度上節約了資源,另外Local服務因為是在同一程序因此不需要IPC,也不需要AIDL。相應bindService會方便很多。主程序被Kill後,服務便會終止。
2、遠程服務為獨立的程序,對應程序名格式為所在包名加上你指定的android:process字串。由於是獨立的程序,因此在Activity所在程序被Kill的時候,該服務依然在執行,不受其他程序影響,有利於為多個程序提供服務具有較高的靈活性。該服務是獨立的程序,會佔用一定資源,並且使用AIDL進行IPC稍微麻煩一點。
按使用方式可以分為以下三種:
1、startService 啟動的服務:主要用於啟動一個服務執行後臺任務,不進行通訊。停止服務使用stopService;
2、bindService 啟動的服務:該方法啟動的服務可以進行通訊。停止服務使用unbindService;
3、startService 同時也 bindService 啟動的服務:停止服務應同時使用stepService與unbindService
Service 與 Thread 的區別
很多時候,你可能會問,為什麼要用 Service,而不用 Thread 呢,因為用 Thread 是很方便的,比起 Service 也方便多了,下面我詳細的來解釋一下。
1). Thread:Thread 是程式執行的最小單元,它是分配CPU的基本單位。可以用 Thread 來執行一些非同步的操作。
2). Service:Service 是android的一種機制,當它執行的時候如果是Local Service,那麼對應的 Service 是執行在主程序的 main 執行緒上的。如:onCreate,onStart 這些函式在被系統呼叫的時候都是在主程序的 main 執行緒上執行的。如果是Remote Service,那麼對應的 Service 則是執行在獨立程序的 main 執行緒上。因此請不要把 Service 理解成執行緒,它跟執行緒半毛錢的關係都沒有!
既然這樣,那麼我們為什麼要用 Service 呢?其實這跟 android 的系統機制有關,我們先拿 Thread 來說。Thread 的執行是獨立於 Activity 的,也就是說當一個 Activity 被 finish 之後,如果你沒有主動停止 Thread 或者 Thread 裡的 run 方法沒有執行完畢的話,Thread 也會一直執行。因此這裡會出現一個問題:當 Activity 被 finish 之後,你不再持有該 Thread 的引用。另一方面,你沒有辦法在不同的 Activity 中對同一 Thread 進行控制。
舉個例子:如果你的 Thread 需要不停地隔一段時間就要連線伺服器做某種同步的話,該 Thread 需要在 Activity 沒有start的時候也在執行。這個時候當你 start 一個 Activity 就沒有辦法在該 Activity 裡面控制之前建立的 Thread。因此你便需要建立並啟動一個 Service ,在 Service 裡面建立、執行並控制該 Thread,這樣便解決了該問題(因為任何 Activity 都可以控制同一 Service,而系統也只會建立一個對應 Service 的例項)。
因此你可以把 Service 想象成一種訊息服務,而你可以在任何有 Context 的地方呼叫 Context.startService、Context.stopService、Context.bindService,Context.unbindService,來控制它,你也可以在 Service 裡註冊 BroadcastReceiver,在其他地方通過傳送 broadcast 來控制它,當然這些都是 Thread 做不到的。
Service的生命週期
onCreate onStart onDestroy onBind
1). 被啟動的服務的生命週期:如果一個Service被某個Activity 呼叫 Context.startService 方法啟動,那麼不管是否有Activity使用bindService繫結或unbindService解除繫結到該Service,該Service都在後臺執行。如果一個Service被startService 方法多次啟動,那麼onCreate方法只會呼叫一次,onStart將會被呼叫多次(對應呼叫startService的次數),並且系統只會建立Service的一個例項(因此你應該知道只需要一次stopService呼叫)。該Service將會一直在後臺執行,而不管對應程式的Activity是否在執行,直到被呼叫stopService,或自身的stopSelf方法。當然如果系統資源不足,android系統也可能結束服務。
2). 被繫結的服務的生命週期:如果一個Service被某個Activity 呼叫 Context.bindService 方法繫結啟動,不管呼叫 bindService 呼叫幾次,onCreate方法都只會呼叫一次,同時onStart方法始終不會被呼叫。當連線建立之後,Service將會一直執行,除非呼叫Context.unbindService 斷開連線或者之前呼叫bindService 的 Context 不存在了(如Activity被finish的時候),系統將會自動停止Service,對應onDestroy將被呼叫。
3). 被啟動又被繫結的服務的生命週期:如果一個Service又被啟動又被繫結,則該Service將會一直在後臺執行。並且不管如何呼叫,onCreate始終只會呼叫一次,對應startService呼叫多少次,Service的onStart便會呼叫多少次。呼叫unbindService將不會停止Service,而必須呼叫 stopService 或 Service的 stopSelf 來停止服務。
4). 當服務被停止時清除服務:當一個Service被終止(1、呼叫stopService;2、呼叫stopSelf;3、不再有繫結的連線(沒有被啟動))時,onDestroy方法將會被呼叫,在這裡你應當做一些清除工作,如停止在Service中建立並執行的執行緒。
特別注意:
1、你應當知道在呼叫 bindService 繫結到Service的時候,你就應當保證在某處呼叫 unbindService 解除繫結(儘管 Activity 被 finish 的時候繫結會自 動解除,並且Service會自動停止);
2、你應當注意 使用 startService 啟動服務之後,一定要使用 stopService停止服務,不管你是否使用bindService;
3、同時使用 startService 與 bindService 要注意到,Service 的終止,需要unbindService與stopService同時呼叫,才能終止 Service,不管 startService 與 bindService 的呼叫順序,如果先呼叫 unbindService 此時服務不會自動終止,再呼叫 stopService 之後服務才會停止,如果先呼叫 stopService 此時服務也不會終止,而再呼叫 unbindService 或者 之前呼叫 bindService 的 Context 不存在了(如Activity 被 finish 的時候)之後服務才會自動停止;
4、當在旋轉手機螢幕的時候,當手機螢幕在“橫”“豎”變換時,此時如果你的 Activity 如果會自動旋轉的話,旋轉其實是 Activity 的重新建立,因此旋轉之前的使用 bindService 建立的連線便會斷開(Context 不存在了),對應服務的生命週期與上述相同。
5、在 sdk 2.0 及其以後的版本中,對應的 onStart 已經被否決變為了 onStartCommand,不過之前的 onStart 任然有效。這意味著,如果你開發的應用程式用的 sdk 為 2.0 及其以後的版本,那麼你應當使用 onStartCommand 而不是 onStart。
下面開始上一個很簡單的程式碼哈~裡頭的註釋也要注意哦,有在上面沒有講到的會在註釋裡提到哇(尤其適用Bind方法的時候的資料傳輸哇)~
首先,因為要再Manifest檔案裡對服務進行註冊,所以就先來Manifest的程式碼吧~
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.test.localservice" 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=".LocalServiceTestActivity"
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 android:name=".MyService">
<intent-filter>
<action android:name="com.test.SERVICE_TEST" />
<category android:name="android.intent.category.default" />
</intent-filter>
</service>
</application>
</manifest>
然後然後,是服務實現類~
package com.test.service; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.util.Log; public class MyService extends Service { public class LocalBinder extends Binder { String stringToSend = "I'm the test String"; MyService getService() { Log.i("TAG", "getService ---> " + MyService.this); return MyService.this; } } private final IBinder mBinder = new LocalBinder(); @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub Log.i("TAG", "onBind~~~~~~~~~~~~"); // IBinder myIBinder = null; // if ( null == myIBinder ) // myIBinder = new LocalBinder() ; // return myIBinder; return mBinder; //也可以像上面幾個語句那樣重新new一個IBinder //如果這邊不返回一個IBinder的介面例項,那麼ServiceConnection中的onServiceConnected就不會被呼叫 //那麼bind所具有的傳遞資料的功能也就體現不出來~\(≧▽≦)/~啦啦啦(這個返回值是被作為onServiceConnected中的第二個引數的) } @Override public void onCreate() { // TODO Auto-generated method stub super.onCreate(); Log.i("TAG", "onCreate~~~~~~~~~~"); } @Override public void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); Log.i("TAG", "onDestroy~~~~~~~~~~~"); } @Override public void onStart(Intent intent, int startId) { // TODO Auto-generated method stub super.onStart(intent, startId); Log.i("TAG", "onStart~~~~~~"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // TODO Auto-generated method stub Log.i("TAG", "onStartCommand~~~~~~~~~~~~"); return super.onStartCommand(intent, flags, startId); } @Override public boolean onUnbind(Intent intent) { // TODO Auto-generated method stub Log.i("TAG", "onUnbind~~~~~~~~~~~~~~~~"); return super.onUnbind(intent); } }
再來,就是我們的Activity的測試類啦~
package com.test.service; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.media.MediaPlayer; 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; public class ServiceTestActivity extends Activity { private Button startButton, bindButton; private Button stopButton, unbindButton; private ServiceConnection sc; private MediaPlayer mediaPlayer = null; private MyService myService;// 類似於MediaPlayer mPlayer = new // MediaPlayer();只不過這邊的服務是自定義的,不是系統提供好了的 /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); startButton = (Button) findViewById(R.id.startbutton_id); stopButton = (Button) findViewById(R.id.stopbutton_id); bindButton = (Button) findViewById(R.id.bindbutton_id); unbindButton = (Button) findViewById(R.id.unbindbutton_id); sc = new ServiceConnection() { /* * 只有在MyService中的onBind方法中返回一個IBinder例項才會在Bind的時候 * 呼叫onServiceConnection回撥方法 * 第二個引數service就是MyService中onBind方法return的那個IBinder例項,可以利用這個來傳遞資料 */ @Override public void onServiceConnected(ComponentName name, IBinder service) { // TODO Auto-generated method stub myService = ((MyService.LocalBinder) service).getService(); String recStr = ((MyService.LocalBinder) service).stringToSend; //利用IBinder物件傳遞過來的字串資料(其他資料也可以啦,哪怕是一個物件也OK~~) Log.i("TAG","The String is : " + recStr); Log.i("TAG", "onServiceConnected : myService ---> " + myService); } @Override public void onServiceDisconnected(ComponentName name) { /* SDK上是這麼說的: * This is called when the connection with the service has been unexpectedly disconnected * that is, its process crashed. Because it is running in our same process, we should never see this happen. * 所以說,只有在service因異常而斷開連線的時候,這個方法才會用到*/ // TODO Auto-generated method stub sc = null; Log.i("TAG", "onServiceDisconnected : ServiceConnection --->" + sc); } }; startButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub Intent intent = new Intent(ServiceTestActivity.this, MyService.class); startService(intent); Log.i("TAG", "Start button clicked"); } }); stopButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub /* * Intent intent = new * Intent(LocalServiceTestActivity.this,MyService.class); * stopService(intent); 這種方法也是可以的哈~ */ Intent intent = new Intent(); intent.setAction("com.test.SERVICE_TEST"); stopService(intent); Log.i("TAG", "Stop Button clicked"); } }); bindButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub // Intent intent = new Intent(LocalServiceTestActivity.this, // MyService.class);//這樣也可以的 Intent intent = new Intent(); intent.setAction("com.test.SERVICE_TEST"); bindService(intent, sc, Context.BIND_AUTO_CREATE);//bind多次也只會呼叫一次onBind方法 Log.i("TAG", "Bind button clicked"); } }); unbindButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub unbindService(sc); // 這邊如果重複unBind會報錯,提示該服務沒有註冊的錯誤——IllegalArgumentException: // Service not registered: null // 所以一般會設定一個flag去看這個service // bind後有沒有被unBind過,沒有unBind過才能呼叫unBind方法(這邊我就不設定了哈~\(≧▽≦)/~啦啦啦) Log.i("TAG", "Unbind Button clicked"); } }); } }
相信開頭的介紹和程式碼裡的註釋應該對大家理解和使用Service有所幫助哈~不過這邊就先只講LocalService吧,剩下的RemoteService就等下次在說嘍~
相關推薦
Android中Service的使用詳解和注意點(LocalService)
開始,先稍稍講一點android中Service的概念和用途吧~ Service分為本地服務(LocalService)和遠端服務(RemoteService): 1、本地服務依附在主程序上而不是獨立的程序,這樣在一定程度上節約了資源,另外Local服務因為是在同一程序因此
JavaScript中的小技巧和注意點(二)
tip:自己收集的一些前端注意事項 1.函式優先 函式宣告和變數宣告都會被提升,但是一個值得注意的細節是函式會首先被提升,然後才是變數 foo();//1 var foo; function foo(){ console.log(1);
android WebView詳解,常見漏洞詳解和安全原始碼(上)
這篇部落格主要來介紹 WebView 的相關使用方法,常見的幾個漏洞,開發中可能遇到的坑和最後解決相應漏洞的原始碼,以及針對該原始碼的解析。 由於部落格內容長度,這次將分為上下兩篇,上篇詳解 WebView 的使用,下篇講述 WebView 的漏洞和
【CronExpression表達式詳解和案例】(轉載)
強烈 簡單的 exce 初始 每分鐘 第三周 normal orm 以及 原文地址:https://www.cnblogs.com/pipi-changing/p/5697481.html 找了下Cron的資料,這篇作者寫的比較清晰,轉載記錄一下,方便後面使用的時候在g
Tomcat記錄-tomcat常用配置詳解和優化方法(轉載)
常用配置詳解 1 目錄結構 /bin:指令碼檔案目錄。 /common/lib:存放所有web專案都可以訪問的公共jar包(使用Common類載入器載入)。 /conf:存放配置檔案,最重要的是server.xml。 /logs:存放日誌檔案。
vue中mixins的使用方法和注意點(詳)
mixins基礎概況 vue中的解釋是這樣的,如果覺得語言枯燥的可以自行跳過嘿~ 混入 (mixins): 是一種分發 Vue 元件中可複用功能的非常靈活的方式。混入物件可以包含任意元件選項。當元件使用混入物件時,所有混入物件的選項將被混入該元件本身的選項。 怎麼用? 舉個栗子: 定義一個混入
Android中ImageSwitcher詳解(注意與圖片瀏覽器的區別)
先看看繼承關係,ImageSwitcher和TextSwitcher的繼承關係是一樣的。兩個重要的父類:ViewSwitcher和ViewAnimator 繼承於ViewSwitcher,說明具備了切換功能 繼承於ViewAnimator,說明具備了動畫功能 Image
專案中遇到的坑和注意點 總結 持續更新
gitHub地址: 傳送門 工作中遇到的坑和思考 有不同意見歡迎指正交流 前排推薦 https://github.com/topics/javascript 關注JS開源框架動態 勤於總結和思考 1. ajax請求的結果要和後端約定好返回的資料格式。
Android中AlarmManager詳解以及利用PendingIntent設定鬧鐘
AlarmManager是提供一種訪問系統鬧鐘服務的方式,允許你去設定在將來的某個時間點去執行你的應用程式。當你的鬧鐘響起(時間到)時,在它上面註冊的一個意圖(Intent)將會被系統以廣播發出,然後自動啟動目標程式,如果它沒有正在執行。註冊的鬧鐘會被保留即使裝置處於休眠中
Android中Context詳解 ---- 你所不知道的Context
前言:本文是我讀《Android核心剖析》第7章 後形成的讀書筆記 ,在此向欲瞭解Android框架的書籍推薦此書。 大家好, 今天給大家介紹下我們在應用開發中最熟悉而陌生的朋友-----Context類 ,說它熟
Android中WindowManager詳解
最近看到 關於 WindowManager的介紹,感到新奇下,瞭解了一下,並整理,以供備用: 一、WindowManager是什麼 WindowManager是Android中一個重要的
tcp連線關閉詳解和注意事項
注:tcp關閉連線不區分客戶端和服務端,哪一埠可以主動發起關閉連線請求。所以為了描述方便,描述中的“主動方”表示主動發起關閉連線一方,“被動方”表示被動關閉連線一方。 1. tcp關閉連線狀態轉換 上圖是tcp連線主動關閉端的狀態轉換圖: (1)應用層呼叫close函式發起關閉連線請求 (2
JAVA 和 C/C++ 中 string 的區別和注意點
所有的字串類都起源於C語言的字串,而C語言字串則是字元的陣列。C語言中是沒有字串的,只有字元陣列。 談一下C++的字串:C++提供兩種字串的表示:C風格的字串和標準C++引入的string型別。一般建議用string型別,但是實際情況中還是要使用老式C風格的字串。 1.C風格的字串:C
Android中Intent詳解(二)之使用Intent廣播事件及Broadcast Receiver簡介
通過第一篇的講解,我們已經看到了如何使用Intent來啟動新的應用程式元件,但是實際上他們也可以使用sendBroadcast方法來在元件間匿名的廣播訊息。 作為一個系統級別的訊息傳遞機制,Intent可以在程序之間傳送結構化的訊息。因此,通過實現Broadcast Rec
Android SQLite使用詳解和多執行緒併發訪問
Android中資料持久化技術包括檔案儲存、SharedPreferences以及資料庫儲存,對於大量複雜的關係型資料,資料庫無疑是最合適的選擇。SQLite是一個輕量級的關係型資料庫,運算速度快,佔用資源少,適合在移動裝置上使用。SQLite不僅支援SQL語法,還遵循資料庫
React生命週期函式詳解和注意事項
React生命週期函式 生命週期函式是指在某一個週期自動執行的函式。 React中的生命週期執行過程 以下是React中的常用的生命週期函式,按個部分中按照自動執行順序列出,這幾個過程
Netty 4.1中的新變化和注意點
本文帶你瞭解Netty 4.0到Netty 4.1的值得注意的改變和新特性. 題外話 儘管我們儘量保持向下相容,4.1 還是有一些和4.0不完全相容的地方. 請確保使用新的Netty版本重新編譯你的應用. 當你重新編譯你的應用時,你可以能看到一些棄用警告. 請依照修改建議
Android WebView技術詳解和經驗分享
WebView和JS相互通訊 WebView呼叫JS函式 通用方式,不能獲取JS函式的返回值: webView.loadUrl("javascript:alert('hello world');"); Android 4.4.及以上系統的WebView專用方式,可以獲取J
Android之Service詳解
1. 簡介 與前一篇Android之Activity的細枝末節是同一系列的文章,是自己在學習和研發過程中,對Service的一些知識點的總結,彙總得到這篇文章。 這篇文章會從Service的一些小知識點,延伸到Android中幾種常用程序間通訊方法。
【計算機網絡】詳解網絡層(二)ARP和RARP
博文 拆分 detail 動態 再次 tcp 將在 ont 關於 ARP ARP(Address Resolution Protocol,地址解析協議)是將IP地址解析為以太網MAC地址(物理地址)的協議。在局域網中,當主機或其他網絡設備有數據要發送給另一個主機或設備時,它