什么是Service?

Service(服务)是Android提供的四大组件之一,是一个没有用户界面的在后台运行执行耗时操作的应用组件。其他应用组件能够启动Service,并且当用户切换到另外的应用场景,Service将持续在后台运行。为了方便记忆,我们可以把Service看做是没有页面的Activity,它总是默默的后台处理一些耗时的操作或者不干扰用户使用的后台操作,例如,一个service可能会处理网络操作,播放音乐,操作文件I/O或者与内容提供者(content provider)交互,所有这些活动都是在后台进行。

Service都有哪些?

1)按照使用范围分类:

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

Local Service运行于当前app的主进程中,如果当前app的进程被Kill掉了,Local Service也会随着随之终止。使用场景举例:音乐播放器服务

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

          Remote Service是运行于一个独立的进程中,可以被多个app复用,可以使用android:process声明进程名字,由于运行于独立的进程,Activity所在进程被Kill的时候不会影响Remote Service。

2)按照运行类别分类:

    1.前台服务

前台服务是那些被认为用户知道的并且在内存低的时候不允许系统杀死的服务,通过startForeground 使服务成为 前台服务。

2.后台服务

区别于前台服务,创建的服务默认是后台服务,在内存低的时候有可能被系统杀死。

3)按照使用方式分类:

    1.context.startService()

2.context.bindService()

Service的如何使用?

    1.Service AndroidManifest.xml 声明

<service android:enabled=["true" | "false"]
android:exported=["true" | "false"]
android:icon="drawable resource"
android:isolatedProcess=["true" | "false"]
android:label="string resource"
android:name="string"
android:permission="string"
android:process="string" >
. . .
</service>

具体参数解说:

android:name 服务类名

android:label 服务的名字,如果此项不设置,那么默认显示的服务名则为类名

android:icon  服务的图标

android:permission 申明此服务的权限,这意味着只有提供了该权限的应用才能控制或连接此服务

android:process  表示该服务是否运行在另外一个进程,如果设置了此项,那么将会在包名后面加上这段字符串表示另一进程的名字

android:enabled  如果此项设置为 true,那么 Service 将会默认被系统启动,不设置默认此项为 false

android:exported  表示该服务是否能够被其他应用程序所控制或连接,不设置默认此项为 false

具体写个测试Service

public class TestService extends Service {

    private TestBinder binder=new TestBinder();
private Thread testThread;
private boolean isStart=false; @Override
public void onCreate() {
super.onCreate();
Log.e("TestService", "执行 onCreate()");
startForeground();
} private void startForeground(){
Notification.Builder builder = new Notification.Builder(this);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
new Intent(this, MainActivity.class), 0);
builder.setContentIntent(contentIntent);//设置目标跳转
builder.setSmallIcon(R.mipmap.ic_launcher);//设置显示的图片
builder.setTicker("前台服务开启");// 状态栏上显示
builder.setContentTitle("前台服务");//设置标题
builder.setContentText("这是一个前台服务");
Notification notification = builder.build();
startForeground(1, notification);
} @Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e("TestService", "执行 onStartCommand()");
//startThread();
//testANR();
return super.onStartCommand(intent, flags, startId);
} @Override
public void onDestroy() {
super.onDestroy();
Log.e("TestService", "执行 onDestroy()");
stopThread();
stopForeground(true);
} @Override
public IBinder onBind(Intent intent) {
Log.e("TestService", "执行 onBind()");
return binder;
} class TestBinder extends Binder { public void testMethod() {
Log.e("TestService", "执行 testMethod()");
} } //测试是否ANR
private void testANR(){
try {
Thread.sleep(50000);
} catch (Exception e) {
}
} private void startThread(){
stopThread();
isStart = true;
if (testThread == null) {
testThread = new Thread(runnable);
testThread.start();
}
} private void stopThread(){
try {
isStart = false;
if (null != testThread && Thread.State.RUNNABLE == testThread.getState()) {
try {
Thread.sleep(500);
testThread.interrupt();
} catch (Exception e) {
testThread = null;
}
}
testThread = null;
} catch (Exception e) {
e.printStackTrace();
} finally {
testThread = null;
}
} private Runnable runnable=new Runnable() {
@Override
public void run() {
while(isStart) {
Log.e("TestService", "runnable");
} }
};
}

启动/关闭,绑定/解绑

         //开启service
Log.e("TestService", "执行 startService()");
Intent intent =new Intent(MainActivity.this,TestService.class);
startService(intent); //停止service
Log.e("TestService", "执行 stopService()");
Intent intent =new Intent(MainActivity.this,TestService.class);
stopService(intent); //绑定service
Log.e("TestService", "执行 bindService()");
Intent intent =new Intent(MainActivity.this,TestService.class);
bindService(intent,connection,BIND_AUTO_CREATE); //解绑service
Log.e("TestService", "执行 unbindService()");
unbindService(connection); //测试ServiceConnection
private ServiceConnection connection = new ServiceConnection() { @Override
public void onServiceDisconnected(ComponentName name) {
} @Override
public void onServiceConnected(ComponentName name, IBinder service) {
TestService.TestBinder testBinder = (TestService.TestBinder) service;
testBinder.testMethod();
}
};

