国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
Android Service完全解析,關(guān)于服務(wù)你所需知道的一切(下)

轉(zhuǎn)載請(qǐng)注冊(cè)出處:http://blog.csdn.net/guolin_blog/article/details/9797169

在上一篇文章中,我們學(xué)習(xí)了Android Service相關(guān)的許多重要內(nèi)容,包括Service的基本用法、Service和Activity進(jìn)行通信、Service的銷毀方式、Service與Thread的關(guān)系、以及如何創(chuàng)建前臺(tái)Service。以上所提到的這些知識(shí)點(diǎn),基本上涵蓋了大部分日常開發(fā)工作當(dāng)中可能使用到的Service技術(shù)。不過關(guān)于Service其實(shí)還有一個(gè)更加高端的使用技巧沒有介紹,即遠(yuǎn)程Service的用法。使用遠(yuǎn)程Service甚至可以實(shí)現(xiàn)Android跨進(jìn)程通信的功能,下面就讓我們具體地學(xué)習(xí)一下。

如果你還沒有看過前面一篇文章,建議先去閱讀一下 Android Service完全解析,關(guān)于服務(wù)你所需知道的一切(上) ,因?yàn)楸酒恼轮猩婕暗降拇a是在上篇文章的基礎(chǔ)上進(jìn)行修改的。

在上篇文章中我們知道了,Service其實(shí)是運(yùn)行在主線程里的,如果直接在Service中處理一些耗時(shí)的邏輯,就會(huì)導(dǎo)致程序ANR。

讓我們來做個(gè)實(shí)驗(yàn)驗(yàn)證一下吧,修改上一篇文章中創(chuàng)建的ServiceTest項(xiàng)目,在MyService的onCreate()方法中讓線程睡眠60秒,如下所示:

  1. public class MyService extends Service {  
  2.   
  3.     ......  
  4.   
  5.     @Override  
  6.     public void onCreate() {  
  7.         super.onCreate();  
  8.         Log.d(TAG, "onCreate() executed");  
  9.         try {  
  10.             Thread.sleep(60000);  
  11.         } catch (InterruptedException e) {  
  12.             e.printStackTrace();  
  13.         }  
  14.     }  
  15.       
  16.     ......  
  17.   
  18. }  

重新運(yùn)行后,點(diǎn)擊一下Start Service按鈕或Bind Service按鈕,程序就會(huì)阻塞住并無法進(jìn)行任何其它操作,過一段時(shí)間后就會(huì)彈出ANR的提示框,如下圖所示。

                                                        

之前我們提到過,應(yīng)該在Service中開啟線程去執(zhí)行耗時(shí)任務(wù),這樣就可以有效地避免ANR的出現(xiàn)。

那么本篇文章的主題是介紹遠(yuǎn)程Service的用法,如果將MyService轉(zhuǎn)換成一個(gè)遠(yuǎn)程Service,還會(huì)不會(huì)有ANR的情況呢?讓我們來動(dòng)手嘗試一下吧。

將一個(gè)普通的Service轉(zhuǎn)換成遠(yuǎn)程Service其實(shí)非常簡(jiǎn)單,只需要在注冊(cè)Service的時(shí)候?qū)⑺腶ndroid:process屬性指定成:remote就可以了,代碼如下所示:

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     package="com.example.servicetest"  
  4.     android:versionCode="1"  
  5.     android:versionName="1.0" >  
  6.   
  7.     ......  
  8.       
  9.     <service  
  10.         android:name="com.example.servicetest.MyService"  
  11.         android:process=":remote" >  
  12.     </service>  
  13.   
  14. </manifest>  
現(xiàn)在重新運(yùn)行程序,并點(diǎn)擊一下Start Service按鈕,你會(huì)看到控制臺(tái)立刻打印了onCreate() executed的信息,而且主界面并沒有阻塞住,也不會(huì)出現(xiàn)ANR。大概過了一分鐘后,又會(huì)看到onStartCommand() executed打印了出來。

為什么將MyService轉(zhuǎn)換成遠(yuǎn)程Service后就不會(huì)導(dǎo)致程序ANR了呢?這是由于,使用了遠(yuǎn)程Service后,MyService已經(jīng)在另外一個(gè)進(jìn)程當(dāng)中運(yùn)行了,所以只會(huì)阻塞該進(jìn)程中的主線程,并不會(huì)影響到當(dāng)前的應(yīng)用程序。
為了證實(shí)一下MyService現(xiàn)在確實(shí)已經(jīng)運(yùn)行在另外一個(gè)進(jìn)程當(dāng)中了,我們分別在MainActivity的onCreate()方法和MyService的onCreate()方法里加入一行日志,打印出各自所在的進(jìn)程id,如下所示:

  1. Log.d("TAG""process id is " + Process.myPid());  
