(学习参考书:第一行代码第2版)
服务是Android中实现程序后台运行的解决方案,适合去执行那些不需要和用户交互而且还需要长时间运行的任务。服务的运行不依赖任何用户界面,及时程序被切换到后台,或者用户打开了另外一个应用程序,服务仍然能够保持正常运行。
服务不是运行在一个独立的线程当中的,而是依赖于创建服务时所在的应用程序进程。当某个应用程序进程被杀掉时,依赖于该进程的服务也会停止运行。
服务也不会自动开启线程,所有的代码默认运行在主线程当中。需要在服务的内部创建子线程,并在这执行具体的任务。

一、Android多线程

Android多线程跟Java多线程采用相同的语法,有三种方式使用线程

  1. 定义线程时只需要新建一个类继承自Thread,然后重写父类的run()方法,并且在里面编写耗时逻辑即可。创建Thread子类的实例后,调用它的start()方法就可以让run方法中的代码在子线程中运行了。
  2. 新建类实现Runnable接口,再重写run()方法。调用时创建实例传入Thread类的构造函数里,再调用Thread的start()方法即可。
  3. 采用匿名类的方式,直接new Thread(new Runnable(){}).start。

二、在子线程中更新UI

与许多其他的GUI库一样,Android的UI也是线程不安全的。也就是说,想要更新应用程序中的UI元素,则必须在主线程中进行,否则会出现异常。
为了解决有时候必须在子线程里去执行一些耗时任务,然后根据任务的执行结果来更新相应的UI控件。Android提供了一套异步消息处理机制,完美的解决了在子线程中进行UI操作的问题。
在子线程中进行UI操作的问题。

(1)基本用法

  1. 在主线程中创建一个Hanlder对象,并重写handleMessage()方法
  2. 当子线程需要进行UI操作时,就创建一个Message对象,并通过Hanlder将这条消息发送出去
  3. 之后这条消息会被添加到MessageQueue的队列中等待被处理
  4. Looper会一直尝试从MessageQueue中取出待处理消息,最后分发回Handler的handleMessage()方法中。
public static final int UPDATE_TEXT=1;
private TextView text;
private Handler handler = new Handler(Looper.getMainLooper()){@Overridepublic void handleMessage(@NonNull Message msg) {switch (msg.what){case UPDATE_TEXT:text.setText("Hello Android!");break;default:break;}}
};
……
new Thread(new Runnable() {@Overridepublic void run() {Message message = new Message();message.what =UPDATE_TEXT;handler.sendMessage(message);}
}).start();

(2)解析异步消息处理机制

Android中的异步消息处理机制主要由4个部分组成:

Message

Message是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间交换数据。

Handler

主要用于发送和处理消息。发送消息一般是Handler的sendMessage()方法,发出的消息经过一系列的辗转处理后,最终会传递到Handler的hanleMessage()方法中。

MessageQueue

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

Looper

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

(3)使用AsyncTask

AsycnTask可以更简单的从子线程切换到主线程。其背后的实现原理也是基于异步消息处理机制的。
AsycnTask是一个抽象类,如果想使用它,就必须创建一个子类去继承它。在继承时可以为AsycnTask类指定三个泛型参数,用途如下:

Params 在执行AsycnTask时需要传入的参数,可用于在后台任务中使用
Progress 后台任务执行时,如果需要在界面上显示当前的进度,则使用这里指定的泛型作为进度单位
Result 当任务执行完毕后,如果需要对结果进行返回,则使用这里指定的泛型作为返回值类型

AsycnTask子类通常需要重写的方法:

onPreExecute() 该方法会在后台任务开始执行之前调用,用于进行一些界面上的初始化操作,比如显示一个进度条对话框doInBackground(Params…) 该方法的所有代码都会在子线程中运行,应该在这里去处理所有的耗时任务。任务一旦完成就可以通过return语句来将任务的执行结果返回,如果AsycnTask的第三个泛型参数指定为Void,可以不返回。该方法中不能进行UI操作;如需更新,如反馈任务进度,可以调用pubishProgress(Progress)方法完成。onProgressUpdate(Progress…) 当在后台任务中调用了pubishProgress(Progress)方法后,该方法会很快被调用。该方法携带的参数就是后台任务中传递过来的。在这个方法中可以对UI进行操作,利用参数中的数值就可以对界面元素进行相应的更新。onPostExecute(Result) 当后台任务执行完毕并通过return语句进行返回时,这个方法很快被调用。返回的数据作为参数传递到此方法中,可以利用返回的数据进行UI操作。

