1. Android Service总结03 之被启动的服务 -- Started Service

版本

版本说明

发布时间

发布人

V1.0

添加了Service的介绍和示例

2013-03-17

Skywang


1 Started Service介绍

Started Service,即被启动的服务。它是2种常见服务之一,另一种是Bound Service。Started Service常被用在执行进程的某个后台操作,如通过该服务来实现文件下载等功能。

  实现步骤和使用方法

(01) 创建一个Started Service类,该类要继承于Service。

(02) 在Started Service类中实现以下接口:
  onStartCommand():必须实现!在其中启动服务提供的功能。例如,若该服务是在后台下载文件,则在该函数中启动一个新的线程(Thread),在线程中实现下载功能。当客>户端通过startService()启动函数时,系统会自动执行服务对应的onStartCommand()函数。
  onBind():必须实现!返回null即可。onBind()是"Bound Service"中用到的函数,在"Started Service"服务不会执行onBind();但必须实现它,因为onBind()是Service类
的抽象方法。
  onCreate():可以不用实现,视用户需求而定。当服务被创建时,系统会自动调用该函数。一般在该函数中进行初始化工作,例如:新建线程。
  onDestroy():可以不用实现,视用户需求而定。当服务被销毁时,系统会自动调用该函数。一般在该函数中进行清除工作,例如,终止并回收线程。

(03) 客户端通过startService()启动服务。

(04) 客户端通过endService()结束服务。

 

  下面以实际例子来说明“Started Service”的实现方式。


2 Service示例

采用Service来实现“Android Service总结02 IntentService介绍及实例”中的示例,即:编写一个activity,包含2个按钮和1个进度条,2个按钮分别是开始按钮、结束按钮。点击“开始”按钮:进度条开始加载;“开始”变成“重启”按钮;显示“结束”按钮(默认情况,“结束”按钮是隐藏状态)。

BaseServiceTest包括了两个主要的类:

StartServiceImpl.java  —— 
Service的子类。当服务被启动时,它会并新建一个线程,每隔200ms将一个数字+2,并通过广播发送出去。

StartServiceTest.java 
——  调用StartServiceImpl的Activity。

StartServiceImpl.java的内容如下

  1. package com.skywang.service;
  2.  
  3. import android.os.IBinder;
  4. import android.app.Service;
  5. import android.content.Intent;
  6. import android.util.Log;
  7.  
  8. import java.lang.Thread;
  9. /**
  10. * @desc 服务:每隔200ms将一个数字+2并通过广播发送出去
  11. * @author skywang
  12. *
  13. */
  14. public class StartServiceImpl extends Service {
  15. private static final String TAG = "skywang-->StartServiceImpl";
  16.  
  17. // 发送的广播对应的action
  18. private static final String COUNT_ACTION = "com.skywang.service.startservice.COUNT_ACTION";
  19.  
  20. // 线程:用来实现每隔200ms发送广播
  21. private static CountThread mCountThread = null;
  22. // 数字的索引
  23. private static int index = 0;
  24.  
  25. @Override
  26. public void onCreate() {
  27. Log.d(TAG, "onCreate");
  28. super.onCreate();
  29. }
  30.  
  31. @Override
  32. public void onDestroy() {
  33. Log.d(TAG, "onDestroy");
  34.  
  35. // 终止服务
  36. if ( mCountThread != null) {
  37. mCountThread.interrupt();
  38. mCountThread = null;
  39. }
  40. super.onDestroy();
  41. }
  42.  
  43. @Override
  44. public int onStartCommand(Intent intent, int flags, int startId) {
  45. Log.d(TAG, "onStartCommand");
  46.  
  47. // 非首次运行服务时,执行下面操作
  48. // 目的是将index设为0
  49. if ( mCountThread != null) {
  50. Log.d(TAG, "mCountThread != null");
  51. index = 0;
  52. return START_STICKY;
  53. }
  54.  
  55. Log.d(TAG, "start thread");
  56. // 首次运行时,创建并启动线程
  57. mCountThread = new CountThread();
  58. mCountThread.start();
  59.  
  60. return START_STICKY;
  61. }
  62.  
  63. @Override
  64. public IBinder onBind(Intent intent) {
  65. Log.d(TAG, "onBind");
  66. return null;
  67. }
  68.  
  69. private class CountThread extends Thread {
  70. @Override
  71. public void run() {
  72. index = 0;
  73. try {
  74. while (true) {
  75. // 将数字+2,
  76. index += 2;
  77.  
  78. // 将index通过广播发送出去
  79. Intent intent = new Intent(COUNT_ACTION);
  80. intent.putExtra("count", index);
  81. sendBroadcast(intent);
  82. // Log.d(TAG, "CountThread index:"+index);
  83.  
  84. // 若数字>=100 则退出
  85. if (index >= 100) {
  86. if ( mCountThread != null) {
  87. mCountThread = null;
  88. }
  89. return ;
  90. }
  91.  
  92. // 修改200ms
  93. this.sleep(100);
  94. }
  95. } catch (InterruptedException e) {
  96. e.printStackTrace();
  97. }
  98. }
  99. }
  100. }