接下来了解下Service的生命周期:

1)startService()/stopService()方式  onCreate()---->onStartCommand()---->running()---->onDestory()

如果多次startService()会不会多次onCreate呢?Service只会调用一次onCreate(),但会多次调用onStartCommand()

如果多次调用stopService()呢?调用stopService()一次终止服务

2)bindService()/unbindService()方式  onCreate()---->onBind()---->running()---->onDestory()

3)同时调用了startService()/bindService()

首先看下我们调用stopService() 看下运行结果如下:未执行onDestory()服务无法关闭;所有两者同时使用时先调用unbindService()然后再调用stopService()才能真正关闭服务

接下来我们重点看下onStartCommand(Intent intent, int flags, int startId)方法中的flags参数。

START_NOT_STICKY:当Service因为内存不足而被系统kill后,接下来未来的某个时间内,即使系统内存足够可用,系统也不会尝试重新创建此Service。除非程序中Client明确再次调用startService(...)启动此Service。

START_STICKY:当Service因为内存不足而被系统kill后,接下来未来的某个时间内,当系统内存足够可用的情况下,系统将会尝试重新创建此Service,一旦创建成功后将回调onStartCommand(...)方法,但其中的Intent将是null,pendingintent除外。

START_REDELIVER_INTENT:与START_STICKY唯一不同的是,回调onStartCommand(...)方法时,其中的Intent将是非空,将是最后一次调用startService(...)中的intent。

START_STICKY_COMPATIBILITY:默认flags值

通常我们为了防止Service在内存不足的时候被系统杀死,把flags设置成START_STICKY 但是在4.0之后部分手机也是无效的,被杀死之后不会重启了。

我们该如何提供app服务不被杀死或者降低被杀死的概率呢?我们可以把设置服务为前台服务,比如音乐播放器,app退出之后就变成前台服务。直接看具体实现:

   //设置前台服务
private void startForeground(){
Notification.Builder builder = new Notification.Builder(this);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
new Intent(this, MainActivity.class), 0);
builder.setContentIntent(contentIntent);//设置目标跳转
builder.setSmallIcon(R.mipmap.ic_launcher);//设置显示的图片
builder.setTicker("前台服务开启");// 状态栏上显示
builder.setContentTitle("前台服务");//设置标题
builder.setContentText("这是一个前台服务");
Notification notification = builder.build();
startForeground(1, notification);
} //关闭前台服务,参数true 代表remove状态栏通知
stopForeground(true);

具体效果:

每当我们讨论Service的时候总是听到别人说:Service用来处理一个耗时的操作!!!接下来我们来验证一下Service里该如何处理耗时操作?

为了方便写了一个模拟耗时的函数:

    //测试是否ANR
private void testANR(){
try {
Thread.sleep(50000);
} catch (Exception e) {
}
}

测试运行:

    @Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e("TestService", "执行 onStartCommand()");
//startThread();
testANR();
return super.onStartCommand(intent, flags, startId);
}

运行结果:

其实结果是在我们的意料之中的,经过上面的知识我们已经得知本地服务是依托附主进程的上的,处理耗时操作肯定会造成ANR的,如果改成远程服务就不会造成ANR了。所以我们在Service处理耗时操作也是要像Activity一样采用异步处理的。需要主要的时如果我们在Service中起了一个线程,我们必须在onDestory ()函数中销毁线程。因为我们stopService()的时候线程并不会随之销毁。因此可知:Service和Thread是两码事,没有一毛钱的关系。

知识拓展:

1)检查某个Service是否在运行中:

    private boolean isServiceRunning(String className) {
boolean isRunning = false;
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningServiceInfo> serviceList = activityManager.getRunningServices(30); if (!(serviceList.isEmpty())) {
return false;
} for (int i=0; i<serviceList.size(); i++) {
if (serviceList.get(i).service.getClassName().equals(className) == true) {
isRunning = true;
break;
}
}
return isRunning;
}

2)本文中开启Service采用的显式Intent,同样采用隐式Intent开启Service,如果app被破译则有安全隐患。

<permission android:name="com.whoislcj.testservice.permission"/>
<uses-permission android:name="com.whoislcj.testservice.permission"/>

如果一个实体运行或绑定一个服务,必须要拥有该服务的权限。如果没有权限, startService() , bindService() 或 stopService() 方法将不执行, Intent 也不会传递到服务。

3)Service与UI之间的通讯。

UI----->Service :Intent传值

UI----->Service  :绑定Service传值

UI<---->Service: 通过广播

