Android遠(yuǎn)程服務(wù)編寫和調(diào)用教程
網(wǎng)上汗牛充棟的文章都是介紹Android遠(yuǎn)程服務(wù)的,一個個將Binder機制、AIDL講得頭頭是道,然而沒有幾個人能夠給出清晰的范例說明如何用最快的方法學(xué)會編寫和調(diào)用一個Android遠(yuǎn)程服務(wù)。若你僅僅是想如何編寫或者調(diào)用Android的遠(yuǎn)程服務(wù),而懶得去理解Binder機制是如何運行的,那么本篇文章正好適合你。畢竟現(xiàn)在人人都會開車,但沒有幾個人明白發(fā)動機到底是如何運作的。
預(yù)備知識
讀者應(yīng)該有基本的java知識,和Android簡單app的開發(fā)經(jīng)驗。
環(huán)境
代碼運行環(huán)境:
1.ADT2014版本;
2.android:minSdkVersion=”8”;android:targetSdkVersion=”20”
3.workspace中已經(jīng)生成了appcompatv7,它的版本是android-22;
遠(yuǎn)程服務(wù)開發(fā)教程
在開始開發(fā)之前,先弄清楚幾個概念:
1. IPC:進(jìn)程間通信,你只需要知道Android是依賴這個東西來進(jìn)行遠(yuǎn)程服務(wù)調(diào)用的就可以了。
2. Binder機制:Android發(fā)明的一種IPC機制,據(jù)說非常非常的好,你就當(dāng)它是個黑盒子,通過這個黑盒子就可以進(jìn)行遠(yuǎn)程服務(wù)調(diào)用了,而且Android中的很多機制都是通過它實現(xiàn)的。
3. AIDL語言:一種專門用來寫遠(yuǎn)程接口的語言,看它的名字就知道了,Android Interface Definition
Language。AIDL語言可以被android提供的編譯器編譯為Java源代碼,這個Java源代碼將會被服務(wù)的和客戶端使用,用來簡化遠(yuǎn)程服務(wù)開發(fā)流程。如果你當(dāng)初玩過CORBA,那就更能明白什么是IDL語言了
4. IInterface接口、IBinder接口、IBinder類等等:都是用來實現(xiàn)Binder機制的接口和類,在本教程中,你就當(dāng)它們是Binder黑盒子的一部分,不需要了解。
再說一點,其實Android提供的ApiDemos中就有一個遠(yuǎn)程服務(wù)的標(biāo)準(zhǔn)范例,但是其一是它沒有將服務(wù)端和客戶端分開寫,其二是例子中摻雜了太多其他的功能,因此理解起來較為困難。這個例子是com.example.android.apis.app.RemoteService,有興趣的可以在看完本文后再去詳細(xì)研究。
第一步,創(chuàng)建一個普通Android應(yīng)用
應(yīng)用名為WxbRemoteService,這個應(yīng)用可以刪掉其Activity類,但是為了簡單,我們就保留所有自動創(chuàng)建的代碼。
第二步,編寫AIDL
AIDL語言的語法和Java其實很像,你甚至可以先編寫一個Java接口,然后刪掉public、protected、private這些權(quán)限限定詞即可。例子如下IWxbService.aidl:
package com.dumaisoft.wxbremoteservice; interface IWxbService { void setName(String name); String getName(); }
注意幾點:
1.接口名和aidl文件名相同。
2.接口和方法前不用加訪問權(quán)限修飾符public,private,protected等,也不能用final,static。
3.Aidl默認(rèn)支持的類型包話java基本類型(int、long、boolean等)和(String、List、Map、 CharSequence),使用這些類型時不需要import聲明。對于List和Map中的元素類型必須是Aidl支持的類型。如果使用自定義類型作 為參數(shù)或返回值,自定義類型必須實現(xiàn)Parcelable接口。
4.自定義類型和AIDL生成的其它接口類型在aidl描述文件中,應(yīng)該顯式import,即便在該類和定義的包在同一個包中。
5.在aidl文件中所有非Java基本類型參數(shù)必須加上in、out、inout標(biāo)記,以指明參數(shù)是輸入?yún)?shù)、輸出參數(shù)還是輸入輸出參數(shù)。
6.Java原始類型默認(rèn)的標(biāo)記為in,不能為其它標(biāo)記
IWxbService.aidl文件的位置是在com.dumaisoft.wxbremoteservice包中,只要語法正確,則會在ADT的gen目錄下的com.dumaisoft.wxbremoteservice包中生成java文件IWxbService.java。
IWxbService.aidl定義了一個遠(yuǎn)程接口,它包含兩個方法getName和setName。
第三步,編寫服務(wù)類
添加一個WxbService類,它繼承了Service類,源代碼如下:
package com.dumaisoft.wxbremoteservice; import com.dumaisoft.wxbremoteservice.IWxbService.Stub; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; public class WxbService extends Service { private ServiceImpl serviceImpl; //繼承由IWxbService.aidl生成的com.dumaisoft.wxbremoteservice.IWxbService.Stub類 class ServiceImpl extends Stub{ private String _name; @Override public void setName(String name) throws RemoteException { _name = name; } @Override public String getName() throws RemoteException { return _name; } } //將ServiceImpl做一個簡單的單例模式 private ServiceImpl getInstance(){ if(serviceImpl == null){ serviceImpl = new ServiceImpl(); } return serviceImpl; } @Override public IBinder onBind(Intent intent) { return getInstance(); } }
通過研究代碼可知,和普通的服務(wù)類相比,遠(yuǎn)程服務(wù)類最大的區(qū)別就是它擁有一個名為ServiceImpl的成員變量,這個成員變量繼承了Stub類,并實現(xiàn)了Stub類的getName和setName方法。這個Stub類就是由 IWxbService.aidl生成的IWxbService.java提供的。我們不用研究其源代碼,只用知道它的用法:
第一:讓Service的一個成員變量繼承Stub,并實現(xiàn)遠(yuǎn)程接口的方法;
第二:在Service的onBind方法中返回一個Stub子類的實例。
第四步,配置AndroidManifest.xml
加上如下代碼:
<service android:name="WxbService"> <intent-filter> <action android:name="com.dumaisoft.wxbremoteservice.REMOTE_SREVICE"/> </intent-filter> </service>
注意action的name為”com.dumaisoft.wxbremoteservice.REMOTE_SREVICE”,這個由開發(fā)者保證不重名即可。
第五步,安裝app到手機上
安裝完成后,你的遠(yuǎn)程服務(wù)就被注冊到Binder黑盒子中了,任何客戶端只要知道你的遠(yuǎn)程服務(wù)action名稱和接口,就可以bind服務(wù),并調(diào)用接口。
遠(yuǎn)程服務(wù)調(diào)用教程
第一步,創(chuàng)建一個android應(yīng)用
應(yīng)用名為WxbRemoteServiceClient,src包中自動生成了com.dumaisoft.wxbremoteserviceclient包。
第二步,引入遠(yuǎn)程服務(wù)的AIDL文件
在src包中創(chuàng)建com.dumaisoft.wxbremoteservice包(為了與服務(wù)端的包名相同),然后將上面編寫的IWxbService.aidl文件拷貝入此目錄。顯然,在本工程的gen目錄中也生成了IWxbService.java文件。
第三步,編寫調(diào)用遠(yuǎn)程服務(wù)的代碼
代碼如下:
package com.dumaisoft.wxbremoteserviceclient; import com.dumaisoft.wxbremoteservice.IWxbService; import android.app.Activity; import android.app.Service; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.Toast; public class MainActivity extends Activity { private Button btnBind; private Button btnSetName; private Button btnGetName; private IWxbService serviceProxy; //遠(yuǎn)程服務(wù)的代理 private ServiceConnection conn = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { } @Override public void onServiceConnected(ComponentName name, IBinder service) { //獲取遠(yuǎn)程服務(wù)代理 serviceProxy = IWxbService.Stub.asInterface(service); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btnBind = (Button) this.findViewById(R.id.btnBind); btnSetName = (Button) this.findViewById(R.id.btnSetName); btnGetName = (Button) this.findViewById(R.id.btnGetName); btnBind.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent service = new Intent(); //Remote Service Action name service.setAction("com.dumaisoft.wxbremoteservice.REMOTE_SREVICE"); bindService(service, conn, Service.BIND_AUTO_CREATE); } }); btnSetName.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { try { serviceProxy.setName("MyName"); } catch (RemoteException e) { e.printStackTrace(); } } }); btnGetName.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { try { String name = serviceProxy.getName(); Toast.makeText(getApplicationContext(), name, Toast.LENGTH_LONG).show(); } catch (RemoteException e) { e.printStackTrace(); } } }); } }
注意幾點:
一、創(chuàng)建一個ServiceConnection的匿名子類,在其onServiceConnected方法中獲取遠(yuǎn)程服務(wù)代理對象serviceProxy。事實上,onServiceConnected方法會在bindService方法調(diào)用時被調(diào)用,因此能確保一定可以獲得遠(yuǎn)程服務(wù)的代理對象;
二、IWxbService.Stub.asInterface(service)方法也是由IWxbService.java文件提供的,其內(nèi)部機制不用研究,只需要知道它會返回一個IWxbService接口的對象,該對象可以通過Binder黑盒子調(diào)用遠(yuǎn)程服務(wù)的setName和getName方法;
三、使用Intent指定action為”com.dumaisoft.wxbremoteservice.REMOTE_SREVICE”,即可正確的bind到遠(yuǎn)程服務(wù)。
四、bind成功后,就可以通過遠(yuǎn)程服務(wù)的代理對象,使用遠(yuǎn)程服務(wù)的功能了。
小結(jié)
至此,讀者應(yīng)該能比較快速的開發(fā)出一個遠(yuǎn)程服務(wù),并能編寫客戶端輕松的調(diào)用它了。還有一點需要說明的是,除了使用AIDL來進(jìn)行遠(yuǎn)程服務(wù)的編寫和調(diào)用外,還可以直接使用IBinder、Binder等接口和類來進(jìn)行遠(yuǎn)程服務(wù)編寫調(diào)用。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助。
- 利用ASP從遠(yuǎn)程服務(wù)器上接收XML數(shù)據(jù)的方法
- ColdFusion MX 遠(yuǎn)程服務(wù)實例入門教程
- 可以從一臺遠(yuǎn)程服務(wù)器運行 SP2 安裝程序Install.vbs
- C# FTP,GetResponse(),遠(yuǎn)程服務(wù)器返回錯誤
- 將MSSQL Server 導(dǎo)入/導(dǎo)出到遠(yuǎn)程服務(wù)器教程的圖文方法分享
- python 從遠(yuǎn)程服務(wù)器下載東西的代碼
- python 從遠(yuǎn)程服務(wù)器下載日志文件的程序
- java判斷遠(yuǎn)程服務(wù)器上的文件是否存在的方法
- 利用xcopy命令實現(xiàn)本地文件復(fù)制到遠(yuǎn)程服務(wù)器的方法
相關(guān)文章
android仿360加速球?qū)崿F(xiàn)內(nèi)存釋放
本篇文章實現(xiàn)了Android仿360加速球?qū)崿F(xiàn)內(nèi)存釋放,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-10-10Android自定義ViewPager實現(xiàn)個性化的圖片切換效果
這篇文章主要介紹了Android自定義ViewPager實現(xiàn)個性化的圖片切換效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-05-05Android Activity與Fragment實現(xiàn)底部導(dǎo)航器
這篇文章主要介紹了Android Activity與Fragment實現(xiàn)底部導(dǎo)航器的相關(guān)資料,并附實例代碼,需要的朋友可以參考下2016-11-11Android編程處理窗口控件大小,形狀,像素等UI元素工具類
這篇文章主要介紹了Android編程處理窗口控件大小,形狀,像素等UI元素工具類,可實現(xiàn)像素與dp的轉(zhuǎn)換、窗口寬度設(shè)置、彈出窗口中l(wèi)istview高度設(shè)置等功能,需要的朋友可以參考下2017-12-12Android基于ViewPager+Fragment實現(xiàn)左右滑屏效果的方法
這篇文章主要介紹了Android基于ViewPager+Fragment實現(xiàn)左右滑屏效果的方法,結(jié)合實例形式分析了Android實現(xiàn)滑屏效果的布局與滑動功能相關(guān)操作技巧,需要的朋友可以參考下2017-07-07