StartServiceTest.java的内容如下

  1. package com.skywang.service;
  2.  
  3. import android.os.Bundle;
  4. import android.app.Activity;
  5. import android.content.BroadcastReceiver;
  6. import android.content.Context;
  7. import android.content.Intent;
  8. import android.content.IntentFilter;
  9. import android.view.View;
  10. import android.widget.Button;
  11. import android.widget.ProgressBar;
  12. import android.util.Log;
  13.  
  14. public class StartServiceTest extends Activity {
  15. private static final String TAG = "skywang-->StartServiceTest";
  16.  
  17. private static final String COUNT_ACTION = "com.skywang.service.startservice.COUNT_ACTION";
  18. private CurrentReceiver mReceiver;
  19. private Button mStart = null;
  20. private Button mStop = null;
  21. private Intent mIntent = null;
  22. private Intent mServiceIntent = null;
  23. private ProgressBar mProgressBar = null;
  24. @Override
  25. protected void onCreate(Bundle savedInstanceState) {
  26. super.onCreate(savedInstanceState);
  27. setContentView(R.layout.start_service_test);
  28.  
  29. mStart = (Button) findViewById(R.id.start);
  30. mStart.setOnClickListener(new View.OnClickListener() {
  31.  
  32. @Override
  33. public void onClick(View arg0) {
  34. Log.d(TAG, "click start button");
  35. // 显示“结束”按钮
  36. mStop.setVisibility(View.VISIBLE);
  37. // 将“开始”按钮更名为“重启”按钮
  38. mStart.setText(R.string.text_restart);
  39. // 启动服务,用来更新进度
  40. if (mServiceIntent == null)
  41. mServiceIntent = new Intent("com.skywang.service.StartService");
  42. startService(mServiceIntent);
  43. }
  44. });
  45.  
  46. mStop = (Button) findViewById(R.id.stop);
  47. mStop.setOnClickListener(new View.OnClickListener() {
  48.  
  49. @Override
  50. public void onClick(View view) {
  51. Log.d(TAG, "click stop button");
  52. if (mServiceIntent != null) {
  53. // 结束服务。
  54. stopService(mServiceIntent);
  55. mServiceIntent = null;
  56. }
  57. }
  58. });
  59. mStop.setVisibility(View.INVISIBLE);
  60.  
  61. mProgressBar = (ProgressBar) findViewById(R.id.pbar_def);
  62. // 隐藏进度条
  63. mProgressBar.setVisibility(View.INVISIBLE);
  64.  
  65. // 动态注册监听COUNT_ACTION广播
  66. mReceiver = new CurrentReceiver();
  67. IntentFilter filter = new IntentFilter();
  68. filter.addAction(COUNT_ACTION);
  69. this.registerReceiver(mReceiver, filter);
  70. }
  71.  
  72. @Override
  73. public void onDestroy(){
  74. super.onDestroy();
  75.  
  76. if(mIntent != null)
  77. stopService(mIntent);
  78.  
  79. if(mReceiver != null)
  80. this.unregisterReceiver(mReceiver);
  81. }
  82.  
  83. /**
  84. * @desc 更新进度条
  85. * @param index
  86. */
  87. private void updateProgressBar(int index) {
  88. int max = mProgressBar.getMax();
  89.  
  90. if (index < max) {
  91. mProgressBar.setProgress(index);
  92. mProgressBar.setVisibility(View.VISIBLE);
  93. } else {
  94. // 隐藏进度条
  95. mProgressBar.setVisibility(View.INVISIBLE);
  96. // 隐藏“结束”按钮
  97. mStop.setVisibility(View.INVISIBLE);
  98. // 将“重启”按钮更名为“开始”按钮
  99. mStart.setText(R.string.text_start);
  100. }
  101. // Log.d(TAG, "progress : "+mProgressBar.getProgress()+" , max : "+max);
  102. }
  103.  
  104. /**
  105. * @desc 广播:监听COUNT_ACTION,获取索引值,并根据索引值来更新进度条
  106. * @author skywang
  107. *
  108. */
  109. private class CurrentReceiver extends BroadcastReceiver {
  110. @Override
  111. public void onReceive(Context context, Intent intent) {
  112. String action = intent.getAction();
  113. if (COUNT_ACTION.equals(action)) {
  114. int index = intent.getIntExtra("count", 0);
  115. updateProgressBar(index);
  116. }
  117. }
  118. }
  119. }

