一、服务的介绍:

作为Android四大组件之中的一个,Service(服务)也常常运用于我们的日常使用中,它与Activity的差别在于:Service一直在后台执行。没实用户界面。所以绝不会到前台来。但Service被启动起来之后。它就和Activity一样。全然具有自己的生命周期。

在关于程序中是选择用Activity还是Service的一个选择标准就是:假设某个程序组件须要执行时向用户呈现某种用户界面。或者该程序须要与用户交互,就须要使用Activity,否则就该考虑使用Service。

就像开发Activity须要两个步骤:①开发Activity子类;②在AndroidManifest文件里配置Activity。开发Service也须要两个步骤:①定义一个继承Service的子类;②在AndroidManifest文件里配置该Service。

public class FirstService extends Service {
@Nullable
@Override
/**
* Service中唯一的一个抽象方法。子类必须实现,
* 该方法返回一个IBinder对象。应用程序可通过该对象与Service通信
*/
public IBinder onBind(Intent intent) {
return null;
} /**
* 在Service第一次被创建后将马上回调该方法
*/
@Override
public void onCreate() {
super.onCreate();
Log.i("TAG","Service is Created");
} /**
* 每次client调用startService(Intent)方法启动该Service时都会回调该方法
* @return
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("TAG","Service is Started");
return super.onStartCommand(intent, flags, startId);
} /**
* 在该Service被关闭之前将会回调该方法
*/
@Override
public void onDestroy() {
Log.i("TAG","Service is Destroyed!");
super.onDestroy();
}
}

这个Service类重写了Service组件的onCreate()、onStartCommand()、onDestroy()、onBind()方法,重写这些方法时仅仅是简单地输出了一条字符串,除此之外什么也没干。

当然,为了启动这个服务我们还是要在Activity中写明的:

package com.bigmoney.www.servicetest;

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button; public class MainActivity extends AppCompatActivity implements View.OnClickListener { private Button serviceStart;
private Button serviceStop; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
serviceStart = (Button) findViewById(R.id.button1);
serviceStop = (Button) findViewById(R.id.button2);
serviceStart.setOnClickListener(this);
serviceStop.setOnClickListener(this); } @Override
public void onClick(View v) {
Intent intent = new Intent(this,FirstService.class);
switch (v.getId()){
case R.id.button1:
startService(intent) ;//用意图启动服务
case R.id.button2:
stopService(intent); //用意图停止服务
default:
break;
}
}
}

由activity中的代码可知。点击第一个button后,后台将打印出例如以下log:

再点击第二个button后。后台会有例如以下log:

本程序中启动Service的方法属于“通过Context的startService()方法”,通过此方法启动Service,訪问者与Service之间没有关联。即使訪问者退出了,Service也仍然执行。

(有人可能注意到了这里使用了显式Intent(直接指定要启动的目标组件的实现类)来启动Service,而并没有使用隐式。并非我偷懒。而是从Android5.0開始,Google要求必须使用显式Intent启动Service组件)。

Service也是context中的一份子,能够把Service看成是一个长期执行在后台的,没有界面的Activity。

是的。或许你看到这里会想服务难道还有第二种启动方式?是的,在讲第二种启动方式之前,我们先来明白下为什么须要使用服务:

普通情况下,假设我们想让某一块逻辑长期执行在后台,那么能够把它放到服务里面去执行。这也决定了服务的用途:①长期在后台监听设备接入;②在后台轮巡server获取数据(股票类软件等须要频繁刷新操作);③在后台播放音乐(音乐播放器)……等等。

二、Service的两种执行方式:

①通过Context的startService()方法:通过该方法启动Service。訪问者与Service之间没有关联。即使訪问者退出了。Service也仍然执行。

②通过Context的BindService()方法:使用该方法启动Service,訪问者与Service绑定在一起。訪问者一旦退出,Service也就终止了。

用第①种方式启动的代码上面已经给出,启动、关闭Service十分简单,调用Context里定义的startService()、stopService()方法就可以启动、关闭Service。

假设在不关闭Service的情况下。连续三次单击“开启Service”。程序将连续三次启动Service,能够看到logcat中连续三次打印出“Service
is Started”的log信息。能够由此看出。每当Service被创建时会回调onCreate()方法。每次Service被启动时会回调onStartCommand()方法——多次启动一个已有的Service组件将不会再回调onCreate()方法。但每次启动时都会回调onStartCommand()方法。

