服务(Service)是 Android 中实现程序后台运行的解决方案,它非常适合用于去执行那些不需要和用户交互而且还要求长期运行的任务。

一、多线程编程

先介绍一下四个组件:

  1. Message

Message 是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间交换数据。上一小节中我们使用到了 Message 的 what 字段,除此之外还可以使用 arg1 和 arg2 字段来携带一些整型数据,使用 obj 字段携带一个 Object 对象。

  1. Handler

Handler 顾名思义也就是处理者的意思,它主要是用于发送和处理消息的。发送消息一般是使用 Handler 的 sendMessage()方法,而发出的消息经过一系列地辗转处理后, 最终会传递到 Handler 的 handleMessage()方法中。

  1. MessageQueue

MessageQueue是消息队列的意思,它主要用于存放所有通过 Handler 发送的消息。这部分消息会一直存在于消息队列中,等待被处理。每个线程中只会有一个 MessageQueue 对象。

  1. Looper

Looper 是每个线程中的 MessageQueue 的管家,调用 Looper 的 loop()方法后,就会进入到一个无限循环当中,然后每当发现 MessageQueue 中存在一条消息,就会将它取出,并传递到 Handler 的 handleMessage()方法中。每个线程中也只会有一个 Looper 对象。

public class MainActivity extends Activity implements OnClickListener { public static final int UPDATE_TEXT = 1;private TextView text; private Button changeText;private Handler handler = new Handler() {public void handleMessage(Message msg) { switch (msg.what) {case UPDATE_TEXT:// 在这里可以进行UI操作text.setText("Nice to meet you"); break;default:break;}}};@Overridepublic void onClick(View v) { switch (v.getId()) {case R.id.change_text:new Thread(new Runnable() { @Overridepublic void run() {Message message = new Message(); message.what = UPDATE_TEXT;handler.sendMessage(message); // 将Message对象发送出去}}).start(); break;default:break;}
}

使用 AsyncTask

class DownloadTask extends AsyncTask<Void, Integer, Boolean> {@Overrideprotected void onPreExecute() {progressDialog.show(); // 显示进度对话框}@Overrideprotected Boolean doInBackground(Void... params) {try {while (true) {int downloadPercent = doDownload(); // 这是一个虚构的方法publishProgress(downloadPercent);if (downloadPercent >= 100) {break;}}} catch (Exception e) {return false;}return true;}@Overrideprotected void onProgressUpdate(Integer... values) {// 在这里更新下载进度progressDialog.setMessage("Downloaded " + values[0] + "%");}@Overrideprotected void onPostExecute(Boolean result) {progressDialog.dismiss(); // 关闭进度对话框// 在这里提示下载结果if (result) {Toast.makeText(context, "Download succeeded", Toast.LENGTH_SHORT).show();} else {Toast.makeText(context, " Download failed", Toast.LENGTH_SHORT).show();}}
}
  1. 在 doInBackground()方法里去执行具体的下载任务。这个方法里的代码都是在子线程中运行的,因而不会影响到主线程的运行。注意这里虚构了一个doDownload()方法,这个方法用于计算当前的下载进度并返回。

  2. 调用 publishProgress()方法并将当前的下载进度传进来,这样 onProgressUpdate()方法就会很快被调用,在这里就可以进行 UI 操作了。

  3. 当下载完成后,doInBackground()方法会返回一个布尔型变量,这样 onPostExecute()方法就会很快被调用,这个方法也是在主线程中运行的。然后在这里我们会根据下载的结果来弹出相应的 Toast 提示,从而完成整个 DownloadTask 任务。

简单来说,使用 AsyncTask 的诀窍就是,在 doInBackground()方法中去执行具体的耗时任务,在 onProgressUpdate()方法中进行 UI 操作,在 onPostExecute()方法中执行一些任务的收尾工作。

二、服务的基本用法

  1. 新建一个服务继承Service类。
public class MyService extends Service {@Overridepublic IBinder onBind(Intent intent) {return null;}@Overridepublic void onCreate() {super.onCreate();}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {return super.onStartCommand(intent, flags, startId);}@Overridepublic void onDestroy() {super.onDestroy();}
}

其中 onCreate()方法会在服务创建的时候调用,onStartCommand()方法会在每次服务启动的时候调用,onDestroy()方法会在服务销毁的时候调用。onBind()方法目前暂时将它忽略掉。