4)Service与AIDL实现跨进程通信  总结文章地址:http://www.cnblogs.com/whoislcj/p/5509868.html

先认识几个名词:

  • 进程间通信(IPC):Inter Process Communication
  • AIDL:Android Interface Definition Language, Android接口定义语言

Android探索之Service全面回顾及总结的更多相关文章

  1. (转载)Android中的Service:Binder,Messenger,AIDL(2)

    前言 前面一篇博文介绍了关于Service的一些基本知识,包括service是什么,怎么创建一个service,创建了一个service之后如何启动它等等.在这一篇博文里有一些需要前一篇铺垫的东西,建 ...

  2. Android 面试题--Service

    1.Service 是否在 main thread 中执行, service 里面是否能执行耗时的操作?默认情况,如果没有显示的指 servic 所运行的进程, Service 和 activity ...

  3. Android 中的 Service 全面总结(转载)

    转载地址:http://www.cnblogs.com/newcj/archive/2011/05/30/2061370.html 感谢作者 Android 中的 Service 全面总结 1.Ser ...

  4. java攻城狮之路(Android篇)--BroadcastReceiver&Service

    四大组件:activity 显示. contentProvider 对外暴露自己的数据给其他的应用程序.BroadcastReceiver 广播接收者,必须指定要接收的广播类型.必须明确的指定acti ...

  5. 图解Android - Binder 和 Service

    在 Zygote启动过程 一文中我们说道,Zygote一生中最重要的一件事就是生下了 System Server 这个大儿子,System Server 担负着提供系统 Service的重任,在深入了 ...

  6. Android 服务类Service 的详细学习

    http://blog.csdn.net/vipzjyno1/article/details/26004831 Android服务类Service学习四大组建   目录(?)[+] 什么是服务 服务有 ...

  7. 大仙说道之Android studio实现Service AIDL

    今天要开发过程中要用到AIDL的调用,之前用的eclipse有大量教程,用起来很方便,现在刚换了Android studio,不可否认studio真的很强大,只是很多功能还需要摸索. AIDL(And ...

  8. Android四大组件——Service

    Service相关链接 Service初涉 Service进阶 Service精通 Service是Android系统中的一种组件,它跟Activity的级别差不多,但是它不能自己运行,只能后台运行, ...

  9. Android学习总结——Service组件

    从Service的启动方式上,可以将Service分为Started Service和Bound Service.在使用Service时,要想系统能够找到此自定义Service,无论哪种类型,都需要在 ...

随机推荐

  1. Code[VS] 1230 题解

    1230 元素查找 题目描述 Description 给出n个正整数,然后有m个询问,每个询问一个整数,询问该整数是否在n个正整数中出现过. 输入描述 Input Description 第一行两个整 ...

  2. 反编译apk时遇到的问题

    第一次尝试反编译的时候遇到如下问题:Input file (ganzhou) was not found or was not readable 百度之后说是apktool版本2.0以上,编译命令变了 ...

  3. C#调用exe文件,IIS发布后无法掉用本地exe程序的解决方法

    http://blog.csdn.net/junjieking/article/details/6277836?reload这位楼主的问题,我也遇到了,但是我按照他那样操作并没有解决问题,弄了好久终于 ...

  4. 压缩png质量不改变像素

    private static byte[] CompressionImage(Bitmap bitmap, Stream fileStream, long quality) { using (Syst ...

  5. SEO:避免关键词内部竞争带来的无法收录问题,

    站内关键词相互竞争在未经过搜索引擎优化的网站中常出现.许多人不理解搜索引擎对关键词的索引原理,以为在整站内频繁布局某几个热门关键词能提升这些词的排名. 一.搜索引擎希望展现多种多样的搜索结果 搜索引擎 ...

  6. SQL 表的完整性

    建立:主外键,约束.(删除主表的时候,同时删除子表:更新主表的时候更新子表) 1.建表时定义主键 Create table 表名 ( Sno int identity(1,1), Sname nvar ...

  7. PHP基础知识之foreach

    定义: foreach (array_expression as $value)------------循环时传递key foreach (array_expression as $key => ...

  8. 微信支付:JSAPI支付一直提示URL未注册

    今天意外碰上了这个问题,想想微信的坑真多…… 解决办法: 首先要看微信公众号里的 支付授权目录 是否已正确填写,还要验证 url大小写 必须相同 其次查看一下自己请求的地址是否与上面填写的是否一样!u ...

  9. git配置ssh(github)

    [参考官方文档] SSH keys are a way to identify trusted computers, without involving passwords. The steps be ...

  10. Mpale 在汽车底盘悬架系统公差分析应用

    汽车底盘的作用是接受发动机的动力,使车轮转动,并保证汽车按驾驶员的操纵正常行驶.底盘包括传动系统.行驶系统.转向系统和制动系统这四大部分,通常,这四大系统也简称为传动系.行驶系.转向系和制动系.悬架是 ...