再次重新運(yùn)行程序,然后點(diǎn)擊一下Start Service按鈕,打印結(jié)果如下圖所示:

                       

可以看到,不僅僅是進(jìn)程id不同了,就連應(yīng)用程序包名也不一樣了,MyService中打印的那條日志,包名后面還跟上了:remote標(biāo)識(shí)。

那既然遠(yuǎn)程Service這么好用,干脆以后我們把所有的Service都轉(zhuǎn)換成遠(yuǎn)程Service吧,還省得再開啟線程了。其實(shí)不然,遠(yuǎn)程Service非但不好用,甚至可以稱得上是較為難用。一般情況下如果可以不使用遠(yuǎn)程Service,就盡量不要使用它。

下面就來看一下它的弊端吧,首先將MyService的onCreate()方法中讓線程睡眠的代碼去除掉,然后重新運(yùn)行程序,并點(diǎn)擊一下Bind Service按鈕,你會(huì)發(fā)現(xiàn)程序崩潰了!為什么點(diǎn)擊Start Service按鈕程序就不會(huì)崩潰,而點(diǎn)擊Bind Service按鈕就會(huì)崩潰呢?這是由于在Bind Service按鈕的點(diǎn)擊事件里面我們會(huì)讓MainActivity和MyService建立關(guān)聯(lián),但是目前MyService已經(jīng)是一個(gè)遠(yuǎn)程Service了,Activity和Service運(yùn)行在兩個(gè)不同的進(jìn)程當(dāng)中,這時(shí)就不能再使用傳統(tǒng)的建立關(guān)聯(lián)的方式,程序也就崩潰了。

那么如何才能讓Activity與一個(gè)遠(yuǎn)程Service建立關(guān)聯(lián)呢?這就要使用AIDL來進(jìn)行跨進(jìn)程通信了(IPC)。

AIDL(Android Interface Definition Language)是Android接口定義語言的意思,它可以用于讓某個(gè)Service與多個(gè)應(yīng)用程序組件之間進(jìn)行跨進(jìn)程通信,從而可以實(shí)現(xiàn)多個(gè)應(yīng)用程序共享同一個(gè)Service的功能。

下面我們就來一步步地看一下AIDL的用法到底是怎樣的。首先需要新建一個(gè)AIDL文件,在這個(gè)文件中定義好Activity需要與Service進(jìn)行通信的方法。新建MyAIDLService.aidl文件,代碼如下所示:

  1. package com.example.servicetest;  
  2. interface MyAIDLService {  
  3.     int plus(int a, int b);  
  4.     String removeSpace(String str);  
  5. }  
點(diǎn)擊保存之后,gen目錄下就會(huì)生成一個(gè)對(duì)應(yīng)的Java文件,如下圖所示:

                                             

然后修改MyService中的代碼,在里面實(shí)現(xiàn)我們剛剛定義好的MyAIDLService接口,如下所示:

  1. public class MyService extends Service {  
  2.   
  3.     ......  
  4.   
  5.     @Override  
  6.     public IBinder onBind(Intent intent) {  
  7.         return mBinder;  
  8.     }  
  9.   
  10.     MyAIDLService.Stub mBinder = new Stub() {  
  11.   
  12.         @Override  
  13.         public String toUpperCase(String str) throws RemoteException {  
  14.             if (str != null) {  
  15.                 return str.toUpperCase();  
  16.             }  
  17.             return null;  
  18.         }  
  19.   
  20.         @Override  
  21.         public int plus(int a, int b) throws RemoteException {  
  22.             return a + b;  
  23.         }  
  24.     };  
  25.   
  26. }  
這里先是對(duì)MyAIDLService.Stub進(jìn)行了實(shí)現(xiàn),重寫里了toUpperCase()和plus()這兩個(gè)方法。這兩個(gè)方法的作用分別是將一個(gè)字符串全部轉(zhuǎn)換成大寫格式,以及將兩個(gè)傳入的整數(shù)進(jìn)行相加。然后在onBind()方法中將MyAIDLService.Stub的實(shí)現(xiàn)返回。這里為什么可以這樣寫呢?因?yàn)镾tub其實(shí)就是Binder的子類,所以在onBind()方法中可以直接返回Stub的實(shí)現(xiàn)。

