Android_Service组件详解
1.Service概述
Service服务是一个没有用户界面的在后台运行执行操作的应用组件,其它组件可以通过Intent意图启动这个Service去完成特定的功能,比如通过Service可以完成播放音乐等后台操作,且每个Service必须在manifest中 通过<service>来声明配置。每个service运行在宿主线程上,因此,访问网络读取Sdcard等耗时操作需要放在工作线程中!Android系统有五种进程Foreground
Process(比如Activity处于resumed状态),Visible Process(比如activity处于paused状态),Service Process,Background Process(比如activity处于stopped状态),Empty Process,service处于第三级,后台的Activiy处于第四等级,后台运行的进程被杀死的概率比service大。
2.Service的启动方式
(1).startService()
// 1.startService开启
public void start(View view) {
//显示意图或者使用隐式意图找到Service对象
Intent intent = new Intent(this, TestService.class);
startService(intent);
}(2).bindService()绑定服务
// 2.bindService绑定服务
public void bind(View view) {
Intent intent = new Intent(this, TestService.class);
conn = new MyServiceConn();
bindService(intent, conn, Context.BIND_AUTO_CREATE);
}
class MyServiceConn implements ServiceConnection { /*
* Service服务返回一个IBinder对象,该onServiceConnected函数将接受该IBinder对象
*/
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
System.out.println("得到binder对象");
binder = (IMyBinder) service;
} /*
* 一般不会被调用, 只有在Service被破坏了或者被杀死的时候调用.
* 例如, 系统资源不足, 要关闭一些Services, 刚好连接绑定的 Service 是被关闭者之一, 这个时候onServiceDisconnected() 就会被调用。
*/
@Override
public void onServiceDisconnected(ComponentName name) {
}
}(3).两种启动方式的区别
可以多次启动同一服务,但只能一次终止该服务。两种启动方式对应服务的生命周期不调,bindService可以得到Binder代理对象。
通过startService方式启动的服务,在退出当前activity时,service服务仍然存在,但无法操作服务内部方法;
通过bindService可以得到Binder对象,间接调用服务内部方法,但在用户退出当前该Activity时,服务终止。
结合以上两种优点,结论:
Activity使用startService启动服务(延长该服务的生命周期),再使用bindService()(服务已存在,但为得到Binder代理对象),再定义一个接口用于暴露MyBinder代理对象的方法,自定义MyBinder类(继承Binder实现接口),在服务的onBind()中返回MyBinder的实例化对象,Activity中ServiceConnection子类实例化对象的onServiceConnected()接收该Binder对象,再将该Binder对象强转为接口类型。通过调用Binder对象方法,达到在Binder对象内部操作服务方法。
更多Activity调用服务方法,请看下面源代码!
3.Service的生命周期
(1).startService启动方式的生命周期
1).context.startService() 当前activity调用startService()方法
2).service.onCreate() 当前服务如果首次创建,会执行服务的onCreate方法,执行一次
3).service.onStart() 每次activity调用startService()都会执行该方法
4).context.stopService() 停止当前服务
5).service.onDestroy() 调用了服务onDestroy方法(2).bindService启动方式的生命周期
1).context.bindService()绑定服务,可以指定服务标签,比如服务不存在可以自动创建
2). service.onCreate() 服务如果首次创建,会执行服务的onCreate方法,执行一次
3). service.onBind() 每次绑定都会执行该方法,并返回一个Binder对象,通过该Binder对象,可以间接执行服务中的方法
4).context.onUnbind() 解除绑定,如果当前服务是在绑定时候创建的,则销毁该服务
5). service.onDestroy() 销毁服务,Service调用onDestroy()(3).混合启动方式的生命周期(***)
1).context.startService() activity调用startService()方法
2). service.onCreate() 服务首次创建,会执行服务的onCreate方法,执行一次
3). service.onStart() 每次startService()都会执行该方法
4).context.bindService() 操作同一服务,以得到Binder代理对象
5). service.onBind(); 返回Binder对象
6).在activity中操作binder对象,从而调用服务中方法
7).context.unbindService()可以在当前Activity销毁时,即在Activity的onDestroy解除绑定,用try语句,如果没有绑定服务可能出现异常
8).context.stopService() activity停止服务
9). service.onDestroy() 服务销毁
4.IntentService
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery; private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
} @Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
} @Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
/*
* 在thread.start(); 对应执行的run方法中,执行了
* Looper.prepare();
* Looper.loop();
* 操作,然后将生成的looper作为参数,传递到handler中,虽然该handler在主线程中创建,
* 但是由于为其制定了looper,故工作线程在阻塞掉用Loop.loop(),调用依然在工作线程中,
* 耗时操作可以方法onHandleIntent中,可以处理接收到intent对象
*/
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
} @Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
} protected abstract void onHandleIntent(Intent intent);
}可查看Android_Thread多线程_Handler,Message,Looper,MessageQueue多线程和特殊UI更新一文
5.粘性Service和非粘性Service
只有在系统内存很低时,才有可能强制杀死Service来回收系统资源。如果该Service绑定在有用户焦点的Activity上,很少可能被杀死;如果在foreground中定义,几乎不可能被杀死。onStartCommand()必须返回一个整数,该返回值描述了服务被杀死后如何再处理该服务,下面接受3种类型!
(1).START_NOT_STICKY
If the system kills the service
after onStartCommand() returns, do not recreate the service, unless there are pending intents to deliver. This is the safest option
to avoid running your service when not necessary and when your application can simply restart any unfinished jobs.(2).START_STICKY
If the system kills the service
after onStartCommand() returns, recreate the service and call onStartCommand(),but do not redeliver the last intent. Instead, the
system callsonStartCommand() with a
null intent, unless there were pending intents to start the service, in which case, those intents are delivered. This is suitable for media players (or similar services) that are not executing commands, but running indefinitely and waiting
for a job.(3).START_REDELIVER_INTENT
If the system kills the service
after onStartCommand() returns, recreate the service and call onStartCommand() withthe last intent that was delivered to the service.
Any pending intents are delivered in turn. This is suitable for services that are actively performing a job that should be immediately resumed, such as downloading a file.
6.Service完成UI的更新
public class MainActivity extends Activity { private ProgressBar bar;
private IMyBinder mBinder;
private Handler handler = new Handler(){
public void handleMessage(Message msg) {
bar.setProgress(Integer.parseInt(msg.obj.toString()));
}
}; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bar = (ProgressBar) findViewById(R.id.progressBar1);
startService(new Intent(this, MyService.class));
bindService(new Intent(this, MyService.class), conn, Context.BIND_AUTO_CREATE);
} public void click(View view){
mBinder.doLongWork();
}
private ServiceConnection conn = new ServiceConnection() { @Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mBinder = (IMyBinder) service; //得到binder对象,为其设定handler对象
mBinder.setHandler(handler);
};
};
}public class MyService extends Service { private Handler mHandler;
private Mybinder binder;
@Override
public void onCreate() {
super.onCreate();
binder = new Mybinder();
} @Override
public IBinder onBind(Intent intent) {
return binder;
} class Mybinder extends Binder implements IMyBinder{ @Override
public void setHandler(Handler handler) {
//用于接收handler对象,完成ui的更新
mHandler = handler;
} @Override
public void doLongWork() {
//开启线程,完成耗时操作
new Thread(){
public void run() {
for(int i=0; i<11; i++){
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("i = "+i);
Message msg = mHandler.obtainMessage();
msg.obj = i*10;
mHandler.sendMessage(msg);
}
}
}.start();
}
}
}/**
* 提供一个公共接口
* @author Administrator
*
*/
public interface IMyBinder {
public void setHandler(Handler handler);
public void doLongWork();
}
7.服务类型分类
(1).本地服务
服务依附在主进程上而不是独立的进程,服务通信很方便。主进程终止后,服务也会终止,音乐播放等后台操作大多是这种类型。
服务通信,一种方式是通过绑定服务,根据返回Binder对象调用;另一种是在服务类别声明一个广播接收者内部类,其它应用通过发送一个广播,来达到通信目的。通信过程请看后面介绍。
(2).远程服务
该服务是独立的进程,这种Service是常驻的,如果想其它应用与该service通信,必须满足一定机制要求。达到远程服务通信,除了发送一个广播,还可以根据aidl(安卓接口定义语言)。
8.服务通信
(1).通用型(本地/远程)
1).广播接收者
/**
* TestService.java
* 允许第三方应用,启动该服务完成计算的功能,第三方广播的intent设置需要计算的参数,
* 在内部类广播接收者中获得该参数信息,并调用服务的方法,完成计算功能
* @author Administrator
*/
public class TestService extends Service {
private MyReceiver receiver; @Override
public void onCreate() {
/*
* 服务开启的时候注册一个广播接收者,广播接收者注册不用再清单文件中配置
* 其action为com.baidu.caluservice2
*/
receiver = new MyReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("com.baidu.caluservice2");
registerReceiver(receiver, filter); //注册接收者
super.onCreate();
} //内部类的广播接收者
class MyReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
//得到传递的参数信息
int m = intent.getIntExtra("m", 0);
int n = intent.getIntExtra("n", 0);
// 调用服务的计算功能
int result = methodService(m, n);
Toast.makeText(getApplicationContext(), m+"+"+n+"="+result, Toast.LENGTH_SHORT).show();
}
} //服务计算功能
public int methodService(int m, int n){
int result = m*n;
return result;
} @Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
// 对于注册的广播接收者,在服务销毁时,应该解除广播的注册
@Override
public void onDestroy() {
unregisterReceiver(receiver);
super.onDestroy();
}
}<!-- AndroidManifest.xml -->
<service android:name="com.baidu.calu.TestService">
<intent-filter>
<action android:name="com.baidu.caluservice"/>
</intent-filter>
</service>/**
* TestService.java
* 第三方应用发送一个携带传递参数的广播,通过其它应用的服务,完成计算的功能
* @author Administrator
*
*/
public class MainActivity extends Activity {
private EditText textm;
private EditText textn;
private Intent intent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textm = (EditText) this.findViewById(R.id.textm);
textn = (EditText) this.findViewById(R.id.textn); //首先应该启动第三方服务,完成广播接收者注册初始化
intent = new Intent();
intent.setAction("com.baidu.caluservice");
startService(intent);
}
public void start(View view){ //发送一个广播,并未intent设置需要传递的参数信息
Intent intent2 = new Intent();
intent2.setAction("com.baidu.caluservice2");
//设置需要传递 的参数信息
intent2.putExtra("m", Integer.parseInt(textm.getText().toString()));
intent2.putExtra("n", Integer.parseInt(textn.getText().toString()));
sendBroadcast(intent2);
}
@Override
protected void onDestroy() {
stopService(intent);
super.onDestroy();
}
}
2).Parcel
private ServiceConnection conn = new ServiceConnection() { @Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInt(10);
data.writeInt(20);
try {
/*
* transact(),将包含数据的data,调用binder对象的onTransact()方法,
* 接收onTransact()写入的数据reply,通过reply得到执行结果
* 实际上,service中的binder的onTransact()方法在主线程中调用,不能执行耗时操作
* 可以在执行service.transact(100, data, reply, 0);时使用多线程
*/
service.transact(100, data, reply, 0);
int result = reply.readInt();
//得到结果
} catch (RemoteException e) {
e.printStackTrace();
}
data.recycle();
reply.recycle();
};
};public class MyService extends Service { private Mybinder binder;
@Override
public void onCreate() {
super.onCreate();
binder = new Mybinder();
} @Override
public IBinder onBind(Intent intent) {
return binder;
} class Mybinder extends Binder{ @Override
protected boolean onTransact(int code, Parcel data, Parcel reply,
int flags) throws RemoteException {
/*
* Parcel data activity写入的数据
* Parcel reply 执行完成之后写入的数据
*/
int x = data.readInt();
int y = data.readInt();
reply.writeInt(x+y); return super.onTransact(code, data, reply, flags);
}
}
}
(2).代理通信
1).本地Binder通信
/**
* MainActivity.java
* @author Administrator
*
*/
public class MainActivity extends Activity {
private EditText textm;
private EditText textn;
private IMyBinder binder; //Binder对象
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textm = (EditText) this.findViewById(R.id.textm);
textn = (EditText) this.findViewById(R.id.textn);
}
public void start(View view){
Intent intent = new Intent(this, CalService.class);
// 绑定服务
bindService(intent, new MyServiceConn(), Context.BIND_AUTO_CREATE);
}
class MyServiceConn implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//service返回Binderdialing对象,由于代理对象私有,只能强转为其实现的接口类型
binder = (IMyBinder) service;
String m = textm.getText().toString();
String n = textn.getText().toString();
try {
//调用binder的方法,从而调用service内部计算方法,并得到计算的返回值
int result = binder.method(Integer.parseInt(m), Integer.parseInt(n));
Toast.makeText(MainActivity.this, m+"+"+n+"="+result, Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
}
}
//服务异常退出或者终止时才调用该方法
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
}/**
* IMyBinder.java
* 供代理类继承,并暴露代理类的方法,供调用者使用
* @author Administrator
*
*/
interface IMyBinder {
int method(int m, int n);
}/**
* CalService.java
* 计算服务
* @author Administrator
*
*/
public class CalService extends Service {
private MyBinder binder;
@Override
public void onCreate() {
binder = new MyBinder();
super.onCreate();
}
//每次绑定会调用该方法
@Override
public IBinder onBind(Intent intent) {
return binder;
}
//内部代理类,该类应该设置为私有的,只向外暴露继承接口的方法
private class MyBinder extends Binder implements IMyBinder {
@Override
public int method(int m, int n) {
//调用服务内部方法
int result = methodService(m, n);
return result;
}
}
// 服务计算功能
public int methodService(int m, int n) {
int result = m + n;
return result;
}
}2) .远程aidl通信
/**
* TestService.java
* 允许第三方应用,启动该服务完成计算的功能,第三方广播的intent设置需要计算的参数,
* 在内部类广播接收者中获得该参数信息,并调用服务的方法,完成计算功能
* @author Administrator
*
*/
public class TestService extends Service { private MyBinder binder;
@Override
public void onCreate() {
System.out.println("onCreate");
binder = new MyBinder();
super.onCreate();
}
//返回Binder对象
@Override
public IBinder onBind(Intent intent) {
System.out.println("onBind");
return binder;
}
//直接继承IMyBinder的Stub内部类,由于该类已经继承了Binder
private class MyBinder extends IMyBinder.Stub{
@Override
public int method(int m, int n) throws RemoteException {
//调用service方法
int result = methodService(m, n);
return result;
}
}
//计算中心
public int methodService(int m, int n){
int result = m*n;
return result;
}
}/**
* 服务下的IMyBinder.aidl文件
* aidl文件,该文件定义不能使用public使用权限,由于接口已经默认为public,该文件会自动编译
* 调用该服务的应用也应该声明同样的IMyBinder.aidl文件,注意包名也应该一致
* @author Administrator
*
*/
interface IMyBinder {
int method(int m, int n);
}/**
* MainActivity.java
* 第三方应用发送一个携带传递参数的广播,通过其它应用的服务,完成计算的功能
* @author Administrator
*
*/
public class MainActivity extends Activity {
private EditText textm;
private EditText textn;
private IMyBinder binder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textm = (EditText) this.findViewById(R.id.textm);
textn = (EditText) this.findViewById(R.id.textn);
}
public void start(View view){
//绑定服务
Intent intent = new Intent();
intent.setAction("com.baidu.caluservice");
bindService(intent, new MyServiceConn(), Context.BIND_AUTO_CREATE);
}
class MyServiceConn implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//得到服务onBind返回的Binder对象
binder = IMyBinder.Stub.asInterface(service); //使用该方式得到返回的接口对象
String m = textm.getText().toString();
String n = textn.getText().toString();
try {
//调用binder方法,并得到返回值
int result = binder.method(Integer.parseInt(m), Integer.parseInt(n));
Toast.makeText(MainActivity.this, m+"+"+n+"="+result, Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
}/**
* 第三方应用的IMyBinder.aidl文件
* 注意包名应该与服务的包名一致
* @author Administrator
*
*/
interface IMyBinder {
int method(int m, int n);
}
Android_Service组件详解的更多相关文章
- Android中Intent组件详解
Intent是不同组件之间相互通讯的纽带,封装了不同组件之间通讯的条件.Intent本身是定义为一个类别(Class),一个Intent对象表达一个目的(Goal)或期望(Expectation),叙 ...
- Android笔记——四大组件详解与总结
android四大组件分别为activity.service.content provider.broadcast receiver. ------------------------------- ...
- vue.js基础知识篇(6):组件详解
第11章:组件详解 组件是Vue.js最推崇也最强大的功能之一,核心目标是可重用性. 我们把组件代码按照template.style.script的拆分方式,放置到对应的.vue文件中. 1.注册 V ...
- Echars 6大公共组件详解
Echars 六大组件详解 : title tooltip toolbox legend dataZoom visualMap 一.title标题详解 myTitleStyle = { color ...
- Angular6 学习笔记——组件详解之组件通讯
angular6.x系列的学习笔记记录,仍在不断完善中,学习地址: https://www.angular.cn/guide/template-syntax http://www.ngfans.net ...
- Angular6 学习笔记——组件详解之模板语法
angular6.x系列的学习笔记记录,仍在不断完善中,学习地址: https://www.angular.cn/guide/template-syntax http://www.ngfans.net ...
- admin组件详解
admin组件详解 先根据admin组件启动流程复习下django项目启动至请求过来发生的事 1将admin组件注册进app 2django项目启动 3在运行到定制的admin时执行其下面的apps文 ...
- OpenStack各组件详解和通信流程
一.openstack由来 openstack最早由美国国家航空航天局NASA研发的Nova和Rackspace研发的swift组成.后来以apache许可证授权,旨在为公共及私有云平台建设.open ...
- Tomcat系列之服务器的安装与配置以及各组件详解
Tomcat系列之服务器的安装与配置以及各组件详解 大纲 一.前言 二.安装与配置Tomcat 三.Tomcat 目录的结构 四.Tomcat 配置文件 注,本文的测试的操作系统为CentOS 6.4 ...
随机推荐
- Java Web学习笔记(1)
1.项目名称用小写,类名用大小写骆驼式,对象名用骆驼式但是第一个字母是小写: 2.写对象属性时要空行,第一个方法也要空行,一般要加注释: 3.new 新的对象时等号左右要空格,if语句左右摇有空格: ...
- 进度记录 和 安装imagick时Cannot locate header file MagickWand.h错误的解决
修改php.ini文件,已使php支持扩展的功能 [root@localhost imagick-2.2.2]# ./configure --with-php-config=/usr/local/ph ...
- poj 1850/poj 1496
http://poj.org/problem?id=1850 -----------------http://poj.org/problem?id=1496 两题解法类似..本题为组合数学的题,要求所 ...
- django virtualenv
1. virtualenv virtualenv用于创建独立的Python环境,多个Python相互独立,互不影响,它能够:1. 在没有权限的情况下安装新套件2. 不同应用可以使用不同的套件版本3. ...
- "No appenders found for logger" and "Please configure log4j properly"
Why do I see a warning about "No appenders found for logger" and "Please configure lo ...
- 孙弘与Masa Maso 做互联网最贵的衬衫(2)_人物对话_中国时尚品牌网
孙弘与Masa Maso 做互联网最贵的衬衫(2)_人物对话_中国时尚品牌网 孙弘与Masa Maso 做互联网最贵的衬衫(2)
- [Django实战] 第9篇 - 表单、视图、模型、模板的交互
本章通过实现一个用户提交任务请求的页面,讲述表单.视图.模型.模板间的交互. 首先,我们需要定义一个表单(forms.py) class CreatetaskForm(forms.Form): cre ...
- java实现文件夹(包括其中的子文件夹、子文件)的复制——递归
这是学校java课的一道实验题,题目如下:编程,根据指定的源和目标位置,完成指定文件或文件夹(包括其中的子文件夹.子文件)的复制. 以下是我的实现,使用了递归: package com.simon.m ...
- 【HTML相关】iframe+javascript实现一个表单提交后多个处理文件按序处理
最近在弄一个网页的问题,总结如下. [问题描述] 页面中包括以下几个部分:1)表单form,供用户输入图片文件:2)iframe1,显示a.php文件的内容,a.php接收客户端图片并保存,后台程序处 ...
- 2057 A + B Again
A + B Again Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total S ...