android SDK提供了Service,用于类似*nix守护进程或者windows的服务。

Service有两种类型:

  1. 本地服务(Local Service):用于应用程序内部
  2. 远程服务(Remote Sercie):用于android系统内部的应用程序之间

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

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

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

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

package com.easymorse;

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() { @Override
public void run() {
while (!threadDisable) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
count++;
Log.v("CountService", "Count is " + count);
}
}
}).start();
} @Override
public void onDestroy() {
super.onDestroy();
this.threadDisable = true;
Log.v("CountService", "on destroy");
} public int getCount() {
return count;
} }

需要将该服务注册到配置文件AndroidManifest.xml中,否则无法找到:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.easymorse" android:versionCode="1" android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".LocalServiceDemoActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="CountService" />
</application>
<uses-sdk android:minSdkVersion="3" />
</manifest>

在Activity中启动和关闭本地服务。

package com.easymorse;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle; public class LocalServiceDemoActivity extends Activity {
/** Called when the activity is first created. */
@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了。

这是新建立的接口代码:

package com.easymorse;

public interface ICountService {

    public abstract int getCount();
}

修改后的CountService代码:

package com.easymorse;

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++;
Log.v("CountService", "Count is " + count);
}
}
}).start();
} @Override
public void onDestroy() {
super.onDestroy();
this.threadDisable = true;
Log.v("CountService", "on destroy");
} /* (non-Javadoc)
* @see com.easymorse.ICountService#getCount()
*/
public int getCount() {
return count;
} }

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

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.easymorse" android:versionCode="1" android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".LocalServiceDemoActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="CountService">
<intent-filter>
<action android:name="com.easymorse.CountService"/>
</intent-filter>
</service>
</application>
<uses-sdk android:minSdkVersion="3" />
</manifest>

Acitity代码不再通过startSerivce和stopService启动关闭服务,另外,需要通过ServiceConnection的内部类实现来连接Service和Activity。

package com.easymorse;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log; public class LocalServiceDemoActivity extends Activity { private ServiceConnection serviceConnection = new ServiceConnection() { @Override
public void onServiceConnected(ComponentName name, IBinder service) {
countService = (ICountService) service;
Log.v("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.easymorse.CountService"),
this.serviceConnection, BIND_AUTO_CREATE);
} @Override
protected void onDestroy() {
super.onDestroy();
this.unbindService(serviceConnection);
}
}

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

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

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

package com.easymorse;

interface ICountService {
int getCount();
}

编写服务(Service)类,稍有差别,主要在binder是通过远程获得的,需要通过桩(Stub)来获取。桩对象是远程对象的本地代理。

package com.easymorse;

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.v("CountService", "Count is " + count);
}
}
}).start();
} @Override
public void onDestroy() {
super.onDestroy();
this.threadDisable = true;
Log.v("CountService", "on destroy");
}
}

配置文件AndroidManifest.xml和上面的类似,没有区别。

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

private ServiceConnection serviceConnection = new ServiceConnection() {

    @Override
public void onServiceConnected(ComponentName name, IBinder service) {
countService = (ICountService) service;
try {
Log.v("CountService", "on serivce connected, count is "
+ countService.getCount());
} catch (RemoteException e) {
throw new RuntimeException(e);
}
} @Override
public void onServiceDisconnected(ComponentName name) {
countService = null;
} };

这样就可以在同一个应用程序中使用远程服务的方式和自己定义的服务交互了。

如果是另外的应用程序使用远程服务,需要做的是复制上面的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数据改为复杂数据类型:

package com.easymorse;

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;
} }

然后,需要在相同包下建一个同名的aidl文件,用于android生成相应的辅助文件:

package com.easymorse;

parcelable CountBean;

这一步是android 1.5后的变化,无法通过adt生成aidl,也不能用一个比如全局的project.aidl文件,具体见:

http://www.anddev.org/viewtopic.php?p=20991

然后,需要在服务的aidl文件中修改如下:

package com.easymorse;

import com.easymorse.CountBean;

interface ICountService {
CountBean getCount();
}

其他的改动很小,只需将CountService和调用CountService的部分修改为使用CountBean即可。

转自:http://marshal.easymorse.com/archives/1564