layout文件start_service_test.xml的内容如下

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:orientation="vertical"
  4. android:layout_width="match_parent"
  5. android:layout_height="match_parent"
  6. >
  7.  
  8. <LinearLayout
  9. android:orientation="horizontal"
  10. android:layout_width="wrap_content"
  11. android:layout_height="wrap_content"
  12. >
  13. <Button
  14. android:id="@+id/start"
  15. android:layout_width="wrap_content"
  16. android:layout_height="wrap_content"
  17. android:text="@string/text_start"
  18. />
  19. <Button
  20. android:id="@+id/stop"
  21. android:layout_width="wrap_content"
  22. android:layout_height="wrap_content"
  23. android:text="@string/text_stop"
  24. />
  25.  
  26. </LinearLayout>
  27.  
  28. <ProgressBar
  29. android:id="@+id/pbar_def"
  30. android:layout_width="match_parent"
  31. android:layout_height="wrap_content"
  32. style="@android:style/Widget.ProgressBar.Horizontal"
  33. android:max="100"
  34. android:progress="0"
  35. />
  36. </LinearLayout>

manifest内容如下

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3. package="com.skywang.service"
  4. android:versionCode="1"
  5. android:versionName="1.0" >
  6.  
  7. <uses-sdk
  8. android:minSdkVersion="11"
  9. android:targetSdkVersion="17" />
  10.  
  11. <application
  12. android:allowBackup="true"
  13. android:icon="@drawable/ic_launcher"
  14. android:label="@string/app_name"
  15. android:theme="@style/AppTheme" >
  16. <activity
  17. android:name="com.skywang.service.StartServiceTest"
  18. android:screenOrientation="portrait"
  19. android:label="@string/app_name" >
  20. <intent-filter>
  21. <action android:name="android.intent.action.MAIN" />
  22.  
  23. <category android:name="android.intent.category.LAUNCHER" />
  24. </intent-filter>
  25. </activity>
  26.  
  27. <service android:name=".StartServiceImpl">
  28. <intent-filter>
  29. <action android:name="com.skywang.service.StartService" />
  30. </intent-filter>
  31. </service>
  32. </application>
  33.  
  34. </manifest>

点击下载源代码

效果图


3 补充说明

在示例中,我们自定义了onStartCommand()的返回值。Android API文档中说明它的返回值,可以有以下4种:

START_STICKY

如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到service,那么参数Intent将为null。

START_NOT_STICKY

“非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务。

START_REDELIVER_INTENT

重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。

START_STICKY_COMPATIBILITY

START_STICKY的兼容版本,但不保证服务被kill后一定能重启。


更多service内容:

Android Service总结01 目录

Android Service总结02 service介绍

Android Service总结03 之被启动的服务 -- Started Service

Android Service总结04 之被绑定的服务 -- Bound Service

Android Service总结05 之IntentService

Android Service总结06 之AIDL

  1.  


  1. 参考文献:
    1Android API文档:http://developer.android.com/guide/components/services.html
  2. 2Android Service被关闭后自动重启,解决被异常kill 服务http://blog.csdn.net/by317966834/article/details/7591502
  1.  

