Android服務Service使用總結(jié)資料_第1頁
Android服務Service使用總結(jié)資料_第2頁
Android服務Service使用總結(jié)資料_第3頁
Android服務Service使用總結(jié)資料_第4頁
Android服務Service使用總結(jié)資料_第5頁
已閱讀5頁,還剩16頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

Android服務Service使用總結(jié)一.Service簡介Service是Android系統(tǒng)中的四大組件之一(Activity、Service、BroadcastReceiver、ContentProvider),它跟Activity的級別差不多,但不能頁面顯示只能后臺運行,并且可以和其他組件進行交互。service可以在很多場合的應用中使用,比如播放多媒體的時候用戶啟動了其他Activity 這個時候程序要在后臺繼續(xù)播放,比如檢測 SD卡上文件的變化,再或者在后臺記錄你地理信息位置的改變等等,總之服務總是藏在后臺的 ,例如,一個 service可能處理網(wǎng)絡 事物,播放音樂,執(zhí)行文件 I/O,或與一個內(nèi)容提供者交互,所有這些都在后臺進行。我們一定要知道的是這里Service的后臺運行并不是子線程。Service的運行是在主線程中進行的,只是它沒有界面顯示而已,它的耗時操作同樣需要開啟子線程,否者會跟Activity 一樣出現(xiàn) ANR(applicationnotresponse–程序沒有響應)。我們要知道的是主線程的內(nèi)容包括 UI和后臺。只要程序中的 UI或后臺其中一個在跑,程序都算是在運行狀態(tài)。(一)Service的創(chuàng)建和注冊1.Service服務的創(chuàng)建必須要實現(xiàn)重寫其中的onBind方法,可以在里面做各種操作,也可以接收傳遞過來的Intent的數(shù)據(jù)做處理。publicclassMyServiceextendsService{@Nullable@OverridepublicIBinderonBind(Intentintent){returnnull;}}2.Service服務的注冊,在 AndroidManifest 中注冊<serviceandroid:name=".MyService"/>服務的注冊是四大組件中最簡單的一個,一般只要設(shè)置 name屬性就可以了。但是如果有其他需求還是要設(shè)置其他的屬性值的。對Service服務做好創(chuàng)建和注冊后,就可以操作服務了。(二)Service兩種啟動模式Service的啟動有兩種方式:Context.startService()和Context.bindService()。這里的Context是上下文的意思。1.startService()方式啟動時的生命周期回調(diào)方法(1)啟動服務 startService:–>onCreate()–>onStart()2)停止服務stopService:–>onDestroy()如果調(diào)用者直接退出而沒有停止走只是關(guān)閉了UI界面。

Service,則

Service

會一直在后臺運行。這里的退startService()方法啟動服務,在服務未被創(chuàng)建時,系統(tǒng)會先調(diào)用服務的onCreate()方法,接著調(diào)用onStart()方法。如果調(diào)用startService()方法前服務已經(jīng)被創(chuàng)建,多次調(diào)用startService()方法并不會導致多次創(chuàng)建服務,但會導致多次調(diào)用onStart()方法。采用startService()方法啟動的服務,只能調(diào)用stopService()方法結(jié)束服務,服務結(jié)束時會調(diào)用生命周期的onDestroy()方法。2.bindService()方式啟動時的生命周期回調(diào)方法1)綁定bindService:–>onCreate()–>onBind()2)解綁unbindService:–>onUnbind()3)正常停止程序服務的方法是先解綁unbindService,再停止服務stopService。4)如果綁定后調(diào)用stopService方法,這時是不能停止服務的,如果這時再調(diào)用解綁unbindService,程序后先解綁,后停止服務。用bindService()方法啟動服務,在服務未被創(chuàng)建時,系統(tǒng)會先調(diào)用服務的onCreate()方法,接著調(diào)用onBind()方法。這個時候調(diào)用者和服務綁定在一起,調(diào)用者退出了,系統(tǒng)就會先調(diào)用服務的 onUnbind()方法,接著調(diào)用 onDestroy()方法。如果調(diào)用 bindService()方法前服務已經(jīng)被綁定, 多次調(diào)用bindService()方法并不會導致多次創(chuàng)建服務及綁定 (也就是說onCreate()和onBind()方法并不會被多次調(diào)用 )。如果調(diào)用者希望與正在綁定的服務解除綁定,可以調(diào)用unbindService()方法,調(diào)用該方法也會導致系統(tǒng)調(diào)用服務的onUnbind()->onDestroy()方法。綁定Service方法:bindService(intent,conn,Service.BIND_AUTO_CREA TE);三個參數(shù)的說明:第一個:Intent對象第二個: ServiceConnection

