【转】 Pro Android学习笔记(八十):服务(5):访问远程服务
文章转载只能用于非商业性质,且不能带有虚拟货币、积分、注册等附加条件。转载须注明出处:http://blog.csdn.net/flowingflying/
和Local service不同,remote service可以被其他进程,即其他应用所调用。
Client的AIDL文件在onBind()中将stub对象返回给client,client对stub对象的操作,就如同操作service的对外接口。继上学习了AIDL文件和远程服务的实现,我们将学习client如何访问远程服务。
Client的AIDL文件
Client要访问远程服务,必须清楚服务接口,因此同样需要用AIDL文件来将该接口描述清楚,可以直接从remote service中copy过来,AIDL文件是client和server之间的契约,对双方之间的接口进行说明。
我们将remote service中的IStockQuoteService.aidl文件copy到client的src下面。由于aidl中的包名和client的包名不一样,我们将看到下面的视图:

Client的代码
客户端的activity很简单,主要又两个button组成,第一个是ToggleButton,有两个状态,点击分别连接remote service和断开连接,即bind和unbind。第二个button是请求远程服务,得到的结果用toast显示,只有成功连接远程服务后才能请求服务,故button根据连接状态确实是否enable。

public class MainActivity extends Activity {
private ToggleButton bindButton = null;
private Button callButton = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindButton = (ToggleButton)findViewById(R.id.bindButton);
callButton = (Button)findViewById(R.id.callButton);
}
@Override
protected void onDestroy() {
Log.v("client","Activity onDestroy() is called");
if(bindButton.isChecked()){
unbindService(servCon); //【3】在activity退出时断开连接
}
super.onDestroy();
}
// 按Button的处理
public void doClick(View v){
switch(v.getId()){
case R.id.bindButton:
Log.v("client","bindButton check ? " + bindButton.isChecked());
if(bindButton.isChecked()){ //want bind
/* 【1】连接远程服务:通过bindService()进行,有三个参数:
* 1、service的名字,我们在remote service的AndroidManifest.xml中在<intent-fliter>定义
* 2、ServiceConnetion,连接
* 3、flag,表明如服务部存在则自动创建。
* */
bindService(new Intent(IStockQuoteService.class.getName()),
servCon,
Context.BIND_AUTO_CREATE);
}else{//want unbind
callButton.setEnabled(false);
unbindService(servCon); //【3】断开服务连接
}
break;
case R.id.callButton:
callService();
break;
default:
return;
}
}
//【1】连接远程服务
private IStockQuoteService remoteService = null; // 【1.1】存储远程服务返回的stub中的代理实例
private ServiceConnection servCon = new ServiceConnection() {
@Override //【1.2】当远程服务出现异常,如crash,导致连接中断时触发,注意,unBindService()并不会触发此。
public void onServiceDisconnected(ComponentName name) {
Log.v("client","onServiceDisconnected() is called");
bindButton.setChecked(false);
callButton.setEnabled(false);
remoteService = null;
}
@Override //【1.3】当远程服务连接成功时,即bindService()成功时触发,在此需要获得Stub对象,实际是获得Stub中的代理实例,操作这个代理对象,就如同直接操作远程服务,使用起来很是方便
public void onServiceConnected(ComponentName name, IBinder service) {
Log.v("client","onServiceConnected() is called");
//从接口中获取代理对象,操作这个对象,就如同操作接口一般,下面是自动生成的接口文件中相关的代码,
/* 在 IStockQuoteService.Stub:在接口中获取一个IBinder对象作为proxy(代理),有则返回,无则生成之。
* Cast an IBinder object into an cn.wei.flowingflying.proandroidservice.IStockQuoteService interface,
* generating a proxy if needed.
* public static cn.wei.flowingflying.proandroidservice.IStockQuoteServiceasInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof cn.wei.flowingflying.proandroidservice.IStockQuoteService))) {
return ((cn.wei.flowingflying.proandroidservice.IStockQuoteService)iin);
}
return new cn.wei.flowingflying.proandroidservice.IStockQuoteService.Stub.Proxy(obj);
}
* */
remoteService = IStockQuoteService.Stub.asInterface(service);
bindButton.setChecked(true);
callButton.setEnabled(true);
}
};
private void callService(){
try{
double value = remoteService.getQuote("WEI"); //【2】请求服务:操作接口代理实例,如果本地操作远程服务接口
Log.v("client","callService(): get stockQuote from reference :" + value);
Toast.makeText(this, "Stock quote is " + value, Toast.LENGTH_LONG).show();
}catch(RemoteException e){
Log.e("client",e.toString());
}
}
}
client访问远程服务分为三步:【1】建立连接、【2】请求服务、【3】断开连接。
建立连接
远程服务可以被本应用和其他应用调用,client通过bindService()和远程服务建立连接,并从中获取接口代理对象。对应的在远程服务中,如果服务不存在,则服务启动,执行onCreate(),然后执行onBind();如果服务存在则直接执行onBind()。
bindService()是异步,即asynchronouse call,也就是它不会等到服务执行完onCreate()、onBind()然后返回,因此我们需要serviceConnection中的onServiceConnected()回调函数来表明已经成功连接。serviceConnection中的onServiceDisconnected()是在service崩溃的时候触发,如果原来存在连接,Android系统会自动重启服务。我们可以通过DDMS中强制终止remote Service的进程来实现,可以看到触发了onServiceDisConnected(),remote Service会被重新启动,接着连接的onServiceConnected()会被触发。
请求服务
直接操作接口代理实例,操作远程服务就如同在本地操作一样便捷。
断开连接
通过unBindService()断开远程服务的连接,相应地执行远程服务的onDestroy()。也许你会担心,如果我在程序中进行unBindService(),或不会影响其他应用对远程服务的调用。这不需要担心。在上一次学习中,我们在remote service中定义一个静态变量(static int count)进行跟踪。当我们unbind,从新再bind时,我们发现count继续计数,而不是重头开始,说明service实际一直在后台存在,这点也可以通过DDMS查看进程来确定。这就很有趣了,Stub是针对每个接口,而remote service中的onCreate(),onDestroy(),onBind()也是针对连接,或者说针对为每个接口分配的Stub。因此不同应用去连接远程服务,并请求服务或者访问服务时,他们之间不会发生混淆,服务可以分隔每一个连接。当然如果我们不使用静态变量,而采用普通的变量,unbind后再bind,是会从新计数。
本笔记涉及的例子代码,可以在Pro Android学习:Android service小例子中下载。
相关链接: 我的Android开发相关文章
【转】 Pro Android学习笔记(八十):服务(5):访问远程服务的更多相关文章
- 【转】 Pro Android学习笔记(十九):用户界面和控制(7):ListView
目录(?)[-] 点击List的item触发 添加其他控件以及获取item数据 ListView控件以垂直布局方式显示子view.系统的android.app.ListActivity已经实现了一个只 ...
- 【转】Pro Android学习笔记(十二):了解Intent(下)
解析Intent,寻找匹配Activity 如果给出component名字(包名.类名)是explicit intent,否则是implicit intent.对于explicit intent,关键 ...
- 【转】Pro Android学习笔记(十):了解Intent(上)
目录(?)[-] Intent基本含义 系统的Intent Android引入了Intent的概念来唤起components,component包括:1.Activity(UI元件) 2.Servic ...
- 【转】Pro Android学习笔记(十四):用户界面和控制(2):Text类控制
目录(?)[-] TextView 例子1在XML中设置autoLink属性 例子2在代码中设置autoLink属性 EditText AutoCompleteTextView MultiAutoCo ...
- 【转】Pro Android学习笔记(十六):用户界面和控制(4):ImageView控件
目录(?)[-] XML片段 代码设置ImageView ImageView是基础的控件,它是android.widget.ImageView的继承类. XML片段 <LinearLa ...
- 【转】Pro Android学习笔记(十八):用户界面和控制(6):Adapter和AdapterView
目录(?)[-] SimpleCursorAdapter 系统预置的layout ArrayAdapter 动态数据增插删排序 自定义TextView风格 其他Adapter AdapterView不 ...
- 【转】Pro Android学习笔记(十五):用户界面和控制(3):Button控件
目录(?)[-] 基础Button ImageButton ToggleButton CheckBox RadioButton 基础Button Button是最常用的基础控件之一,在Android中 ...
- 【转】Pro Android学习笔记(三十):Menu(1):了解Menu
目录(?)[-] 创建Menu MenuItem的属性itemId MenuItem的属性groupId MenuItem的属性orderId MenuItem的属性可选属性 Menu触发 onOpt ...
- 【转】 Pro Android学习笔记(三五):Menu(6):XML方式 & PopUp菜单
目录(?)[-] 利用XML创建菜单 XML的有关属性 onClick事件 Pop-up菜单 利用XML创建菜单 在代码中对每个菜单项进行设置,繁琐且修改不灵活,不能适配多国语言的要求,可以利用资源进 ...
- 【转】Pro Android学习笔记(二五):用户界面和控制(13):LinearLayout和TableLayout
目录(?)[-] 布局Layout 线性布局LinearLayout 表格布局TableLayout 布局Layout Layout是容器,用于对所包含的view进行布局.layout是view的子类 ...
随机推荐
- C++逗号表达式
c++中,逗号表达式的结果是最右边表达式的值
- SQl查询基础
SQL语言是一门简单易学却又功能强大的语言,他让你快速上手并写出比较复杂的查询语句,但对于大多数开发者来书,使用SQL查询数据库并没有一个抽象的过程和一个合理的步骤,这很可能会是在写一些特定的查询语句 ...
- Spring获取bean的一种方式
随便一百度,网上一大把,并且还不止一种.所以这里就只记录目前用的一种好了. 实现ApplicationContextAware接口 即可: import org.springframework.bea ...
- 2017-03-05 CentOS中结合Nginx部署dotnet core Web应用程序
Visual Studio Live 倒计时2天,当然这是美国倒计时两天,中国应该是在3月8日的凌晨,正值"3.8妇女节".提前祝广大的女性同志节日快乐,当然还有奋斗在一线的程序媛 ...
- 工程优化方法中的“最速下降法”和“DFP拟牛顿法”的 C 语言实现
这个小程序是研一上学期的“工程优化”课程的大作业.其实这题本可以用 MATLAB 实现,但是我为了锻炼自己薄弱的编码能力,改为用 C 语言实现.这样,就得自己实现矩阵的运算(加减乘除.求逆.拷贝):难 ...
- andriod sdk 模拟器的安装以及root
安卓模拟器常用的一共2种java sdk 和 bluestacks 蓝手指.前者比较卡,后者貌似不能模拟2g/3g上网. 本文主要是针对java sdk的安装使用,以及root.关于root的意思 ...
- Redis 存储机制
Redis存储机制分成两种Snapshot和AOF.无论是那种机制,Redis都是将数据存储在内存中. Snapshot工作原理: 是将数据先存储在内存,然后当数据累计达到某些设定的伐值的时候,就会触 ...
- hdu 5236 Article(概率dp¥)
Article Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Sub ...
- android横屏布局文件设置
一.AndroidManifest.xml配置 1.在AndroidManifest.xml的activity(需要禁止转向的activity)配置中加入 android:screenOrient ...
- memcached telnet command
memcached telnet commandtelnet 127.0.0.1 11211 --连接memcached 1.基本命令1)set set 命令用于向缓存添加新的键值对.如果键已经存在, ...