  1. 在AndroidManifest.xml注册该服务(四大组件都需要注册)
<service android:name=".MyService" >
</service>
  1. 启动和停止服务
// 启动服务
Intent startIntent = new Intent(this, MyService.class);
startService(startIntent); // 停止服务
Intent stopIntent = new Intent(this, MyService.class);
stopService(stopIntent);

二、活动与服务之间的通信

启动服务之后,活动与服务无关。只是活动通知服务一下:你可以启动了,具体做什么不知道,完成的如何也不知道。 那么如何让活动与服务更紧密一些:那就要用上面的onbind方法了。

目的:在 MyService 里提供一个下载功能,然后在活动中可以决定何时开始下载,以及随时查看下载进度。

  1. 首先要知道ServiceConnection这个类的onServiceConnected和onServiceDisconnected这两个方法分别会在绑定服务和取消绑定服务的时候回调用。我们写一个匿名内部类。
private ServiceConnection connection = new ServiceConnection() { @Overridepublic void onServiceDisconnected(ComponentName name) {}@Overridepublic void onServiceConnected(ComponentName name, IBinder service) { }
};

可以看到onServiceConnected传进一个Ibinder实例。

  1. 我们创建一个Ibinder实例
private DownloaderBinder mBinder = new DownloaderBinder();class DownloaderBinder extends Binder{public void startDownload(){Log.d(TAG, "startDownload: ");}public int getProgress(){Log.d(TAG, "getProgress: ");return 0;}}
  1. 重写ServcieConnection的onServiceConnected方法,让服务和活动连接时产生联系。
public void onServiceConnected(ComponentName name, IBinder service) {downloaderBinder = (MyService.DownloaderBinder) service;downloaderBinder.startDownload();downloaderBinder.getProgress();
}

三、服务的生命周期

有onCreate、onStartCommand、onBind和onDestroy等方法都是在服务生命周期内可能调用的方法。

  1. 任何位置调用startService方法,服务会启动起来,并回调onStartCommand方法;若服务未曾创建,则onCreate会先于onStartCommand方法;服务启动后会运行,直到onStopService或StopSelf方法被调用;

  2. 还可以调用bindService来获得服务持久连接,此时回调bind方法,若未创建过,则会先onCreate再onbind,onBind方法会返回IBinder对象实例。自由通信了已经可以。

  3. bindService绑定后用unbindService解绑,此时会调用onDestroy方法;startService启动后会调用stopService来结束服务。若同时调用了startService,bindService两个方法,则必须同时调用stopService和unbindservice才可会执行onDestroy方法,因为android机制规定了服务被启动和绑定之后,会一直处于运行状态。

四、服务的更多技巧