對象,創(chuàng)建該對象要實現(xiàn)它的

onServiceConnected()和

onServiceDisconnected()來判斷連接成功或者是斷開連接第三個:創(chuàng)建 Service的模式,一般指定綁定的時候自動創(chuàng)建(三)Service的五個生命周期的回調(diào)方法1.周期命名1)onCreate()2)onStart()3)onBind()4)onUnBind()5)onDestroy()2.生命周期圖解上面展示的是沒有綁定服務和有綁定服務的生命周期的不同情況的過程。3.關(guān)于幾個方法的說明(1)onCreate()說明服務第一次被創(chuàng)建(2)onStartComand()說明服務開始工作(3)onBind()說明服務已經(jīng)綁定(4)onUnBind()說明服務已經(jīng)解綁(5)onDestroy()說明服務已經(jīng)停止正如上面說的啟動服務有兩種方式,一個是使用 startService,另一個方法是使用bindService方法;使用 bindService方法沒有回調(diào)到 startCommand方法;也可以先啟動服務用 startService,再綁定服務用 bindService,這時的Service的回調(diào)方法的順序是:–>onCreate()–>onStartCommand()–>onBind()二.IntentService普通的Service要創(chuàng)建一個線程去完成耗時操作, 因為其運行在主線程, 並且要手動停止IntentService是繼承于 Service并處理異步請求的一個類,在 IntentService內(nèi)有一個工作線程 來處理耗時操作,啟動 IntentService的方式和啟動傳統(tǒng) Service一樣,同時,當任務執(zhí)行完 后,IntentService會自動停止,而不需要我們?nèi)ナ謩涌刂?。另外,可以啟動IntentService多次,而每一個耗時操作會以工作隊列的方式在IntentService的onHandleIntent回調(diào)方法中執(zhí)行,并且,每次只會執(zhí)行一個工作線程,執(zhí)行完第一個再執(zhí)行第二個,以此類推。而且,所有請求都在一個單線程中,不會阻塞應用程序的主線程(UIThread),同一時間只處理一個請求。那么,用 IntentService有什么好處呢?首先,我們省去了在 Service中手動開線程的麻煩,第二,當操作完成時,我們不用手動停止 ServiceIntentService,一個方便我們處理業(yè)務流程的類,它是一個 Service,但是比 Service更智能三.查看 Service的生命周期回調(diào)方法的簡單示例本示例只是用來看看Service在服務開啟時,停止時,綁定時,解綁時,生命周期方法的回調(diào)情況加深對Service生命周期的印象。(一)創(chuàng)建MyService類(繼承 Service)/**服務的創(chuàng)建,測試生命周期的過程和先后五個生命周期:onCreateonStartCommandonDestroyonBindonUnBind*/publicclassMyServiceextendsService{@Nullable@OverridepublicIBinderonBind(Intentintent){returnnull;}@OverridepublicvoidonCreate(){super.onCreate();}@Overridereturnsuper.onStartCommand(intent,flags,startId);}@OverridepublicvoidonDestroy(){super.onDestroy();}@OverridepublicbooleanonUnbind(Intentintent){returnsuper.onUnbind(intent);}}(二)在AndroidManifest 中注冊服務<serviceandroid:name=".MyService"/>(三)設(shè)計控制服務開啟、停止、綁定、解綁狀態(tài)的代碼/**服務的創(chuàng)建和使用注意這里的服務不依賴于Activity頁面,即使頁面關(guān)閉了,服務沒有主動去停止,是不會關(guān)閉的Service也是在主線程中執(zhí)行任務的,但是為什么不會造成主線程阻塞??*因為做的不是耗時操作,如果做耗時操作一樣會造成 ANR。。。這里點擊綁定服務后,點擊停止服務按鈕是無效的,要先解綁后,才能停止服務。正常情況下,從綁定狀態(tài)到解綁狀態(tài)是不會停止服務的。只是一種狀態(tài)改變而已。這里點擊綁定服務后,點擊停止服務按鈕是無效的,但是解綁后,會馬上停止服務。*/publicclassMainActivityextendsAppCompatActivity{@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);}//開啟服務publicvoidstartService(Viewview){//開啟服務需要 Intent對象,和Activity 跳轉(zhuǎn)類似startService(newIntent(this,MyService.class));}//停止服務publicvoidstopService(Viewview){//停止服務的方法stopService(newIntent(this,MyService.class));}//綁定服務publicvoidbindService(Viewview){//綁定服務bindService(newIntent(this,MyService.class),conn,flags);}//解綁服務publicvoidunBindService(Viewview){//防止在沒有綁定的情況下,去解除綁定,拋出異常try{解除綁定unbindService(conn);}}//服務綁定的連接對象privateServiceConnectionconn=newServiceConnection(){@OverridepublicvoidonServiceConnected(ComponentNamename,IBinderservice){}@OverridepublicvoidonServiceDisconnected(ComponentNamename){}};//服務綁定的標識//BIND_AUTO_CREA TE綁定的同時,啟動 Serviceprivateintflags=Service.BIND_AUTO_CREATE;}上面是使用四個按鈕來實現(xiàn)服務的幾種狀態(tài)的改變。(四)布局文件的設(shè)計<?xmlversion="1.0"encoding="utf-8"?>android:id="@+id/activity_main"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:text="Service"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:onClick="startService"android:text="啟動服務"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:onClick="stopService"android:text="停止服務"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:onClick="bindService"android:text="綁定服務"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:onClick="unBindService"android:text="解綁服務"/></LinearLayout>上面布局文件代碼比較簡單的,只是用四個按鈕搞定!程序運行后顯示的界面:這里執(zhí)行了兩個回調(diào)方法,先啟動服務,再綁定服務!在綁定服務的情況下是不能停止服務的,要解綁服務才能停止服務。在程序的服務啟動 /綁定了的情況下,再點擊啟動服務,只會回調(diào) onStartCommand方法,也就是說一個服務在一個生命周期內(nèi)只會回調(diào)一次 onCreate方法。點擊“解綁服務”按鈕后顯示的 Log信息:執(zhí)行了兩個回調(diào)方法: onUnBind和onDestroy如果是用服務做簡單的事情,使用第一種方法來啟動服務就可以了,但是如果需要涉及到比較復雜的數(shù)據(jù)處理和操作就用綁定服務的方法來啟動服務。.IntentService的使用示例程序設(shè)計:查找手機 SD卡中的所有圖片顯示在 UI界面上。(一)布局文件 activity_main.xml 文件實際<?xmlversion="1.0"encoding="utf-8"?>android:id="@+id/activity_main"android:layout_width="match_parent"android:layout_height="match_parent"><ListViewandroid:id="@+id/main_lv"android:layout_width="match_parent"android:layout_height="match_parent"></ListView></RelativeLayout>非常簡單的布局設(shè)計,使用 ListView來顯示所有的圖片(二)遍歷文件的工具類的設(shè)計/**SD卡的路徑:Environment.getExternalStorageDirectory()*/publicclassFileUtils{/**獲得指定目錄下的所有的圖片*/publicstaticfinalArrayList<File>getAllPicture(Filedir){ArrayList<File>files=getAllFile(dir);ArrayList<File>imgList=newArrayList<>();for(Filefile:files){if(file.getName().endsWith(".png")||file.getName().endsWith(".jpg"))imgList.add(file);}returnimgList;}/**遞歸遍歷文件夾的方法*/publicstaticfinalvoidgetFileFromDir(Filedir,List<File>fileList){File[]files=dir.listFiles();if(files==null)return;for(Filefile:files){if(file.isDirectory())getFileFromDir(file,fileList);fileList.add(file);}}/**獲得根目錄下的所有圖片*/publicstaticfinalArrayList<File>getAllPicture(){returngetAllPicture(Environment.getExternalStorageDirectory());}}(三)簡化 BaseAdapter的一個工具類/**這是一個簡化BaseAdapter適配器的工具類*這是使用的是定義一個泛型 T,使用時傳入什么數(shù)據(jù), T就是什么數(shù)據(jù)實際設(shè)計中除了getVIew方法外,其他的方法基本是差不多的*所以繼承這個工具類后只要重寫 getView方法,就可以使用 BaseAdapter了*/publicabstractclassListItemAdapter<T>extendsBaseAdapter{List<T>list=newArrayList<>();Contextcontext;ListItemAdapter(Contextcontext,List<T>list){this.context=context;this.list=list;}ListItemAdapter(Contextcontext,T[]list){this.context=context;for(Tt:list){}}@OverridepublicintgetCount(){returnlist==null?0:list.size();}@OverridepublicTgetItem(intposition){returnlist==null?null:list.get(position);}@OverridepubliclonggetItemId(intposition){returnposition;}}(四)MyIntentService的創(chuàng)建/***IntentService的使用*IntentService是Service的子類,也需要在 xml中注冊*它有自定義的子線程的方法*這里主要需要解決的問題是資源文件得到后怎么把數(shù)據(jù)傳遞給 UI線程的Activity*/publicclassMyIntentServiceextendsIntentService{/**通過構(gòu)造方法,傳入子線程的名字但是這里必須要創(chuàng)建一個無參的構(gòu)造方法*/publicMyIntentService(){super("myService");}/**這是在子線程中的執(zhí)行操作*/@OverrideprotectedvoidonHandleIntent(Intentintent){Log.e("TAG","子線程開始工作 ");//遍歷文件夾獲取圖片ArrayList<File>list=FileUtils.getAllPicture();//使用handler發(fā)送信息Messagemsg=Message.obtain();//這里給handler對象傳遞一個對象msg.obj=list;//發(fā)送廣播來傳遞數(shù)據(jù)Intentintent1=newIntent("filefinish");intent1.putExtra("file",list);sendBroadcast(intent1);}@OverridepublicvoidonCreate(){super.onCreate();Log.e("TAG","onCreate");}@OverridepublicvoidonDestroy(){super.onDestroy();Log.e("TAG","onDestroy");}}這里的IntentService的注冊和 Intent的注冊是一樣的。(五)MainActivity 中的代碼設(shè)計/**這里使用服務來IntentService來遍歷文件夾在程序創(chuàng)建的使用就要啟動服務在頁面銷毀的時候就停止服務但是Service執(zhí)行完任務后還有傳遞數(shù)據(jù)給 MainActivity在MainActivity中才能進行UI界面的更新這就涉及到 Service和Activity 的數(shù)據(jù)傳遞問題了這里使用的是用廣播來傳遞數(shù)據(jù)*/publicclassMainActivityextendsAppCompatActivity{//定義布局內(nèi)的控件ListViewlistView;//定義適配器的數(shù)據(jù)的集合//一定要static???staticArrayList<File>fileList;staticMyBaseAdapteradapter;MyBroadcastReceivermbcr;@Overridembcr=newMyBroadcastReceiver();//動態(tài)注冊一個廣播IntentFilterfilter=newIntentFilter();filter.addAction("filefinish");registerReceiver(mbcr,filter);// 注冊//創(chuàng)建適配器的對象adapter=newMyBaseAdapter(this,fileList);//實例化布局內(nèi)的控件//給listView設(shè)置適配器listView.setAdapter(adapter);//啟動服務startService(newIntent(this,MyIntentService.class));}//創(chuàng)建適配器的類classMyBaseAdapterextendsListItemAdapter<File>{MyBaseAdapter(Contextcontext,List<File>list){super(context,list);}@OverridepublicViewgetView(intposition,ViewconvertView,ViewGroupparent){ImageViewimage=null;if(convertView==null){image=newImageView(getBaseContext());convertView=image;}else{image=(ImageView)convertView;}設(shè)置圖片資源和屬性image.setImageURI(Uri.fromFile(fileList.get(position)));image.setAdjustViewBounds(true);returnimage;}}//停止服務publicvoidstop(){stopService(newIntent(MainActivity.this,MyIntentService.class));}@OverrideprotectedvoidonDestroy(){super.onDestroy();//即使之前停止了服務,再次停止服務也是不會報錯的stop();//解除廣播unregisterReceiver(mbcr);}//動態(tài)創(chuàng)建廣播接收者classMyBroadcastReceiverextendsBroadcastReceiver{@OverridepublicvoidonReceive(Contextcontext,Intentintent){對接收到的廣播進行處理,intent里面包含數(shù)據(jù)fileList=(ArrayList<File>)intent.getSerializableExtra("file");刷新適配器adapter.notifyDataSetChanged();停止服務,它的子線程也會停止stop();}}}程序運行前還記得加上 SD卡的訪問權(quán)限;上面程序功能還是有點問題!遍歷完文件后。頁面沒有馬上更新?退出程序再進來,頁面上馬上顯示SD卡的圖片。一般的說遍歷文件夾也不算是耗時操作,這里只是簡單示范。一般的耗時操作是從網(wǎng)絡下載數(shù)據(jù),或本地移動大文件等等。五.同一個程序中 Service和Activity 通信的一些方式,這里展示主要代碼。這里組件不要忘記在 AndroidManifest 中注冊(一)使用 Intent來傳遞數(shù)據(jù)1.MainActivity 中的代碼,發(fā)送數(shù)據(jù)Intentintent=newIntent(this,MyService.class);intent.putExtra("msg","activity向service傳遞一個helloservice");startService(intent);2.MyService中的代碼,接收數(shù)據(jù)這里要使用 onStartCommand的方法來接收 Intent的數(shù)據(jù),如果上面使用的是 bind的方法來啟動服務,這里可以在 onBind方法中接收數(shù)據(jù)。@OverridepublicintonStartCommand(Intentintent,intflags,intstartId){Log.e("onStartCommand",intent.getStringExtra(msg));returnsuper.onStartCommand(intent,flags,startId);}(二)使用單例模式來傳遞數(shù)據(jù)這個方法算是有點麻煩的吧!這里要在MyService類中先做好單例,然后在Activity中調(diào)用MyService對象的方法1.MyService中的代碼//定義一個靜態(tài)的類變量,單例的使用準備privatestaticMyServiceinstance;//靜態(tài)方法,返回的是一個本類對象//為了能讓另一邊的類調(diào)用 Myservice的方法publicstaticMyServicegetInstance(){returninstance;}@OverridepublicvoidonCreate(){super.onCreate();//單例模式變量賦值instance=this;}publicvoidprint(Stringmsg){Log.e("service",msg);}其中print方法是在 Activity 中調(diào)用的,可以達到傳送數(shù)據(jù)給 MyService,但是這里要先啟動過服務后才能使用單例,因為這里是在 MyService的onCreate方法中把對象賦值給instance,之后才能實現(xiàn)單例。2.MainActivity 中的代碼:/**單例模式傳參*MyService這里通過一個靜態(tài)方法,來獲得 MyService這里通過 MyService.getInstance()方法來獲得 MyService對象