简单来说,AsycnTask的使用诀窍是:在doInBackground()方法中执行具体的耗时操作,在onProgressUpdate()方法中进行UI操作,在onPostExecute()方法中执行一些任务的收尾工作。只需要调用publishProgress()方法,就可以轻松从子线程切换到UI线程了。

三、服务的基本用法

(1)定义服务

自定义的服务类是继承于Service类的,onBind方法时Service中唯一一个抽象方法,必须要在子类中实现。除此之外,还可以重写onCreate()每次服务创建时调用,onStartComand()每次服务启动时调用,onDestory()服务销毁时调用等方法。

(2)启动和停止服务

启动和停止服务是 借助Intent实现的。

  1. 启动服务:创建Intent对象,传入参数上下文和服务类实例;调用startService()方法,传入intent对象
  2. 停止服务:创建Intent对象,传入参数上下文和服务类实例;调用stopService()方法,传入intent对象。在服务内部任意位置调用stopSelf()也可以让服务停止。

(3)活动与服务间通信

要实现活动和服务间的通信,需要使用到Service类重写的onBind()方法,具体方法如下:

  1. 创建一个专门继承Binder的类来对需要实现的功能进行管理
  2. 在Binder子类内部实现需要的功能
  3. 创建新建类的实例,在onBind()中返回
  4. 在活动中绑定服务,首先创建一个ServiceConnection的匿名类
  5. 在匿名类中重写onServiceConnection()和onServiceDisconnection()方法,这两个方法分别会在活动与服务成功绑定和连接断开的时候调用
  6. 在onServiceConnection()方法中通过下转型获得Binder子类的实例,这样在活动中根据具体场景可以调用Binder子类中任何public()方法,即实现指挥服务实现相应功能
  7. 通过构建和服务相关的Intent对象,调用bindService()方法将活动和服务绑定起来。该方法接收三个参数:Intent对象、ServiceConnection对象、标志位
  8. 如果需要解绑服务,调用unbindService()方法即可

(4)服务的生命周期

一旦项目在任何位置调用了startService()方法,相应的服务就会启动起来,并回调onStartCommand()方法。如果这个服务之前没有被创建过,onCreate()方法会先于onStartCommand()方法执行。服务启动后会一直保持运行状态,直到stopService()stopSelf()方法被调用。
还可以调用bindService()方法来获取一个服务的持久连接,这时就会回调服务中的onBind()方法。如果服务未被创建,onCreate()方法会先于onBind()执行。之后,调用方可以获取到onBind()方法力返回的IBinder对象实例,就可以自由与服务通信了。只要调用方和服务的链接没有断开,服务就会一直保持运行状态。
当调用startService()方法后,又去调用stopService()方法,这是服务中的onDestory()方法就会执行,表示服务已被销毁。类似的,调用了bindService()方法后,又调用unbindService()方法,onDestory()方法也会执行。当两个启动方法都被调用,则只有同时调用两个停止方法才能让onDestory()方法执行。

区别辨析:
stopSelf() 服务执行完成onCreate()后,停止service,调用onDestory()方法
stopService() 立即停止服务,调用onDestory()方法

(5)使用前台服务

服务几乎都是在后台运行的,优先级较低,容易被系统回收。如果希望服务一直保持运行状态,可以考虑使用前台服务。前台服务会一直有一个正在运行的图标在系统的状态栏显示,类似于通知。创建前台服务的方法如下:

  1. 在AndroidManifest.xml中添加前台服务的权限:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
  1. 创建一个通知
  2. 使用startForeground()方法传入id和Notification对象

(6)在子线程运行服务

服务中的代码默认运行在主线程当中,如果直接在服务里处理一些耗时操作,很容易出现程序无响应的情况。这时就需要在服务的每个具体方法里开启一个子线程,然后在子线程里处理耗时操作。故一个标准服务可写为:

public class MyService extends Service{...@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {new Thread(new Runnable() {@Overridepublic void run() {//具体操作逻辑stopself();}})return super.onStartCommand(intent, flags, startId);}
}

处于子线程的服务一旦启动后,会一直处于运行状态,必须调用stopService()或者stopSelf()方法才能让服务停止下来。

Android开发学习之探究服务相关推荐

  1. android 壁纸服务,Android开发学习之WallPaper设置壁纸详细介绍与实例

    今天和大家分享的是关于在android中设置壁纸的方法,在android中设置壁纸的方法有三种,分别是: 1.使用wallpapermanager的setresource(int resourceid ...

  2. 《Android Studio应用开发实战详解》——第1章,第1.5节Android开发学习路线图

    本节书摘来自异步社区<Android Studio应用开发实战详解>一书中的第1章,第1.5节Android开发学习路线图,作者 王翠萍,更多章节内容可以访问云栖社区"异步社区& ...

  3. android培训内容明细,记录Android开发学习

    记录Android开发学习 Menu菜单学习 1.掌握Android中菜单的创建. 2.掌握Intent信使组件. 创建菜单Menu 我们模仿微信菜单栏学习,创建一个于微信菜单栏相似的菜单 那么我们应 ...

  4. android开发学习之路——连连看之游戏逻辑(五)

    GameService组件则是整个游戏逻辑实现的核心,而且GameService是一个可以复用的业务逻辑类. (一)定义GameService组件接口 根据前面程序对GameService组件的依赖, ...

  5. Android开发学习---使用Intelij idea 13.1 进行android 开发

    Android开发学习---使用Intelij idea 13.1 进行android 开发 原文:Android开发学习---使用Intelij idea 13.1 进行android 开发 1.为 ...

  6. 《Java和Android开发学习指南(第2版)》—— 1.5 本章小结

    本节书摘来异步社区<Java和Android开发学习指南(第2版)>一书中的第1章,第1.5节,作者:[加]Budi Kurniawan,更多章节内容可以访问云栖社区"异步社区& ...

  7. 《Java和Android开发学习指南(第2版)》——第2章,第2.10节本章小结

    本节书摘来自异步社区<Java和Android开发学习指南(第2版)>一书中的第2章,第2.10节本章小结,作者 [加]Budi Kurniawan,更多章节内容可以访问云栖社区" ...

  8. Android开发学习之基于ViewPager实现Gallery画廊效果

    通过我们前面的学习,我们知道ViewPager是可以做出近乎完美的滑动体验,回顾整个Android,我们发现Gallery具备同样的特点,于是我们大胆地猜想,Gallery是否和ViewPager之间 ...

  9. Android开发学习总结(四)——Eclipse在线安装ADT插件

    Android开发学习总结(四)--Eclipse在线安装ADT插件 要想使用Eclipse开发Android应用,首先要安装一个ADT插件,在此记录一下在Eclipse中采用在线安装的方式ADT插件 ...

最新文章

  1. 学python好找工作么-学完Python好找工作吗?为什么有人学完还找不到工作?
  2. python3安装setuptools步骤_linux环境下的python安装过程(含setuptools)
  3. DeepMind用ReinforcementLearning玩游戏
  4. 出国?上研?工作?回家种田?(三) IT类专业的工作方向与特点(软硬件技术等岗位)
  5. 只要懂得拒绝,哪会有什么狗血感情与莫名其妙的误会
  6. apache.camel_使用Apache Camel 2.14的轻松REST端点
  7. win10查看端口占用
  8. 5分钟带你看懂 GCanvas渲染引擎的演进
  9. 编译分析:提memcmp.c+gcc四十米大刀到C#世界中屠龙
  10. B/S应用中的ActiveX数字签名相关问题杂谈
  11. 最新!2021全球Top 1000计算机科学家h指数发布,中国53人上榜!Bengio总榜第二,韩家炜居华人首位...
  12. 学习笔记:unity自带寻路(导航)系统:Nav Mesh导航网格
  13. 苏州新导监狱戒毒行业工具资产智能管理
  14. ARP报文头部格式和请求流程
  15. 【Linux 0.11】第九章 块设备驱动程序
  16. 墨迹天气灰白色风格Discuz模板源码
  17. Typora也能做思维导图?做笔记的又一个绝佳选择?
  18. Linux下的延时函数
  19. 服务器上tomcat修改内存,8g服务器tomcat内存设置
  20. 华南师大计算机转专业,广西师范大学计算机科学与信息工程学院/软件学院转专业管理规定(试行)...

热门文章

  1. PyG搭建GAT实现节点分类
  2. woo语言使用sockets模拟http请求
  3. python 删除文件夹、删除非空文件夹
  4. 【ASE入门学习】ASE入门系列二十四——轴向溶解
  5. 那些年啊 那些事 一个程序员的奋斗史 127
  6. c语言专业教学,C语言在计算机专业中的教学.docx
  7. 加工制造业采购商城平台:实现加工制造业采购自动化、协同化管理
  8. 直播软件开发Android直播悬浮窗实现
  9. Mybatis从入门到精通(刘增辉)
  10. Tesseract的所有参数