当程序通过startService()和stopService()启动、关闭Service时,Service与訪问者之间基本不存在太多的关联,因此Service和訪问者之间也无法进行通信、交换数据。

假设Service和訪问者之间须要进行方法调用或者交换数据,则应该使用bindService()或者unbindService()方法启动、关闭Service。这里就须要用到我们的第②中启动方式了,也叫“绑定Service”。

实例代码例如以下:

ServiceDemo类:

package com.bigmoney.www.sevvvvv;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;
import android.widget.Toast; /**
* Created by hasee on 2016/3/19.
* @param
*/
public class ServiceDemo extends Service { /**
* 这是服务内部的代理。用于当activity与服务绑定之后,返回给activity
*/
class MyBinder extends Binder {
/**
* 内部类就通过自己的方法去调用服务的方法,这个内部类方法实际上就是给外部訪问的
* 也就是给activity訪问的
* @param name
* @param money
*/
public void callMethodInService(String name, int money){
methodInService(name, money);
};
} private void methodInService(String name, int money) {
Toast.makeText(this,name+"有"+money+"钱",Toast.LENGTH_LONG).show();
} /**
* 当服务成功绑定之后。就返回这里的内部对象
* 所谓的“绑定”就是把activity和Service放到一个Map中去形成映射关系
* @param intent
* @return
*/
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
} @Override
public void onCreate() {
super.onCreate();
Log.i("vim","onCreate---");
} @Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("vim","onStartCommand---");
return super.onStartCommand(intent, flags, startId);
} @Override
public void onDestroy() {
super.onDestroy();
Log.i("vim", "onDestroy---");
}
}

MainActivity类:

package com.bigmoney.www.sevvvvv;

import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.view.View; public class MainActivity extends AppCompatActivity { ServiceDemo.MyBinder binder; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
} class Myconn implements ServiceConnection {
/**
* 当服务成功绑定上之后调用,里面有一个參数很重要就是第二个參数。
* 这个參数就是服务里面的onBind方法返回的内部对象
*/
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//这里的service实际上就是ServiceDemo类
binder = (ServiceDemo.MyBinder) service;
} @Override
public void onServiceDisconnected(ComponentName name) { }
} Myconn myconn = new Myconn(); //绑定服务
public void bind(View v) {
//启动服务---startService
//绑定服务---bindService
Intent intent = new Intent(this, ServiceDemo.class);
//參数二:用于接收当前服务的一些状态,是启动还是停止了
//參数三:服务不存在,就创建然后绑定,存在则直接绑定
bindService(intent, myconn, BIND_AUTO_CREATE);
} //调用服务中的方法
public void call(View v) {
//调用了Service里面的呼叫服务的方法
binder.callMethodInService("张三", 1000);
} //解除绑定
public void unbind(View v) {
Intent intent = new Intent(this, ServiceDemo.class);
unbindService(myconn);
}
}

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?

>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.bigmoney.www.sevvvvv.MainActivity"> <Button
android:onClick="bind"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="绑定服务" />
<Button
android:onClick="call"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="调用服务中的方法" />
<Button
android:onClick="unbind"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="解除绑定服务" />
</LinearLayout>

最后执行起来如图:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

当我们点击“绑定服务”后会打印例如以下log:

当我们点击“调用服务中的方法”时。会有例如以下效果:

当我们点击“解出绑定服务”时,

上面的代码示范了怎样在Activity中绑定本地Service,该程序的Service类须要“真正”实现onBind()方法。并让该方法返回一个有效的IBinder对象。

public IBinder onBind(Intent intent) {
return new MyBinder();
}

这段代码返回了一个可訪问该Service状态数据的IBinder对象,该对象将被传给该Service的訪问者。

Service中的内部类MyBinder通过继承Binder类实现了一个IBinder对象,这对于绑定本地Service并与之通信是一种常见场景。

对于Service的onBinder()方法所返回的IBinder对象来说。它可被当成该Service组件所返回的代理对象,Service同意client通过该IBinder对象来訪问Service内部的数据,这样就可以实现client与Service之间的通信。与多次调用startService()方法启动Service不同的是,多次调用bindService()方法并不会运行反复绑定。对于前一个实例程序。用户每单击“启动服务”button一次,系统就会回调Service的onStartCommand()方法一样。对于这个演示样例程序,无论用户单击“绑定服务”多少次,系统仅仅会回调用Service的onBind()方法一次。