的對象*///必須保證

Myservice

對象不能為

null//靜態(tài)的變量,最后釋放(不用的時候,手動將

static變量=null)if(MyService.getInstance()!=null){MyService.getInstance().print("

使用單例從

activity

中調(diào)用

service的方法

");}(三)廣播傳參傳數(shù)據(jù)弄兩個廣播接收者相互傳數(shù)據(jù)。這里要在MyService和MyService中分別動態(tài)的創(chuàng)建廣播接收者和動態(tài)注冊廣播接收者,然后在MainActivity中發(fā)送廣播,在MyService中接收到廣播傳來遞數(shù)據(jù)后,在發(fā)送廣播,讓MainActivity接收廣播數(shù)據(jù)!1.MyService中的代碼:@OverridepublicvoidonCreate(){super.onCreate();//動態(tài)注冊廣播接收者 ,要定義好接收的 action屬性值IntentFilterfilter=newIntentFilter("service");registerReceiver(serviceReceiver,filter);}//定義一個廣播接收者 BroadcastReceiverBroadcastReceiverserviceReceiver=newBroadcastReceiver(){@OverridepublicvoidonReceive(Contextcontext,Intentintent){Log.e("service","接收到了activity發(fā)送的廣播:"+intent.getStringExtra("msg"));//發(fā)送廣播給MainActivitysendBroadcast(newIntent("activity").putExtra("msg"," 發(fā)送給activity的消息"));}};2.MainActivity 中的代碼:@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);//注冊本類內(nèi)的廣播 ,定義好action的屬性值IntentFilterfilter=newIntentFilter("activity");registerReceiver(activityReceiver,filter);}/**通過廣播來傳遞數(shù)據(jù)*/publicvoidsendBroadcast(Viewview){//指明action屬性值Intentintent=newIntent("service");intent.putExtra("msg","activity 向廣播傳遞一個 hellobroadcast");sendBroadcast(intent);}//定義一個內(nèi)部類的廣播接收者,用于接收 MyService傳遞過來的數(shù)據(jù)BroadcastReceiveractivityReceiver=newBroadcastReceiver(){@OverridepublicvoidonReceive(Contextcontext,Intentintent){Log.e("activity",intent.getStringExtra("msg"));}};(四)

MyService

實例調(diào)用方法這個方法是最最麻煩的方法了!涉及到一個Binder類的使用!這里要被調(diào)用的方法其實不是MyService中的方法,而是里面的內(nèi)部接口的抽象方法,需要在MainActivity中去實現(xiàn)這個方法!但是,實際這個方法實在MyService中執(zhí)行的。1.MyService中的代碼://定義一個接口interfaceCallback{//定義兩個要實現(xiàn)的方法voidcall();voidstart();}//定義一個接口對象Callbackcallback;/***創(chuàng)建Binder類,很多很多的 Service就是通過 Binder機制來和客戶端通訊交互的。*/classMybinderextendsBinder{publicMyServicegetService(){returnMyS

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論