Android遠(yuǎn)程服務(wù)編寫(xiě)和調(diào)用教程
網(wǎng)上汗牛充棟的文章都是介紹Android遠(yuǎn)程服務(wù)的,一個(gè)個(gè)將Binder機(jī)制、AIDL講得頭頭是道,然而沒(méi)有幾個(gè)人能夠給出清晰的范例說(shuō)明如何用最快的方法學(xué)會(huì)編寫(xiě)和調(diào)用一個(gè)Android遠(yuǎn)程服務(wù)。若你僅僅是想如何編寫(xiě)或者調(diào)用Android的遠(yuǎn)程服務(wù),而懶得去理解Binder機(jī)制是如何運(yùn)行的,那么本篇文章正好適合你。畢竟現(xiàn)在人人都會(huì)開(kāi)車(chē),但沒(méi)有幾個(gè)人明白發(fā)動(dòng)機(jī)到底是如何運(yùn)作的。
預(yù)備知識(shí)
讀者應(yīng)該有基本的java知識(shí),和Android簡(jiǎn)單app的開(kāi)發(fā)經(jīng)驗(yàn)。
環(huán)境
代碼運(yùn)行環(huán)境:
1.ADT2014版本;
2.android:minSdkVersion=”8”;android:targetSdkVersion=”20”
3.workspace中已經(jīng)生成了appcompatv7,它的版本是android-22;
遠(yuǎn)程服務(wù)開(kāi)發(fā)教程
在開(kāi)始開(kāi)發(fā)之前,先弄清楚幾個(gè)概念:
1. IPC:進(jìn)程間通信,你只需要知道Android是依賴這個(gè)東西來(lái)進(jìn)行遠(yuǎn)程服務(wù)調(diào)用的就可以了。
2. Binder機(jī)制:Android發(fā)明的一種IPC機(jī)制,據(jù)說(shuō)非常非常的好,你就當(dāng)它是個(gè)黑盒子,通過(guò)這個(gè)黑盒子就可以進(jìn)行遠(yuǎn)程服務(wù)調(diào)用了,而且Android中的很多機(jī)制都是通過(guò)它實(shí)現(xiàn)的。
3. AIDL語(yǔ)言:一種專門(mén)用來(lái)寫(xiě)遠(yuǎn)程接口的語(yǔ)言,看它的名字就知道了,Android Interface Definition
Language。AIDL語(yǔ)言可以被android提供的編譯器編譯為Java源代碼,這個(gè)Java源代碼將會(huì)被服務(wù)的和客戶端使用,用來(lái)簡(jiǎn)化遠(yuǎn)程服務(wù)開(kāi)發(fā)流程。如果你當(dāng)初玩過(guò)CORBA,那就更能明白什么是IDL語(yǔ)言了
4. IInterface接口、IBinder接口、IBinder類(lèi)等等:都是用來(lái)實(shí)現(xiàn)Binder機(jī)制的接口和類(lèi),在本教程中,你就當(dāng)它們是Binder黑盒子的一部分,不需要了解。
再說(shuō)一點(diǎn),其實(shí)Android提供的ApiDemos中就有一個(gè)遠(yuǎn)程服務(wù)的標(biāo)準(zhǔn)范例,但是其一是它沒(méi)有將服務(wù)端和客戶端分開(kāi)寫(xiě),其二是例子中摻雜了太多其他的功能,因此理解起來(lái)較為困難。這個(gè)例子是com.example.android.apis.app.RemoteService,有興趣的可以在看完本文后再去詳細(xì)研究。
第一步,創(chuàng)建一個(gè)普通Android應(yīng)用
應(yīng)用名為WxbRemoteService,這個(gè)應(yīng)用可以刪掉其Activity類(lèi),但是為了簡(jiǎn)單,我們就保留所有自動(dòng)創(chuàng)建的代碼。
第二步,編寫(xiě)AIDL
AIDL語(yǔ)言的語(yǔ)法和Java其實(shí)很像,你甚至可以先編寫(xiě)一個(gè)Java接口,然后刪掉public、protected、private這些權(quán)限限定詞即可。例子如下IWxbService.aidl:
package com.dumaisoft.wxbremoteservice;
interface IWxbService {
void setName(String name);
String getName();
}
注意幾點(diǎn):
1.接口名和aidl文件名相同。
2.接口和方法前不用加訪問(wèn)權(quán)限修飾符public,private,protected等,也不能用final,static。
3.Aidl默認(rèn)支持的類(lèi)型包話java基本類(lèi)型(int、long、boolean等)和(String、List、Map、 CharSequence),使用這些類(lèi)型時(shí)不需要import聲明。對(duì)于List和Map中的元素類(lèi)型必須是Aidl支持的類(lèi)型。如果使用自定義類(lèi)型作 為參數(shù)或返回值,自定義類(lèi)型必須實(shí)現(xiàn)Parcelable接口。
4.自定義類(lèi)型和AIDL生成的其它接口類(lèi)型在aidl描述文件中,應(yīng)該顯式import,即便在該類(lèi)和定義的包在同一個(gè)包中。
5.在aidl文件中所有非Java基本類(lèi)型參數(shù)必須加上in、out、inout標(biāo)記,以指明參數(shù)是輸入?yún)?shù)、輸出參數(shù)還是輸入輸出參數(shù)。
6.Java原始類(lèi)型默認(rèn)的標(biāo)記為in,不能為其它標(biāo)記
IWxbService.aidl文件的位置是在com.dumaisoft.wxbremoteservice包中,只要語(yǔ)法正確,則會(huì)在ADT的gen目錄下的com.dumaisoft.wxbremoteservice包中生成java文件IWxbService.java。
IWxbService.aidl定義了一個(gè)遠(yuǎn)程接口,它包含兩個(gè)方法getName和setName。
第三步,編寫(xiě)服務(wù)類(lèi)
添加一個(gè)WxbService類(lèi),它繼承了Service類(lèi),源代碼如下:
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類(lèi)
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做一個(gè)簡(jiǎn)單的單例模式
private ServiceImpl getInstance(){
if(serviceImpl == null){
serviceImpl = new ServiceImpl();
}
return serviceImpl;
}
@Override
public IBinder onBind(Intent intent) {
return getInstance();
}
}
通過(guò)研究代碼可知,和普通的服務(wù)類(lèi)相比,遠(yuǎn)程服務(wù)類(lèi)最大的區(qū)別就是它擁有一個(gè)名為ServiceImpl的成員變量,這個(gè)成員變量繼承了Stub類(lèi),并實(shí)現(xiàn)了Stub類(lèi)的getName和setName方法。這個(gè)Stub類(lèi)就是由 IWxbService.aidl生成的IWxbService.java提供的。我們不用研究其源代碼,只用知道它的用法:
第一:讓Service的一個(gè)成員變量繼承Stub,并實(shí)現(xiàn)遠(yuǎn)程接口的方法;
第二:在Service的onBind方法中返回一個(gè)Stub子類(lèi)的實(shí)例。
第四步,配置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”,這個(gè)由開(kāi)發(fā)者保證不重名即可。
第五步,安裝app到手機(jī)上
安裝完成后,你的遠(yuǎn)程服務(wù)就被注冊(cè)到Binder黑盒子中了,任何客戶端只要知道你的遠(yuǎn)程服務(wù)action名稱和接口,就可以bind服務(wù),并調(diào)用接口。
遠(yuǎn)程服務(wù)調(diào)用教程
第一步,創(chuàng)建一個(gè)android應(yīng)用
應(yīng)用名為WxbRemoteServiceClient,src包中自動(dòng)生成了com.dumaisoft.wxbremoteserviceclient包。
第二步,引入遠(yuǎn)程服務(wù)的AIDL文件
在src包中創(chuàng)建com.dumaisoft.wxbremoteservice包(為了與服務(wù)端的包名相同),然后將上面編寫(xiě)的IWxbService.aidl文件拷貝入此目錄。顯然,在本工程的gen目錄中也生成了IWxbService.java文件。
第三步,編寫(xiě)調(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();
}
}
});
}
}
注意幾點(diǎn):
一、創(chuàng)建一個(gè)ServiceConnection的匿名子類(lèi),在其onServiceConnected方法中獲取遠(yuǎn)程服務(wù)代理對(duì)象serviceProxy。事實(shí)上,onServiceConnected方法會(huì)在bindService方法調(diào)用時(shí)被調(diào)用,因此能確保一定可以獲得遠(yuǎn)程服務(wù)的代理對(duì)象;
二、IWxbService.Stub.asInterface(service)方法也是由IWxbService.java文件提供的,其內(nèi)部機(jī)制不用研究,只需要知道它會(huì)返回一個(gè)IWxbService接口的對(duì)象,該對(duì)象可以通過(guò)Binder黑盒子調(diào)用遠(yuǎn)程服務(wù)的setName和getName方法;
三、使用Intent指定action為”com.dumaisoft.wxbremoteservice.REMOTE_SREVICE”,即可正確的bind到遠(yuǎn)程服務(wù)。
四、bind成功后,就可以通過(guò)遠(yuǎn)程服務(wù)的代理對(duì)象,使用遠(yuǎn)程服務(wù)的功能了。
小結(jié)
至此,讀者應(yīng)該能比較快速的開(kāi)發(fā)出一個(gè)遠(yuǎn)程服務(wù),并能編寫(xiě)客戶端輕松的調(diào)用它了。還有一點(diǎn)需要說(shuō)明的是,除了使用AIDL來(lái)進(jìn)行遠(yuǎn)程服務(wù)的編寫(xiě)和調(diào)用外,還可以直接使用IBinder、Binder等接口和類(lèi)來(lái)進(jìn)行遠(yuǎn)程服務(wù)編寫(xiě)調(diào)用。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助。
- 利用ASP從遠(yuǎn)程服務(wù)器上接收XML數(shù)據(jù)的方法
- ColdFusion MX 遠(yuǎn)程服務(wù)實(shí)例入門(mén)教程
- 可以從一臺(tái)遠(yuǎn)程服務(wù)器運(yùn)行 SP2 安裝程序Install.vbs
- C# FTP,GetResponse(),遠(yuǎn)程服務(wù)器返回錯(cuò)誤
- 將MSSQL Server 導(dǎo)入/導(dǎo)出到遠(yuǎn)程服務(wù)器教程的圖文方法分享
- python 從遠(yuǎn)程服務(wù)器下載東西的代碼
- python 從遠(yuǎn)程服務(wù)器下載日志文件的程序
- java判斷遠(yuǎn)程服務(wù)器上的文件是否存在的方法
- 利用xcopy命令實(shí)現(xiàn)本地文件復(fù)制到遠(yuǎn)程服務(wù)器的方法
相關(guān)文章
從源代碼分析Android Universal ImageLoader的緩存處理機(jī)制
這篇文章主要介紹了從源代碼分析Android Universal ImageLoader的緩存處理機(jī)制 的相關(guān)資料,需要的朋友可以參考下2016-01-01
Android集成GreenDao數(shù)據(jù)庫(kù)的操作步驟
這篇文章主要介紹了Android集成GreenDao數(shù)據(jù)庫(kù),使用數(shù)據(jù)庫(kù)存儲(chǔ)時(shí)候,一般都會(huì)使用一些第三方ORM框架,比如GreenDao,本文分幾步給大家介紹Android集成GreenDao數(shù)據(jù)庫(kù)的方法,需要的朋友可以參考下2022-10-10
Android?Studio中如何修改APP圖標(biāo)和APP名稱
這篇文章主要介紹了Android?Studio中如何修改APP圖標(biāo)和APP名稱,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11
Android RecyclerView使用GridLayoutManager間距設(shè)置的方法
本篇文章主要介紹了Android RecyclerView使用GridLayoutManager間距設(shè)置的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12
Android FlowLayout流式布局實(shí)現(xiàn)詳解
這篇文章主要為大家詳細(xì)介紹了Android FlowLayout流式布局的實(shí)現(xiàn)方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-09-09
Flutter進(jìn)階之實(shí)現(xiàn)動(dòng)畫(huà)效果(十)
這篇文章主要為大家詳細(xì)介紹了Flutter進(jìn)階之實(shí)現(xiàn)動(dòng)畫(huà)效果的第十篇,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-08-08

