Android service通过aidl 回调客户端 daemon
前端时间项目运用到AIDL,关于AIDL客户端以及AIDL服务端网络上没有一个比较完备的Demo.
而参考Demo无疑是一个比较快速的学习方法.因此,我写了一个Demo.
供大家参考,也非常欢迎大家对其中写的不好的地方进行指正.
好了,首先简述下基本功能:
在AIDL 客户端三个EditText中输入三个值,点击提交按钮,将这三个值传入到AIDL服务端进行处理.
服务端处理后会执行客户端的回调函数:在AIDL客户端界面进行刷新,并显示一个toast.
接下来看看代码结构:
需要注意的是,两个工程中com.harlan.demo.aidl包内部的文件必须保持一致.
(1)HarlanInfo.java:这是包中唯一的一个java文件,是一个数据结构,该类实现了Parcelable接口
[java]view plaincopyprint?
packagecom.harlan.demo.aidl;
importandroid.os.Parcel;
importandroid.os.Parcelable;
/**
*
*<一句话功能简述>
*Parcelable是Android特有的功能,效率比实现Serializable接口高
*
*@authorAdministrator
*@version[版本号,2012-12-10]
*@see[相关类/方法]
*@since[产品/模块版本]
*/
publicclassHarlanInfoimplementsParcelable
{
privateStringname;
privateintage;
privateStringplace;
publicStringgetName()
{
returnname;
}
publicvoidsetName(Stringname)
{
this.name=name;
}
publicintgetAge()
{
returnage;
}
publicvoidsetAge(intage)
{
this.age=age;
}
publicStringgetPlace()
{
returnplace;
}
publicvoidsetPlace(Stringplace)
{
this.place=place;
}
/**
*<默认构造函数>
*/
publicHarlanInfo()
{
}
/**
*<默认构造函数>
*/
publicHarlanInfo(Parcelin)
{
//注意顺序
name=in.readString();
age=in.readInt();
place=in.readString();
}
/**
*seemsmeaningless
*return0;
*/
@Override
publicintdescribeContents()
{
return0;
}
/**
*将对象序列化为一个Parcel对象
*可以将Parcel看成是一个流,通过writeToParcel把对象写到流里面,
*再通过createFromParcel从流里读取对象
*注意:写的顺序和读的顺序必须一致。
*/
@Override
publicvoidwriteToParcel(Parceldest,intflags)
{
dest.writeString(name);
dest.writeInt(age);
dest.writeString(place);
}
/**
*实例化静态内部对象CREATOR实现接口Parcelable.Creator
*publicstaticfinal一个都不能少,内部对象CREATOR的名称也不能改变,必须全部大写
*/
publicstaticfinalParcelable.Creator<HarlanInfo>CREATOR=newCreator<HarlanInfo>(){
//将Parcel对象反序列化为HarlanInfo
@Override
publicHarlanInfocreateFromParcel(Parcelsource)
{
HarlanInfohlInfo=newHarlanInfo(source);
returnhlInfo;
}
@Override
publicHarlanInfo[]newArray(intsize)
{
returnnewHarlanInfo[size];
}
};
}
(2)HarlanInfo.aidl :协同HarlanInfo.java文件"作战",缺一不可.
[java]view plaincopyprint?
packagecom.harlan.demo.aidl;
parcelableHarlanInfo;
(3)ICallBack.aidl:
这是客户端回调方法的接口,在客户端实现其具体方法,在服务端调用执行.
[java]view plaincopyprint?
packagecom.harlan.demo.aidl;
interfaceICallBack{
/**
*callbackofAIDLClient
*handlebyserver
**/
voidhandleByServer(Stringparam);
}
(4)ExecuteService.aidl:
这是从服务端获取数据方法的接口,在服务端实现其具体方法,在客户端调用执行.
参数info是由用户输入的数据构成的,同时传递的还要客户端回调方法的句柄,从而服务端可以调用客户端的回调方法.
该方法返回一个HarlanInfo的数据类型,客户端获得此数据,在界面上进行相应的显示.
[java]view plaincopyprint?
packagecom.harlan.demo.aidl;
importcom.harlan.demo.aidl.HarlanInfo;
importcom.harlan.demo.aidl.ICallBack;
interfaceExecuteServiceAIDL
{
/**
*getinfofromserverand
*Transferacallbackmethodshandle;
*ifoccurerror,willbereturnnull
*对于非基本数据类型和String和CharSequence类型,要加上方向指示
*包括in、out和inout,in表示由客户端设置,out表示由服务端设置,inout是两者均可设置。
*/
HarlanInfogetServerHarlanInfo(inHarlanInfoinfo,ICallBackicallback);
}
好了,现在对com.harlan.demo.aidl包已经大致了解,build一下project,发现gen文件夹下面多出来一个包:
包中文件可以随便看看,不看也没事.因为你只要在客户端服务端相应的位置实现对应的接口就可以了.
先来看看服务端,因为服务端相对简单些,不需要界面什么的,只是一个Service.
上代码:
[java]view plaincopyprint?
packagecom.harlan.demo.service;
importandroid.app.Service;
importandroid.content.Intent;
importandroid.os.IBinder;
importandroid.os.RemoteException;
importandroid.util.Log;
importcom.harlan.demo.aidl.ExecuteServiceAIDL;
importcom.harlan.demo.aidl.HarlanInfo;
importcom.harlan.demo.aidl.ICallBack;
publicclassAIDLServiceextendsService
{
publicstaticfinalStringTAG="AIDLService";
privateICallBackmCallBack;
/**
*绑定服务
*/
@Override
publicIBinderonBind(Intentintent)
{
//TODOAuto-generatedmethodstub
returnmBinder;
}
/**
*创建服务
*/
@Override
publicvoidonCreate()
{
super.onCreate();
}
/**
*销毁服务
*/
@Override
publicvoidonDestroy()
{
super.onDestroy();
}
/**
*启动服务
*/
@Override
publicvoidonStart(Intentintent,intstartId)
{
super.onStart(intent,startId);
}
/**
*解绑服务
*/
@Override
publicbooleanonUnbind(Intentintent)
{
mCallBack=null;
returnsuper.onUnbind(intent);
}
ExecuteServiceAIDL.StubmBinder=newExecuteServiceAIDL.Stub()
{
//这里实现了getServiceHarlanInfo接口
@Override
publicHarlanInfogetServerHarlanInfo(HarlanInfoinfo,ICallBackicallback)
throwsRemoteException
{
Log.d(TAG,"getServerHarlanInfo");
mCallBack=icallback;
mCallBack.handleByServer("Themsgisfromserver");
HarlanInfonewInfo=newHarlanInfo();
newInfo.setName(info.getName().toLowerCase());
newInfo.setAge(info.getAge()+10);
newInfo.setPlace("Home");
returnnewInfo;
}
};
}
一目了然,服务端主要的功能就是实现了aidl中的getServerHarlanInfo(HarlanInfo info, ICallBack icallback)接口.返回了一个mBinder供客户端调用.
写好了服务,还得在Manifest文件里面配置一下:
[java]view plaincopyprint?
<service
android:name=".AIDLService">
<intent-filter>
<actionandroid:name="com.harlan.demo.aidl.service"/>
</intent-filter>
lt;/service>
服务端写好了,就来客户端的了.客户端主要是一个activity,界面相对简单,如图所示:
界面布局相对简单,就不贴代码了.
下面贴ClientActivity的代码:
[java]view plaincopyprint?
packagecom.harlan.demo.activity;
importandroid.app.Activity;
importandroid.content.ComponentName;
importandroid.content.Intent;
importandroid.content.ServiceConnection;
importandroid.os.Bundle;
importandroid.os.IBinder;
importandroid.os.RemoteException;
importandroid.util.Log;
importandroid.view.View;
importandroid.widget.Button;
importandroid.widget.EditText;
importandroid.widget.Toast;
importcom.harlan.demo.aidl.ExecuteServiceAIDL;
importcom.harlan.demo.aidl.HarlanInfo;
importcom.harlan.demo.aidl.ICallBack;
publicclassClientActivityextendsActivity
{
publicstaticfinalStringTAG="ClientActivity";
privatestaticfinalStringBIND_ACTION="com.harlan.demo.aidl.service";
privateEditTextmEditTextName;
privateEditTextmEditTextAge;
privateEditTextmEditTextPlace;
privateButtonmButtonCommit;
privateExecuteServiceAIDLexecuteService;
@Override
protectedvoidonCreate(BundlesavedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_client);
getView();
//用户点击提交按钮,将数据传至服务端进行处理
mButtonCommit.setOnClickListener(newView.OnClickListener()
{
@Override
publicvoidonClick(Viewv)
{
//绑定服务
getServiceConnect();
}
});
}
privatevoidgetView()
{
mEditTextName=(EditText)findViewById(R.id.editText_name);
mEditTextAge=(EditText)findViewById(R.id.editText_age);
mEditTextPlace=(EditText)findViewById(R.id.editText_place);
mButtonCommit=(Button)findViewById(R.id.button_commit);
}
privatevoidgetServiceConnect()
{
Intentit=newIntent();
it.setAction(BIND_ACTION);
startService(it);
bindService(it,mserviceConnection,BIND_AUTO_CREATE);
}
ServiceConnectionmserviceConnection=newServiceConnection()
{
@Override
publicvoidonServiceDisconnected(ComponentNamename)
{
Log.d(TAG,"onServiceDisconnected");
}
@Override
publicvoidonServiceConnected(ComponentNamename,IBinderservice)
{
Log.d(TAG,"onServiceConnected");
//获取服务端传过来的IBinder对象,通过该对象调用服务端的方法
executeService=ExecuteServiceAIDL.Stub.asInterface(service);
if(executeService!=null)
{
handlerInfo();
}
}
};
privatevoidhandlerInfo()
{
StringmName;
intmAge;
StringmPlace;
if(mEditTextName.getText().toString().equals(""))
{
mEditTextName.setText("Harlan");
mName="Harlan";
}
else
{
mName=mEditTextName.getText().toString();
}
if(mEditTextAge.getText().toString().equals(""))
{
mAge=22;
}
else
{
mAge=Integer.parseInt(mEditTextAge.getText().toString());
}
if(mEditTextPlace.getText().toString().equals(""))
{
mPlace="Nanjing";
}
else
{
mPlace=mEditTextPlace.getText().toString();
}
HarlanInfomInfo=newHarlanInfo();
mInfo.setName(mName);
mInfo.setAge(mAge);
mInfo.setPlace(mPlace);
try
{
HarlanInfoserverInfo=newHarlanInfo();
//调用服务端的方法
serverInfo=executeService.getServerHarlanInfo(mInfo,mCallBack);
//更新界面
mEditTextName.setText(serverInfo.getName());
mEditTextAge.setText(String.valueOf(serverInfo.getAge()));
mEditTextPlace.setText(serverInfo.getPlace());
unbindService(mserviceConnection);
}
catch(RemoteExceptione)
{
e.printStackTrace();
}
}
ICallBack.StubmCallBack=newICallBack.Stub()
{
//客户端回调方法的具体实现
@Override
publicvoidhandleByServer(Stringparam)
throwsRemoteException
{
Toast.makeText(getApplicationContext(),param,Toast.LENGTH_LONG).show();
}
};
}
服务端调用客户端回调方法,在界面上显示一个toast.客户端根据服务端传回来的数据,刷新界面.
最后运行结果如图所示:
具体的Demo已经上传至CSDN,下载地址:http://download.csdn.net/detail/singleton1900/4928804
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。