Android Service总结03 之被启动的服务 -- Started Service的更多相关文章

  1. Android Service总结04 之被绑定的服务 -- Bound Service

    Android Service总结04 之被绑定的服务 -- Bound Service 版本 版本说明 发布时间 发布人 V1.0 添加了Service的介绍和示例 2013-03-17 Skywa ...

  2. Android 编程下的四大组件之服务(Service)

    服务(Service) 是一种在后台运行,没有界面的组件,由其他组件调用开始.Android 中的服务和 Windows 中的服务是类似的东西,它运行于系统中不容易被用户发觉,可以使用它开发如监控之类 ...

  3. Android开发之通过Intent启动其他App的Service

    在Android5.0以前可以通过隐式Intent方式启动其他App的Service,就跟Activity启动隐式Intent一样的. 但是在5.0以后,只能使用显示的Intent方式启动了. 启动其 ...

  4. 【Azure云服务 Cloud Service】如何在部署云服务Cloud Service时候通过启动任务Start Task来配置IIS (如开启ARR)

    问题情形 通过VS部署Cloud Service时,需要在开始任务时候安装或配置其他任务,如安装及配置ARR. 执行步骤 1) 下载 requestRouter_amd64.msi 和 webfarm ...

  5. Android系统在新进程中启动自定义服务过程(startService)的原理分析

    在编写Android应用程序时,我们一般将一些计算型的逻辑放在一个独立的进程来处理,这样主进程仍然可以流畅地响应界面事件,提高用户体验.Android系统为我们提供了一个Service类,我们可以实现 ...

  6. Android权限安全(9)Android权限特点及权限管理服务AppOps Service

    Android权限特点 权限管理服务AppOps Service 图中元素介绍: Ignore 是不提示的,Allow 是允许,Reject 是拒绝 Client是一个使用sms 的应用, AppOp ...

  7. nsis制作启动Tomcat服务的exe安装包教程

    一. 准备工作 下载nsis相关工具包,点击此下载 1. 安装程序:nsis-2.46-setup.exe 2. 编辑程序:cnisedit203.exe 3. 帮助文档:NSIS205帮助文档.ra ...

  8. Kali Linux常用服务配置教程启动DHCP服务

    Kali Linux常用服务配置教程启动DHCP服务 通过前面的介绍,DHCP服务就配置好了.接下来,用户就可以使用该服务器来获取IP地址了.下面将对前面配置的服务进行测试. 1.启动DHCP服务 如 ...

  9. Centos7 环境下开机 自启动服务(service) 设置的改变 (命令systemctl 和 chkconfig用法区别比较)

    参考文章:  <Linux 设置程序开机自启动 (命令systemctl 和 chkconfig用法区别比较)> http://blog.csdn.net/kenhins/article/ ...

随机推荐

  1. 更改jupyter notebook的主题颜色(theme) 包括pycharm

    https://blog.csdn.net/Techmonster/article/details/73382535

  2. ECS Navicat for MySQL远程连接报10038的错误

    解决问题时,建议先在阿里云设置好数据库访问的白名单,把自己的IP地址填进去 问题现象 Navicat for MySQL访问远程mysql数据库,出现报错,显示“2003- Can't connect ...

  3. Java List 转 String

    JAVA中List转换String,String转换List,Map转换String,String转换Map之间的转换工具类(调优)https://www.cnblogs.com/cn-wxw/p/6 ...

  4. 【AtCoder】AGC022

    A - Diverse Word 不到26位就加上一个最小的 到26位了就搜一下,最多回溯就一次,所以复杂度不大 #include <iostream> #include <cstd ...

  5. 判断js数组/对象是否为空

    /** * 判断js数组/对象是否为空 * isPrototypeOf() 验证一个对象是否存在于另一个对象的原型链上.即判断 Object 是否存在于 $obj 的原型链上.js中一切皆对象,也就是 ...

  6. pageHelper 排序 +- 字符串处理

    自己记录一下. 前端要把sort参数传过来, 1. 如果约定是下面这种形式: sort=id-name+age+ 直接在java后台进行替换就行,连正则都不用. sort = sort.replace ...

  7. 【Java】 大话数据结构(10) 查找算法(1)(顺序、二分、插值、斐波那契查找)

    本文根据<大话数据结构>一书,实现了Java版的顺序查找.折半查找.插值查找.斐波那契查找. 注:为与书一致,记录均从下标为1开始. 顺序表查找 顺序查找  顺序查找(Sequential ...

  8. 007.Zabbix监控图形绘制

    一 Graphs配置 1.1 新建图形 Graphs是将数据展示为图像,以视觉化形式展示,Graphs的配置保存在主机和模板中. Configuration---->Hosts---->G ...

  9. IdentityServer4系列之中文文档及实际项目经验分享

    0.前言 原文:http://docs.identityserver.io/en/release/声明: 1.目录一至五章节根据IdentityServer英文文档翻译而来,有些内容会根据自己的理解来 ...

  10. 【BZOJ 4819】 4819: [Sdoi2017]新生舞会 (0-1分数规划、二分+KM)

    4819: [Sdoi2017]新生舞会 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 601  Solved: 313 Description 学校 ...