android service 本地 远程 总结的更多相关文章

  1. Android Service AIDL 远程调用服务 【简单音乐播放实例】

    Android Service是分为两种: 本地服务(Local Service): 同一个apk内被调用 远程服务(Remote Service):被另一个apk调用 远程服务需要借助AIDL来完成 ...

  2. android service 的各种用法(IPC、AIDL)

    http://my.oschina.net/mopidick/blog/132325 最近在学android service,感觉终于把service的各种使用场景和用到的技术整理得比较明白了,受益颇 ...

  3. android Service Activity三种交互方式(付源码)(转)

    android Service Activity三种交互方式(付源码) Android应用服务器OSBeanthread  android Service Binder交互通信实例 最下边有源代码: ...

  4. 【Android】详解Android Service

    目录结构: contents structure [+] Service简单概述 Service在清单文件中的声明 Service启动服务 Service绑定服务 扩展Binder类 使用Messen ...

  5. Android Service总结06 之AIDL

    Android Service总结06 之AIDL 版本 版本说明 发布时间 发布人 V1.0 初始版本 2013-04-03 Skywang           1 AIDL介绍 AIDL,即And ...

  6. Android Service总结02 service介绍

    Android Service总结02 service介绍 版本 版本说明 发布时间 发布人 V1.0 介绍了Service的种类,常用API,生命周期等内容. 2013-03-16 Skywang ...

  7. Android Service和Binder、AIDL

    1.首先理解service的作用和生命周期 由于activity如果切换,那么他就不再运行,那么我们想在玩游戏的时候听播放器中的音乐,activity就应运而生了,这是最常见的一种场景,同时servi ...

  8. Android -- service的开启方式, start开启和绑定开启服务,调用服务的的方法, aidl调用远程服务

    1. 概述 bindService() 绑定服务  可以得到服务的代理人对象,间接调用服务里面的方法. 绑定服务: 间接调用服务里面的方法.           如果调用者activity被销毁了, ...

  9. Android Service完全解析,关于服务你所需知道的一切(下)

    转载请注册出处:http://blog.csdn.net/guolin_blog/article/details/9797169 在上一篇文章中,我们学习了Android Service相关的许多重要 ...

随机推荐

  1. APP架子迁移指南(二)

    接上一篇,这一篇开始用android来解释MVP概念.八股式的架子结构和命名规范.我在准备这篇文章的时候还看到不少在MVP基础上衍生的架子思路,底子是MVP没错,但命名有区别.复杂度变了.架子也用到了 ...

  2. vue.js+boostrap最佳实践

    一.为什么要写这篇文章 最近忙里偷闲学了一下vue.js,同时也复习了一下boostrap,发现这两种东西如果同时运用到一起,可以发挥很强大的作用,boostrap优雅的样式和丰富的组件使得页面开发变 ...

  3. Entity Framework与ADO.Net及NHibernate的比较

    Entity Framework  是微软推荐出.NET平台ORM开发组件, EF相对于ado.net 的优点 (1)开发效率高,Entity Framework的优势就是拥有更好的LINQ提供程序. ...

  4. jquery里面的$(this)和this都什么时候用,有什么区别

    当你用的是jquery时,就用$(this),如果是JS,就用this $(this).html( $(this).html() + " BAM! " + i ); 这个里的htm ...

  5. 34-nl 简明笔记

    为文本文件添加行号 nl [options] files 参数 files是nl需要为其添加行号的文本文件路径名,如果有多个文件,则nl会把多个文件合在一起编号,并输出到标准输出上 选项 -b     ...

  6. JavaScript 全栈工程师培训教程(来自阮一峰)

    来源于:https://twitter.com/ruanyf http://www.ruanyifeng.com/blog/2016/11/javascript.html 全栈工程师培训材料,帮助学习 ...

  7. Velocity教程【转】

    原文:http://blog.csdn.net/qq_25237663/article/details/52262532 Velocity是一个基于Java的模板引擎,通过特定的语法,Velocity ...

  8. Java发送邮件代码

    MailSenderInfo.java package com.nihaorz.mail.util; import java.util.Properties; public class MailSen ...

  9. 安全框架 SpringSecurity 和 Shiro 对比

    突然再次很想理一下权限的事,但是实在不知道实际情况选哪个框架好,现在整理下网上的资料,做一下对比. 1.Spring-security 对spring 结合较好,如果项目用的springmvc ,使用 ...

  10. Placemat:快速生成占位图片器

    快速的生成一张指定大小的图片 最简单的用法就是使用以下三个网址: https://placem.at/peoplehttps://placem.at/placeshttps://placem.at/t ...