这里,我们能够总结下绑定服务的步骤:

1、定义服务类、声明服务中的方法

public class ServiceDemo extends Service{...}

2、在AndroidManifest文件里注冊服务

3、定义一个内部类。继承Binder这样的类型

class MyBinder extends Binder{...}

4、在onBind方法里面返回内部类对象

public IBinder onBind(Intent intent) {

                return new MyBinder();

            }

5、在activity里面绑定服务

public void bind(View v){...}

6、在onServiceConnected方法里面获取到内部对象

class MyConn implements ServiceConnection{

public void onServiceConnected(ComponentName name, IBinder service) {// IBinder service =  new MyBinder();

    binder = (MyBinder) service;

}

7、依据内部对象调用内部类中的方法。由它去调用服务中的方法

public void call(View v){

            binder.callMethodInService("张三",
10000);

        }

三、服务的两种生命周期

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

在官方文档中,服务的生命周期如上:

常规的service总体的生命周期是从onCreate()被调用開始,到onDestroy()方法返回为止。

  和activity一样,service在onCreate()中进行它的初始化工作。在onDestroy()中释放残留的资源。

  比方。一个音乐播放service能够在onCreate()中创建播放音乐的线程,在onDestory()中停止这个线程。

 onCreate() 和 onDestroy()会被全部的service调用,不论service是通过startService()还是bindService()建立。

绑定service积极活动的生命周期是从onStartCommand() 或onBind()被调用開始,它们各自处理由startService()或 bindService()方法传过来的Intent对象。

  假设service是被开启的。那么它的活动生命周期和整个生命周期一同结束。

  假设service是被绑定的,它们它的活动生命周期是在onUnbind()方法返回后结束。

  注意:虽然一个被开启的service是通过调用 stopSelf() 或 stopService()来停止的,没有一个相应的回调函数与之相应,即没有onStop()回调方法。

所以。当调用了停止的方法,除非这个service和客户组件绑定。否则系统将会直接销毁它。onDestory()方法会被调用,而且是这个时候唯一会被调用的回调方法。

四、两种服务的差别

① 生命周期不同



> startService : onCreate -- onStartCommand -- onDestroy



> bindService  : onCreate - onBind -- onUnBind -- onDestroy 



② 与服务通讯方式不同



> startService : 通过intent传递code来区分。(无法与服务进行通讯)



> bindService : 通过内部代理对象操作服务中的方法



③ 与开启者的关系不同



> startService :即使开启者(activity)已经被销毁了, 服务依旧执行着



> bindService : 当开启销毁的时候,服务也跟着销毁。

④ 在设置应用显示不同



> startService: 在设置应用里面有显示当前正在执行的服务



> bindService : 在设置应用里面没有显示。

五、混合绑定服务

假设使用startService启动服务,是能够让服务在后台一直执行,可是没有办法与服务进行通讯。 假设是用的是bindService启动服务。能够与服务进行通讯,可是没有办法让服务一直在后台执行。能不能让服务长期执行在后台,而且还能与服务进行通讯?答案是能够的。

详细操作过程例如以下:

1. 启动服务

2. 绑定服务

3. 调用服务方法

4. 解除绑定

5. 停止服务

以上两个服务类代码都是模板代码。直接套用就可以,这里不做赘述。

注意: 每次与服务进行通讯完成,都记得解除绑定服务。否则服务有可能在退出界面的时候停止。

另一种远程服务,我将在下片博文里为大家具体介绍。

Android基础(五) Service全解析----看不见的Activity的更多相关文章

  1. android基础---->JSON数据的解析

    上篇博客,我们谈到了XML两种常用的解析技术,详细可以参见我的博客(android基础---->XMl数据的解析).网络传输另外一种数据格式JSON就是我们今天要讲的,它是比XML体积更小的数据 ...

  2. android基础---->XMl数据的解析

    在网络上传输数据时最常用的格式有两种,XML和JSON,下面首先学一下如何解析XML格式的数据,JSON的解析可以参见我的博客(android基础---->JSON数据的解析).解析XML 格式 ...

  3. Android fragment源码全解析

