Service Activity的三种交互方式(详解)

service有两种类型:

本地服务(Local Service):用于应用程序内部

远程服务(Remote Sercie):用于android系统内部的应用程序之间

前者用于实现应用程序自己的一些耗时任务,比如查询升级信息,并不占用应用程序比如Activity所属线程,而是单开线程后台执行,这样用户体验比较好。

后者可被其他应用程序复用,比如天气预报服务,其他应用程序不需要再写这样的服务,调用已有的即可。

编写不需和Activity交互的本地服务示例

本地服务编写比较简单。首先,要创建一个Service类,该类继承android的Service类。这里写了一个计数服务的类,每秒钟为计数器加一。在服务类的内部,还创建了一个线程,用于实现后台执行上述业务逻辑。

Service代码:

import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.util.Log; public class CountService extends Service { private boolean threadDisable; private int count; @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); new Thread(new Runnable() { public void run() { while (!threadDisable) { try { Thread.sleep(1000); } catch (InterruptedException e) { } count++; System.out.println(" CountService Count is " + count); } } }).start(); } @Override public void onDestroy() { super.onDestroy(); this.threadDisable = true; Log.v(" CountService ", " on destroy "); } } 将该服务注册到配置文件AndroidManifest.xml中 <service android:name="CountService" /> 在Activity中启动和关闭本地服务 import android.app.Activity; import android.content.Intent; import android.os.Bundle; public class LocalServiceDemoActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); this.startService(new Intent(this, CountService.class)); } @Override protected void onDestroy() { super.onDestroy(); this.stopService(new Intent(this, CountService.class)); } }

编写本地服务和Activity交互的示例

上面的示例是通过startService和stopService启动关闭服务的。适用于服务和activity之间没有调用交互的情况。如果之间需要传递参数或者方法调用。需要使用bind和unbind方法。

具体做法是,服务类需要增加接口,比如ICountService,另外,服务类需要有一个内部类,这样可以方便访问外部类的封装数据,这个内部类需要继承Binder类并实现ICountService接口。还有,就是要实现Service的

onBind方法,不能只传回一个null了。

新建立的接口代码:

