android Service Activity三种交互方式(付源码)
android SDK提供了Service,用于类似Linix守护进程或者windows的服务。
Service有两种类型:
- 本地服务(Local Service):用于应用程序内部
- 远程服务(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() {
this .unbindService(serviceConnection);
super .onDestroy(); //注意先后
}
}
编写传递基本型数据的远程服务
上面的示例,可以扩展为,让其他应用程序复用该服务。这样的服务叫远程(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的一些限制和规定:
- android支持String和CharSequence
- 如果需要在aidl中使用其他aidl接口类型,需要import,即使是在相同包结构下;
- android允许传递实现Parcelable接口的类,需要import;
- android支持集合接口类型List和Map,但是有一些限制,元素必须是基本型或者上述三种情况,不需要import集合接口类,但是需要对元素涉及到的类型import;
- 非基本数据类型,也不是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文件,具体见:
然后,需要在服务的aidl文件中修改如下:
package com.easymorse;
import com.easymorse.CountBean;
interface ICountService {
CountBean getCount();
}
其他的改动很小,只需将CountService和调用CountService的部分修改为使用CountBean即可
本文转载自:http://yangguangfu.iteye.com/blog/699306
android Service Activity三种交互方式(付源码)的更多相关文章
- android Service Activity三种交互方式(付源码)(转)
android Service Activity三种交互方式(付源码) Android应用服务器OSBeanthread android Service Binder交互通信实例 最下边有源代码: ...
- Service Activity三种交互方式
Service Activity三种交互方式 2012-09-09 22:52 4013人阅读 评论(2) 收藏 举报 serviceandroidimportclassthreadjava ...
- Android service ( 一 ) 三种开启服务方法
一. Service简介 Service是android 系统中的四大组件之一(Activity.Service.BroadcastReceiver.ContentProvider),它跟 Activ ...
- wemall app商城源码中android按钮的三种响应事件
wemall-mobile是基于WeMall的android app商城,只需要在原商城目录下上传接口文件即可完成服务端的配置,客户端可定制修改.本文分享wemall app商城源码中android按 ...
- Android事件分发详解(三)——ViewGroup的dispatchTouchEvent()源码学习
package cc.aa; import android.os.Environment; import android.view.MotionEvent; import android.view.V ...
- 大数据--Hive的安装以及三种交互方式
1.3 Hive的安装(前提是:mysql和hadoop必须已经成功启动了) 在之前博客中我有记录安装JDK和Hadoop和Mysql的过程,如果还没有安装,请先进行安装配置好,对应的随笔我也提供了百 ...
- Android上掌纹识别第一步:基于OpenCV的6种肤色分割 源码和效果图
Android上掌纹识别第一步:基于OpenCV的6种肤色分割 源码和效果图 分类: OpenCV图像处理2013-02-21 21:35 6459人阅读 评论(8) 收藏 举报 原文链接 ht ...
- Android系统的三种分屏显示模式
Google在Android 7.0中引入了一个新特性——多窗口支持,允许用户一次在屏幕上打开两个应用.在手持设备上,两个应用可以在"分屏"模式中左右并排或上下并排显示.在电视设备 ...
- 【Android 系统开发】CyanogenMod 13.0 源码下载 编译 ROM 制作 ( 手机平台 : 小米4 | 编译平台 : Ubuntu 14.04 LTS 虚拟机)
分类: Android 系统开发(5) 作者同类文章X 版权声明:本文为博主原创文章 ...
随机推荐
- Qt多文档界面应用设计
使用Qt编写多文档界面(MDI)应用相当方便,主要会使用到QMdiArea和QMdiSubWindow两个类.可以查看Qt Asistant中这两个类的说明文档,里面介绍的相当详细.另外,可以搜索例程 ...
- jQuery入门[1]-构造函数【转载】
最近看了一些jquery的进阶教程,感觉很不错,与大家分享下! jQuery——构造函数 ◦体积小(v1.2.3 15kb)◦丰富的DOM选择器(CSS1-3 + XPath) ◦跨浏览器(IE6,F ...
- 【转】WPF获取外部EXE图标最简单的方法
首先在工程添加对System.Drawing的引用 创建以下方法: public static ImageSource GetIcon(string fileName) { System.Drawin ...
- PythonCrawl自学日志(2)
一.Scrapy环境的安装 1.配套组件的安装 由于开发环境是在VS2015Community中编码,默认下载的python3.5,系统是windows8.1,为此需要安装的组件有如下列表: 所有的组 ...
- json在线校验
弄了一个在线校验,清爽无广告,欢迎大家收藏 http://www.zhhoney.com/
- 2.MVC框架开发(视图开发----基础语法)
1.区别普通的html,在普通的html中不能将控制器里面的数据展示在html中. 在MVC框架中,它提供了一种视图模板(就是结合普通的html标签并能将控制器里传出来的数据进行显示) 视图模板特性: ...
- Asp.Net检查HTML是否闭合以及自动修复
1.htmlCheck类 using System; using System.Collections.Generic; using System.Text; using System.Collect ...
- StringBuffer与StringBuilder原理与区别
其实只要找下Google大神就有答案了:StringBuffer 与 StringBuilder 中的方法和功能完全是等价的,只是StringBuffer 中的方法大都采用了 synchronized ...
- 关于appStore评分的相关说明--转自张诚教授
在iOS7以前,评分地址如下 itms-apps://ax.itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?typ ...
- Uva 654 Ratio
题意: 给两个数, n, m 构造一个序列, 分母从1 ~ m, 并且j / i越来越接近n/m. 思路: 如果存在 j / i 趋近于 n / m 那么则有 j = n * i / m + 0.5( ...