    Fragment 相信基本上每个android developer都用过,但是知晓其原理 用的好的还是不多,今天就从源码的角度上来带着大家分析一下Fragment的源码,对fragment有了更深层次 ...

  4. <Android基础> (五) 广播机制

    1)接收系统广播:a.动态注册监听网络变化 b.静态注册实现开机启动 2)发送自定义广播:a.发送标准广播 b.发送有序广播 3)使用本地广播 第五章 5.1 广播机制 Android中的每个程序都可 ...

  5. Android 开发中Service完全解析

    定义:服务,是Android四大组件之一,属于计算型组件 作用:提供 需在后台长期运行的服务 生命周期:          在Service的生命周期里,常用的有: (1) 4个手动调用的方法 手动调 ...

  6. Android服务类Service具体解析

    Service有什么作用? 很多人不明确service是用来干嘛的.事实上Service作为Android四大组件之中的一个,能够理解为一个执行在后台的Activity.它适用于处理一些不干扰用户的长 ...

  7. 【嵌入式】Arduino编程基础到应用全解析

    Arduino Author: Andrew.Du 基础 基础语法: setup() loop() pinMode(引脚,模式) pinMode(13,OUTPUT):设置13号引脚为输出 //在使用 ...

  8. Android图片加载框架最全解析(五),Glide强大的图片变换功能

    大家好,又到了学习Glide的时间了.前段时间由于项目开发紧张,再加上后来又生病了,所以停更了一个月,不过现在终于又可以恢复正常更新了.今天是这个系列的第五篇文章,在前面四篇文章的当中,我们已经学习了 ...

  9. Android图片加载框架最全解析(四),玩转Glide的回调与监听

    大家好,今天我们继续学习Glide. 在上一篇文章当中,我带着大家一起深入探究了Glide的缓存机制,我们不光掌握了Glide缓存的使用方法,还通过源码分析对缓存的工作原理进行了了解.虽说上篇文章和本 ...

随机推荐

  1. Android Studio 怎样打JAR包

    Android Studio 怎样打JAR包 在eclipse中我们知道怎样将一个项目导出为jar包,供其他项目使用. 在AS中能够通过改动gradle才处理. 我们新建一个项目MakeJar,在项目 ...

  2. utf-8与utf-8(无BOM)的区别

    BOM——Byte Order Mark,就是字节序标记   在UCS 编码中有一个叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的编码是FEFF.而FFFE ...

  3. SpringBoot配置多数据源

    原文:https://www.jianshu.com/p/033e0ebeb617 项目中用到了两个数据库,分别是Oracle和Mysql,涉及到了多数据源问题,这里做下记录 官方讲解:https:/ ...

  4. iPhone开发过程中调试多次Release问题 message sent to deallocated

    初级:第一步   为程序添加符号断点 malloc_error_break  方法如下. 目标效果:让程序崩溃时跳转到出错到那一行.但是往往达不到这个效果.不行就继续往下看. At times, wh ...

  5. C#编程(十二)----------函数

    类和结构 类和结构实际上都是创建对象的模板 ,每 个对象都包含数据 ,并 提供了处理和访问数据的方法. 类定义了类的每个对象 (称 为实例 )可 以包含什么数据和功能 . 例如 ,如 果 一 个类表示 ...

  6. 三层架构下实现用户登陆C#

    上篇文章讲到三层.接下来就通过一个实例详细的看怎么用三层实现用户登陆界面. 一.Model实体(LoginModel): namespace LoginModel { //加入类:UserInfo M ...

  7. 动态规划经典问题Java实现

    动态规划问题Java实现 如果我们有面值为1元.3元和5元的硬币若干枚,如何用最少的硬币凑够11元? public class DPProblem { public static void main( ...

  8. linux中解压rar文件

    linux平台默认是不支持RAR文件的解压,需要安装linux版本的RAR压缩软件,下载地址为:http://www.rarlab.com/download.htm 下载之后进行解压之后,进入rar目 ...

  9. 快速找到自己想要用到的cocos2d-x的缓冲动画

    游戏中在做很多动画时,需要用到缓冲来增强表现.比如宝箱"鼓"几下,然后"蹦"的一下打开.很多时候要调效果时,需要轮着试,如果有一张图和实际示例效果,那就省很多事 ...

  10. Easyui 页面设置加载完成之后,满屏

    js文件: if(top.location!=self.location){ top.location.href=self.location; }