public interface ICountService { public abstract int getCount(); } CountService代码: import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.util.Log; public class CountService extends Service implements ICountService { private boolean threadDisable; private int count; private ServiceBinder serviceBinder = new ServiceBinder(); public class ServiceBinder extends Binder implements ICountService { // @Override public int getCount() { return count; } } @Override public IBinder onBind(Intent intent) { return serviceBinder; } @Override public void onCreate() { super.onCreate(); new Thread(new Runnable() { // @Override public void run() { while (!threadDisable) { try { Thread.sleep(1000); } catch (InterruptedException e) { } count++; System.out.println("CountService Count is " + count); } } }).start(); } @Override public void onDestroy() { super.onDestroy(); this.threadDisable = true; Log.v(" CountService ", " on destroy "); } // @Override public int getCount() { return count; } }

服务的注册也要做改动,AndroidManifest.xml文件:

<service android:name="CountService" > <intent-filter> <action android:name="com.phone.jiaohuservice.CountService" /> </intent-filter> </service> Acitity代码不再通过startSerivce和stopService启动关闭服务,另外,需要通过ServiceConnection的内部类实现来连接Service和Activity。 import android.app.Activity; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; public class LocalServiceDemoActivity extends Activity { private ServiceConnection serviceConnection = new ServiceConnection() { // @Override public void onServiceConnected(ComponentName name, IBinder service) { countService = (ICountService) service; System.out.println(" CountService on serivce connected, count is " + countService.getCount()); } // @Override public void onServiceDisconnected(ComponentName name) { countService = null; } }; private ICountService countService; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); this.bindService(new Intent("com.phone.jiaohuservice.CountService"), this.serviceConnection, BIND_AUTO_CREATE); } @Override protected void onDestroy() { this.unbindService(serviceConnection); super.onDestroy(); // 注意先后 } }

编写传递基本型数据的远程服务

上面的示例,可以扩展为,让其他应用程序复用该服务。这样的服务叫远程(remote)服务,实际上是进程间通信(RPC)。

这时需要使用android接口描述语言(AIDL)来定义远程服务的接口,而不是上述那样简单的java接口。扩展名为aidl而不是java。可用上面的ICountService改动而成ICountSerivde.aidl,eclipse会自动生成相关的java文件。

远端代码:

ICountService.aidl

package com.phone.remoteservice.aidl; interface ICountService { int getCount(); }

CountService.java

import com.phone.remoteservice.aidl.ICountService; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; public class CountService extends Service { private boolean threadDisable; private int count; private ICountService.Stub serviceBinder = new ICountService.Stub() { // @Override public int getCount() throws RemoteException { return count; } }; // @Override public IBinder onBind(Intent intent) { return serviceBinder; } @Override public void onCreate() { super.onCreate(); new Thread(new Runnable() { // @Override public void run() { while (!threadDisable) { try { Thread.sleep(1000); } catch (InterruptedException e) { } count++; Log.i("aa", "---" + count + "---"); } } }).start(); } // @Override public void onDestroy() { super.onDestroy(); this.threadDisable = true; Log.v(" CountService ", " on destroy "); } }

配置文件AndroidManifest.xml

<service android:name=".CountService" > <intent-filter> <action android:name="com.phone.remoteservice.CountService" /> </intent-filter> </service>

本地代码:

拷贝远端代码gen:com.phone.remoteservice.aidl包名及内部生成的ICountService.java文件到本地,注意包名不要变,java文件名也不要变。

测试代码

import com.phone.remoteservice.aidl.ICountService; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.app.Activity; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.view.Menu; public class RemoteServiceTest extends Activity { private ICountService countService; private boolean SreviceDisable; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); bindService(new Intent("com.phone.remoteservice.CountService"), this.serviceConnection, BIND_AUTO_CREATE); } @Override protected void onDestroy() { this.unbindService(serviceConnection); SreviceDisable = true; super.onDestroy(); // 注意先后 } private ServiceConnection serviceConnection = new ServiceConnection() { public void onServiceConnected(ComponentName name, IBinder service) { countService = ICountService.Stub.asInterface(service); new Thread(new Runnable() { // @Override public void run() { while (!SreviceDisable) { try { System.out .println(" CountService on serivce connected, count is " + countService.getCount()); } catch (RemoteException e) { e.printStackTrace(); } try { Thread.sleep(1000); } catch (InterruptedException e) { } } } }).start(); } public void onServiceDisconnected(ComponentName name) { countService = null; } }; }

在Activity中使用服务的差别不大,只需要对ServiceConnection中的调用远程服务的方法时,要捕获RemoteException 异常。

这样就可以在同一个应用程序中使用远程服务的方式和自己定义的服务交互了。 如果是另外的应用程序使用远程服务,需要做的是复制上面的aidl文件和相应的包构到应用程序中,其他调用等都一样。

编写传递复杂数据类型的远程服务

远程服务往往不只是传递java基本数据类型。这时需要注意android的一些限制和规定:

1. android支持String和CharSequence

2. 如果需要在aidl中使用其他aidl接口类型,需要import,即使是在相同包结构下;

3. android允许传递实现Parcelable接口的类,需要import;

4. android支持集合接口类型List和Map,但是有一些限制,元素必须是基本型或者上述三种情况,不需要import集合接口类,但是需要对元素涉及到的类型import;

5. 非基本数据类型,也不是String和CharSequence类型的,需要有方向指示,包括in、out和inout,in表示由客户端设置,out表示由服务端设置,inout是两者均可设置。

这里将前面的例子中返回的int数据改为复杂数据类型:

import android.os.Parcel; import android.os.Parcelable; public class CountBean implements Parcelable { public static final Parcelable.Creator < CountBean > CREATOR = new Creator < CountBean > () { @Override public CountBean createFromParcel(Parcel source) { CountBean bean = new CountBean(); bean.count = source.readInt(); return bean; } @Override public CountBean[] newArray( int size) { return new CountBean[size]; } }; public int count; @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt( this .count); } @Override public int describeContents() { return 0 ; } }

以上就是小编为大家带来的Service Activity的三种交互方式(详解)的全部内容了,希望对大家有所帮助,多多支持脚本之家~

时间: 2024-10-25 16:32:34

Service Activity的三种交互方式(详解)的相关文章

Service Activity的三种交互方式(详解)_Android

service有两种类型: 本地服务(Local Service):用于应用程序内部 远程服务(Remote Sercie):用于android系统内部的应用程序之间 前者用于实现应用程序自己的一些耗时任务,比如查询升级信息,并不占用应用程序比如Activity所属线程,而是单开线程后台执行,这样用户体验比较好. 后者可被其他应用程序复用,比如天气预报服务,其他应用程序不需要再写这样的服务,调用已有的即可. 编写不需和Activity交互的本地服务示例 本地服务编写比较简单.首先,要创建一个Se

Android 三种动画详解及简单实例

Android 三种动画详解 帧动画 一张张图片不断的切换,形成动画效果 在drawable目录下定义xml文件,子节点为animation-list,在这里定义要显示的图片和每张图片的显示时长 <animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false"> <item android:drawable="

Android编程实现XML解析与保存的三种方法详解

本文实例讲述了Android编程实现XML解析与保存的三种方法.分享给大家供大家参考,具体如下: 简介 在Android开发中,关于XML解析有三种方式,分别是: 1. SAX 基于事件的解析器,解析速度快,占用内存少.非常适合在Android移动设备中使用. 2. DOM 在内存中以树形结构存放,因此检索和更新效率会更高.但是对于特别大的文档,解析和加载整个文档将会很耗资源 3. PULL 基于事件的解析器,不同于SAX是,PULL是主动请求下一个事件,所以在可控上PULL要比SAX实用.An

Hibernate实体对象的生命周期(三种状态详解)

Hibernate生命周期会经历三种不同的状态:     1.Transient(瞬态):实体对象在内存是自由存在的,即与数据库中的数据没有任何关系.换句话说就是:该实体从未与任何持久化上下文关联过,它没有持久化标识.例如:          //创建一个Transient对象  User user=new User(); user.setName("username");  user.setPassword("password");  //此时的user为一个Tr

Javascript定义类(class)的三种方法详解_javascript技巧

将近20年前,Javascript诞生的时候,只是一种简单的网页脚本语言.如果你忘了填写用户名,它就跳出一个警告. 如今,它变得几乎无所不能,从前端到后端,有着各种匪夷所思的用途.程序员用它完成越来越庞大的项目. Javascript代码的复杂度也直线上升.单个网页包含10000行Javascript代码,早就司空见惯.2010年,一个工程师透露,Gmail的代码长度是443000行! 编写和维护如此复杂的代码,必须使用模块化策略.目前,业界的主流做法是采用"面向对象编程".因此,Ja

Apache Prefork、Worker和Event三种MPM详解_Linux

Apache 2.X  支持插入式并行处理模块,称为多路处理模块(MPM).在编译apache时必须选择也只能选择一个MPM,对类UNIX系统,有几个不同的MPM可供选择,它们会影响到apache的速度和可伸缩性. Prefork MPM : 这个多路处理模块(MPM)实现了一个非线程型的.预派生的web服务器,它的工作方式类似于Apache 1.3.它适合于没有线程安全库,需要避免线程兼容性问题的系统.它是要求将每个请求相互独立的情况下最好的MPM,这样若一个请求出现问题就不会影响到其他请求.

mysql备份的三种方式详解_Mysql

一.备份的目的 做灾难恢复:对损坏的数据进行恢复和还原需求改变:因需求改变而需要把数据还原到改变以前测试:测试新功能是否可用 二.备份需要考虑的问题 可以容忍丢失多长时间的数据:恢复数据要在多长时间内完: 恢复的时候是否需要持续提供服务:恢复的对象,是整个库,多个表,还是单个库,单个表. 三.备份的类型 1.根据是否需要数据库离线 冷备(cold backup):需要关mysql服务,读写请求均不允许状态下进行:温备(warm backup): 服务在线,但仅支持读请求,不允许写请求:热备(ho

【转】Mysql三种备份详解

一.备份的目的 做灾难恢复:对损坏的数据进行恢复和还原需求改变:因需求改变而需要把数据还原到改变以前测试:测试新功能是否可用 二.备份需要考虑的问题 可以容忍丢失多长时间的数据:恢复数据要在多长时间内完: 恢复的时候是否需要持续提供服务:恢复的对象,是整个库,多个表,还是单个库,单个表. 三.备份的类型 1.根据是否需要数据库离线 冷备(cold backup):需要关mysql服务,读写请求均不允许状态下进行:温备(warm backup): 服务在线,但仅支持读请求,不允许写请求:热备(ho

【REACT NATIVE 系列教程之四】刷新组件RENDER(重新渲染)的三种方式详解

本站文章均为 李华明Himi 原创,转载务必在明显处注明:  转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/react-native/2242.html 开发过游戏的都应该很清楚,"刷屏"是多么的重要.其实开发应用也如此,当组件的数据被修改后,如何及时更新组件呈现出最新的数据与效果一样至关重要. 那么这里Himi大概讲三种常用的方式: this.setState()  [最为常用] 这是在事件处理函数中和请求回调函数中触发 UI 更新的主