接下來修改MainActivity中的代碼,如下所示:

  1. public class MainActivity extends Activity implements OnClickListener {  
  2.   
  3.     private Button startService;  
  4.   
  5.     private Button stopService;  
  6.   
  7.     private Button bindService;  
  8.   
  9.     private Button unbindService;  
  10.       
  11.     private MyAIDLService myAIDLService;  
  12.   
  13.     private ServiceConnection connection = new ServiceConnection() {  
  14.   
  15.         @Override  
  16.         public void onServiceDisconnected(ComponentName name) {  
  17.         }  
  18.   
  19.         @Override  
  20.         public void onServiceConnected(ComponentName name, IBinder service) {  
  21.             myAIDLService = MyAIDLService.Stub.asInterface(service);  
  22.             try {  
  23.                 int result = myAIDLService.plus(35);  
  24.                 String upperStr = myAIDLService.toUpperCase("hello world");  
  25.                 Log.d("TAG""result is " + result);  
  26.                 Log.d("TAG""upperStr is " + upperStr);  
  27.             } catch (RemoteException e) {  
  28.                 e.printStackTrace();  
  29.             }  
  30.         }  
  31.     };  
  32.   
  33.     ......  
  34.   
  35. }  
我們只是修改了ServiceConnection中的代碼??梢钥吹剑@里首先使用了MyAIDLService.Stub.asInterface()方法將傳入的IBinder對(duì)象傳換成了MyAIDLService對(duì)象,接下來就可以調(diào)用在MyAIDLService.aidl文件中定義的所有接口了。這里我們先是調(diào)用了plus()方法,并傳入了3和5作為參數(shù),然后又調(diào)用了toUpperCase()方法,并傳入hello world字符串作為參數(shù),最后將調(diào)用方法的返回結(jié)果打印出來。

現(xiàn)在重新運(yùn)行程序,并點(diǎn)擊一下Bind Service按鈕,可以看到打印日志如下所示:

                               


由此可見,我們確實(shí)已經(jīng)成功實(shí)現(xiàn)跨進(jìn)程通信了,在一個(gè)進(jìn)程中訪問到了另外一個(gè)進(jìn)程中的方法。

不過你也可以看出,目前的跨進(jìn)程通信其實(shí)并沒有什么實(shí)質(zhì)上的作用,因?yàn)檫@只是在一個(gè)Activity里調(diào)用了同一個(gè)應(yīng)用程序的Service里的方法。而跨進(jìn)程通信的真正意義是為了讓一個(gè)應(yīng)用程序去訪問另一個(gè)應(yīng)用程序中的Service,以實(shí)現(xiàn)共享Service的功能。那么下面我們自然要學(xué)習(xí)一下,如何才能在其它的應(yīng)用程序中調(diào)用到MyService里的方法。

在上一篇文章中我們已經(jīng)知道,如果想要讓Activity與Service之間建立關(guān)聯(lián),需要調(diào)用bindService()方法,并將Intent作為參數(shù)傳遞進(jìn)去,在Intent里指定好要綁定的Service,示例代碼如下:

  1. Intent bindIntent = new Intent(this, MyService.class);  
  2. bindService(bindIntent, connection, BIND_AUTO_CREATE);  
這里在構(gòu)建Intent的時(shí)候是使用MyService.class來指定要綁定哪一個(gè)Service的,但是在另一個(gè)應(yīng)用程序中去綁定Service的時(shí)候并沒有MyService這個(gè)類,這時(shí)就必須使用到隱式Intent了?,F(xiàn)在修改AndroidManifest.xml中的代碼,給MyService加上一個(gè)action,如下所示:
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     package="com.example.servicetest"  
  4.     android:versionCode="1"  
  5.     android:versionName="1.0" >  
  6.   
  7.     ......  
  8.   
  9.     <service  
  10.         android:name="com.example.servicetest.MyService"  
  11.         android:process=":remote" >  
  12.         <intent-filter>  
  13.             <action android:name="com.example.servicetest.MyAIDLService"/>  
  14.         </intent-filter>  
  15.     </service>  
  16.   
  17. </manifest>  

這就說明,MyService可以響應(yīng)帶有com.example.servicetest.MyAIDLService這個(gè)action的Intent。

現(xiàn)在重新運(yùn)行一下程序,這樣就把遠(yuǎn)程Service端的工作全部完成了。

然后創(chuàng)建一個(gè)新的Android項(xiàng)目,起名為ClientTest,我們就嘗試在這個(gè)程序中遠(yuǎn)程調(diào)用MyService中的方法。

ClientTest中的Activity如果想要和MyService建立關(guān)聯(lián)其實(shí)也不難,首先需要將MyAIDLService.aidl文件從ServiceTest項(xiàng)目中拷貝過來,注意要將原有的包路徑一起拷貝過來,完成后項(xiàng)目的結(jié)構(gòu)如下圖所示:

                                     