  1. 使用前台服务

前台服务与普通服务最大区别在于:他有一个正在运行的图标在系统状态栏显示,下拉通知栏可看到更加详细,类似通知。比 如:彩云天气,后台更新天气数据,在系统栏一直显示当前天气信息。

与Notifiction比较类似,构建的notification并没有使用NotificationManager显示出来,而是调用startForeGround来使MyService变成一个前台服务,并在系统状态栏显示处出来。

@Override
public void onCreate() {super.onCreate();Log.d(TAG, "onCreate executed ");Intent intent = new Intent(this, MainActivity.class);PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);Notification notification = new NotificationCompat.Builder(this).setContentTitle("This is contnet title").setContentText("This is contnet Text").setWhen(System.currentTimeMillis()).setSmallIcon(R.mipmap.ic_launcher).setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher)).setContentIntent(pi).build();startForeground(1,notification);
}
  1. 使用IntentService

服务默认在主线程中进行,若在服务中处理耗时逻辑,则很容易出现ANR。这是采用多线程编程技术,在服务的每个方法中开启一个子线程去处理耗时逻辑。服务执行完后自动停止,可以使用StopSelf方法。

@Override
public int onStartCommand(Intent intent, int flags, int startId) {Log.d(TAG, "onStartCommand executed ");new Thread(new Runnable() {@Overridepublic void run() {//处理具体逻辑//服务执行完后自动停止,可以使用StopSelf方法stopSelf();}});return super.onStartCommand(intent, flags, startId);
}

IntentService主要用于解决程序员忘记开启线程,或者忘记调用stopSelf()方法

public class MyIntentService extends IntentService {protected void onHandleIntent(Intent intent) {//处理具体逻辑}
}

安卓学习 之 Service服务(十)相关推荐

  1. Android 学习笔记 Service服务与远程通信...(AIDL)

    PS:这一章节看的我有几分迷茫,不是很容易理解...不过还好总算是明白了一大半了...基本的迷惑是解决了... 学习内容: 1.跨应用启动服务... 2.跨应用绑定服务... 3.跨应用实现通信... ...

  2. 安卓学习 之 网络技术(十)

    一. 显示web页面 添加布局.使用webView 添加权限<user-permission android:name = "android.permission.INTERNET&q ...

  3. 【安卓学习之常见问题】google play service

    █ [安卓学习之常见问题]google play service █ 系列文章目录 提示:这里是收集了安卓学习之常见问题的相关文章 [安卓学习之常见问题] 界面(Activity/Fragment)之 ...

  4. Android重要组件之一 Service 服务讲解学习(一)

      在Android有异步处理需要重要的Service和Handler组件,今天首先学习一下Service组件,      其中涉及到Android Service中进程间通信和bindService ...

  5. 安卓基础知识(一) 服务(Service)

    安卓基础知识(一) 服务(Service) 一.基本概念: 1.服务就是长期于后台运行的程序,可以理解为是一个,用于执行长期任务,并且与用户没有交互的组件.每一个服务需要在配置文件AndroidMan ...

  6. Sharepoint2013商务智能学习笔记之Secure Store Service服务配置(二)

    Secure Store Service 是运行在应用程序服务器上的授权服务,它提供一个存储用户凭据的数据库,Secure Store Service 在商务智能中的地位很重要,Sharepoint商 ...

  7. 安卓学习文档收集汇总

    安卓学习文档收集汇总 https://www.jianshu.com/p/86aed183ce6c?utm_campaign=maleskine&utm_content=note&ut ...

  8. LINUX学习基础篇(十五)软件包管理

    LINUX学习基础篇(十五)软件包管理 软件包管理 软件包分类 源码包 二进制包 选择 依赖性 rpm包安装 rpm包命名规则 rpm包安装和卸载 服务命令 rpm查询命令 验证 数字证书 rpm中文 ...

  9. 安卓学习专栏——实战项目酷欧天气(4)给天气页面加上背景图片

    步骤 系列文章 前言 实现效果 项目结构 1.获取必应每日一图 1.1修改修改activity_weather.xml 1.2修改WeatherActivity 2.背景图和状态栏效果修改 2.1修改 ...

最新文章

  1. Unit05: 创建和访问数组 、 数组的常用方法_1
  2. 【delphi】Byte数组与String类型的转换
  3. PPT讲解机器人产业发展现状与未来展望,重磅资料
  4. 《Ceph源码分析》——第1章,第5节RADOS
  5. linux shell 字符串 数组,bash shell函数返回数组字符串
  6. nginx php unix负载,使用nginx配置多个php fastcgi负载均衡
  7. MPU6050代码解析
  8. r如何查询mysql中的数据类型_MySQL-mysql中的数据类型
  9. 零基础带你学习MySQL—分组统计(十二)
  10. c# 访问hbase_大数据技术之C#通过Thrift连接查询HBase主要方法总结
  11. 磁盘阵列 RAID 技术原理详解
  12. 计算机由指定用户登陆
  13. 在VMware16虚拟机安装Ubuntu详细教程
  14. 3Dmax2014安装问题
  15. 游戏术语 DAU APA ACU PCU
  16. 【项目记录】-上门洗车-汽车服务
  17. 与微型计算机运算速度无关的是,四川大学《计算机应用基础0006》17春在线作业1...
  18. 【读书笔记《凤凰架构》- 构架可靠的大型分布式系统.周志明】(一)
  19. Selenium2学习笔记
  20. 中国锌离子电池行业盈利动态与竞争前景预测报告(新版)2022-2027

热门文章

  1. linux 启动后台服务 nohup
  2. 分布式系统概念 | 分布式理论:CAP、BASE
  3. C++实现一个简易的线程池
  4. pycharm debug 断点调试
  5. python获取文件夹下所有文件的两种方式
  6. 《MySQL实战45讲》实践篇 9-15讲 学习笔记
  7. Java虚拟机结构分析
  8. 【多媒体内容与体验创新】
  9. 音视频技术开发周刊 | 199
  10. Zoom惊人财报、传苹果打造搜索引擎与谷歌竞争、Netflix部分剧集免费以吸引新用户等| Decode the Week...