然后打開或新建activity_main.xml,在布局文件中也加入一個(gè)Bind Service按鈕:

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     android:layout_width="match_parent"  
  3.     android:layout_height="match_parent"  
  4.     android:orientation="vertical"  
  5.      >  
  6.   
  7.    <Button   
  8.        android:id="@+id/bind_service"  
  9.        android:layout_width="match_parent"  
  10.        android:layout_height="wrap_content"  
  11.        android:text="Bind Service"  
  12.        />  
  13.   
  14. </LinearLayout>  
接下來打開或新建MainActivity,在其中加入和MyService建立關(guān)聯(lián)的代碼,如下所示:
  1. public class MainActivity extends Activity {  
  2.   
  3.     private MyAIDLService myAIDLService;  
  4.   
  5.     private ServiceConnection connection = new ServiceConnection() {  
  6.   
  7.         @Override  
  8.         public void onServiceDisconnected(ComponentName name) {  
  9.         }  
  10.   
  11.         @Override  
  12.         public void onServiceConnected(ComponentName name, IBinder service) {  
  13.             myAIDLService = MyAIDLService.Stub.asInterface(service);  
  14.             try {  
  15.                 int result = myAIDLService.plus(5050);  
  16.                 String upperStr = myAIDLService.toUpperCase("comes from ClientTest");  
  17.                 Log.d("TAG""result is " + result);  
  18.                 Log.d("TAG""upperStr is " + upperStr);  
  19.             } catch (RemoteException e) {  
  20.                 e.printStackTrace();  
  21.             }  
  22.         }  
  23.     };  
  24.   
  25.     @Override  
  26.     protected void onCreate(Bundle savedInstanceState) {  
  27.         super.onCreate(savedInstanceState);  
  28.         setContentView(R.layout.activity_main);  
  29.         Button bindService = (Button) findViewById(R.id.bind_service);  
  30.         bindService.setOnClickListener(new OnClickListener() {  
  31.             @Override  
  32.             public void onClick(View v) {  
  33.                 Intent intent = new Intent("com.example.servicetest.MyAIDLService");  
  34.                 bindService(intent, connection, BIND_AUTO_CREATE);  
  35.             }  
  36.         });  
  37.     }  
  38.   
  39. }  
這部分代碼大家一定會(huì)非常眼熟吧?沒錯(cuò),這和在ServiceTest的MainActivity中的代碼幾乎是完全相同的,只是在讓Activity和Service建立關(guān)聯(lián)的時(shí)候我們使用了隱式Intent,將Intent的action指定成了com.example.servicetest.MyAIDLService。

在當(dāng)前Activity和MyService建立關(guān)聯(lián)之后,我們?nèi)匀皇钦{(diào)用了plus()和toUpperCase()這兩個(gè)方法,遠(yuǎn)程的MyService會(huì)對(duì)傳入的參數(shù)進(jìn)行處理并返回結(jié)果,然后將結(jié)果打印出來。

這樣的話,ClientTest中的代碼也就全部完成了,現(xiàn)在運(yùn)行一下這個(gè)項(xiàng)目,然后點(diǎn)擊Bind Service按鈕,此時(shí)就會(huì)去和遠(yuǎn)程的MyService建立關(guān)聯(lián),觀察LogCat中的打印信息如下所示:

                            

不用我說,大家都已經(jīng)看出,我們的跨進(jìn)程通信功能已經(jīng)完美實(shí)現(xiàn)了。

不過還有一點(diǎn)需要說明的是,由于這是在不同的進(jìn)程之間傳遞數(shù)據(jù),Android對(duì)這類數(shù)據(jù)的格式支持是非常有限的,基本上只能傳遞Java的基本數(shù)據(jù)類型、字符串、List或Map等。那么如果我想傳遞一個(gè)自定義的類該怎么辦呢?這就必須要讓這個(gè)類去實(shí)現(xiàn)Parcelable接口,并且要給這個(gè)類也定義一個(gè)同名的AIDL文件。這部分內(nèi)容并不復(fù)雜,而且和Service關(guān)系不大,所以就不再詳細(xì)進(jìn)行講解了,感興趣的朋友可以自己去查閱一下相關(guān)的資料。

好了,結(jié)合上下兩篇,這就是關(guān)于Service你所需知道的一切。

如果喜歡我寫的文章,請(qǐng)小手一抖,為我投上一票,真心非常感謝你的支持。

投票地址:http://vote.blog.csdn.net/blogstaritem/blogstar2013/sinyu890807

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Android 綁定Service 實(shí)現(xiàn)android控制service的生命周期
Android AIDL(Android Interface Definition Language)介紹
android筆記
Binder與AIDL服務(wù)
android service
Android組件系列_Android Service組件深入解析
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服