Service基础使用
Service基础使用
之前的文章一直介绍Activity的使用,很多知识和用法单一的配合Activity使用,这次将总结Android四大组件之二——Service.
本文将要介绍以下内容:
- Service是什么
- 两种Service启动
- Service 前台服务与Notification
- 后台定时服务
- IntentService
Service是什么
Service 是一个可以在后台执行长时间运行操作而不使用用户界面的应用组件。服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。 此外,组件可以绑定到服务,以与之进行交互,甚至是执行进程间通信 (IPC)。 例如,服务可以处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序交互,而所有这一切均可在后台进行。
上面说了这么多可以做的耗时操作,但不要真的认为Service默认会运行在子线程中,他也不运行在一个独立的进程中,他同样执行在UI线程中,因此,不要在Service中执行耗时操作,除非你在Service中创建了子线程来完成耗时操作。
Service不因程序切换到后台或者用户切换到另一个APP而停止,但如果应用程序被杀死,他当然就也消失了。
两种Service的启动
服务启动分为两种形式,一种是通过StartService()启动Service,另一种是通过BindService(),至于先启动在绑定这个我们最后再说。本文主要介绍的就是这两种,这两种有什么区别呢?我们先看一张他们的生命周期图片,然后在慢慢细说。

StartService()
当应用组件(如 Activity)通过调用 startService() 启动服务时,服务即处于“启动”状态。一旦启动,服务即可在后台无限期运行,即使启动服务的组件已被销毁也不受影响。 已启动的服务通常是执行单一操作,而且不会将结果返回给调用方。例如,它可能通过网络下载或上传文件。 操作完成后,服务会自行停止运行。
通过上面的生命周期图也可以看出来首次启动会创建一个Service的实例,然后依次调用onCreate()和onStartCommand(),此时Service进入运行状态,即使你多次调用StartService()启动Service,也不会创建新的Service对象,而是直接复用前面创建的Service对象,调用它的startCommand()方法。下面介绍一下startService各个回调方法,我们该做什么
onCreate():首次创建服务,系统将调用此方法来执行一次性设置程序,如果服务已经运行,则不会调用此方法
onStartCommand():启动服务的时候,系统将会调用此方法。如果实现了此方法,则在服务工作完成后,需要主动调用stopSelf()或者stopService()来停止服务。
onDestroy(),当服务不再使用且将被销毁时,系统将会调用此方法,服务应该实现此方法来清理所有资源。这是服务接受的最后一个调用。
下面我将通过一个实例展示这个service的实现,以及方法调用的顺序。注意,通过AS新建一个Service则不需要配置mainfest文件,否则需要加入service声明,大概如下面这样。且注意始终通过显示Intent启动或者绑定Service,不要为他设置intent-filter
 <application ... >
      <service android:name=".ExampleService" />
  </application>
Service代码如下:
public class TestService extends Service {
    public TestService() {
    }
	@Override
    public void onCreate() {
        super.onCreate();
        //处理一次性设置
        Log.i("TestService","onCreate被调用");
    }
    //必须要有这个方法
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }
    @Override
    public void onDestroy() {
        Log.i("TestService","onDestroy被调用");
        super.onDestroy();
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        //处理Service逻辑
        Log.i("TestService","onStartCommand被调用");
        return super.onStartCommand(intent, flags, startId);
    }
}
Activity中布局文件放置了一个启动按钮,一个停止按钮,在onCreate()方法,实现startService,代码如下:
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        stop = (Button)findViewById(R.id.stop);
        start = (Button) findViewById(R.id.start);
        final Intent intent = new Intent(this, TestService.class);
        start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startService(intent);
            }
        });
        stop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                stopService(intent);
            }
        });
    }
调用的结果如下:
点击启动service按钮后
I/TestService: onCreate被调用
I/TestService: onStartCommand被调用
点击停止service按钮后
I/TestService: onDestroy被调用
bindService()
当应用组件通过调用 bindService() 绑定到服务时,服务即处于“绑定”状态。绑定服务提供了一个客户端-服务器接口,允许组件与服务进行交互、发送请求、获取结果,甚至是利用进程间通信 (IPC) 跨进程执行这些操作。 仅当与另一个应用组件绑定时,绑定服务才会运行。 多个组件可以同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。
和startService()一样,首次使用bindService时绑定一个Service时,系统会实例化一个Service实例,并调用onCreate()和onBind()方法,此后如果再次使用bindService绑定Service,系统不会创建新的Service实例,也不会再调用onBInd()方法,只是会直接把IBinder对象传递给其他后来增加的客户端。 如果我们解除与服务的绑定,只需调用unbindService(),此时onUnbind和onDestory方法将会被调用!这是一个客户端的情况,假如是多个客户端绑定同一个Service的话,情况如下 当一个客户完成和service之间的互动后,它调用 unbindService() 方法来解除绑定。当所有的客户端都和service解除绑定后,系统会销毁service。(除非service也被startService()方法开启)。但一旦调用者销毁,Service也立即终止。下面主要说一下onBInd这个回调方法。
第一种启动方式并没有直接提供Service与Activity的交互方式。第二种启动方式即用bindService提供了Service与Activity交互方式,可以很方便的利用Ibinder实现Service与Activity的通信。关键在onBind方法
onBind()方法返回值是一个IBinder 对象,这个方法必须实现,通过startService返回为null,表示不调用,bindService则返回一个扩展Binder类的对象。
步骤如下:
- 定义一个继承Binder类的类,在类里面编写想要Activity调用的方法.
- 生成一个该类的对象,放到onBInd()方法中返回。
 代码例子如下:
public class TestService2 extends Service {
    public TestService2() {
    }
    public Mybinder mybinder = new Mybinder();
    public int getInfo() {
        return 123;
    }
    public class Mybinder extends Binder {
        public TestService2 getService() {
            return TestService2.this;
        }
    }
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        Log.i("TS","onbind被调用");
        return mybinder;
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i("TS","onDestory被调用");
    }
    @Override
    public void onRebind(Intent intent) {
        super.onRebind(intent);
        Log.i("TS","onRebind被调用");
    }
}
这个例子Mybinder对象中getService方法,得到这个Service对象,从而调用Service中所有方法。
在Activity中的代码,要实现ServiceConnection类中的onServiceDisconnected和onServiceConnected方法,并且通过bindService来绑定服务,unbindService来解绑服务。
主要代码如下:
 TestService2.Mybinder binder;
    private ServiceConnection conn = new ServiceConnection() {
        //Activity与Service断开连接时回调该方法
        @Override
        public void onServiceDisconnected(ComponentName name) {
            System.out.println("------Service DisConnected-------");
        }
        //Activity与Service连接成功时回调该方法
        @Override
	        public void onServiceConnected(ComponentName name, IBinder service) {
	        //将Service强制转换类型为Binder,这种用法在回调中很常见。
            System.out.println("------Service Connected-------");
            binder = (TestService2.Mybinder) service;
        }
    };
   ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
	    ...
	     start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                bindService(intent, conn, Service.BIND_AUTO_CREATE);
            }
        });
        stop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                unbindService(conn);
            }
        });
		//通过binder对象就可以对我们绑定的Service进行各种操作
        status.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this,binder.getService().getInfo() + "",Toast.LENGTH_SHORT).show();
            }
        });
    }
至于调用顺序,还是和流程图一样,就不一一详说了。这里已经说明了2种启动Service的方式和区别。下面将介绍一个很流行的Service应用,前台服务。
Service 前台服务与Notification
我们在用很多应用的时候,发现他们启动的时候,会在通知栏生成一个和该App的通知,来继续执行Service,比如墨迹天气,很多音乐App.这种叫前台服务,其实这种Service有一个很好的一点,就是不会因为Service自身的优先级低,而被系统KILL,而前台服务就不会。
前台服务的写法很容易,只需要在onCreate()中,建立一个通知,然后用startForeground()设置为前台服务即可。
下面直接放出代码,结合代码注释看看就好了,关于通知更多的内容可以看看Notification详解
这里只列出Service的onCreate()部分代码
@Override
    public void onCreate() {
        super.onCreate();
        //设定一个PendingIntent,来表示点击通知栏时跳转到哪里
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), 0);
        Notification.Builder builder = new Notification.Builder(this);
        //建立一个notificationManager来管理通知的出现
        notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        //构造通知的样式,包括图片,标题,内容,时间。
        builder.setSmallIcon(R.mipmap.ic_launcher).
                setWhen(System.currentTimeMillis()).
                setContentTitle("我是标题").
                setContentText("我是内容").
                setTicker("在启动时弹出一个消息").//这个Android5.0以上可能会失效
                setWhen(System.currentTimeMillis()).
                setContentIntent(contentIntent);
                //最后通过build建立好通知
        Notification notification = builder.build();
        //通过manager来显示通知,这个1为notification的id
        notificationManager.notify(1,notification);
        //启动为前台服务,这个1为notification的id
        startForeground(1,notification);
    }
后台定时服务
后台定时服务其实并不是特殊的Service,只是Service的常见的一种应用,放到后台做定时更新,轮询等。这次的Service要配合Alarm以及简单的广播机制来实现。
步骤主要如下:
第一步  获得Service AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);
第二步  通过set方法设置定时任务
int time = 1000;
        long triggerAtTime = SystemClock.elapsedRealtime() + time;
        Intent i = new Intent(this,AlarmReceiver.class);
        PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, 0);
        manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);
第三步 定义一个Service,在onStartCommand中开辟一个事务线程,用于处理一些定时逻辑
@Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        new Thread(new Runnable() {
            @Override
            public void run() {
               //执行想做的操作,比如输出时间
            }
        }).start();
	      //步骤二里面的代码
        return super.onStartCommand(intent, flags, startId);
    }
第四步 定义一个Broadcast,用于启动Service。
public class AlarmReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Intent i = new Intent(context,LongRunningService.class);
        context.startService(i);
    }
}
这样我们就能执行后台定时服务
IntentService
这是
Service的子类,它使用工作线程逐一处理所有启动请求。如果您不要求服务同时处理多个请求,这是最好的选择。 您只需实现onHandleIntent()方法即可,该方法会接收每个启动请求的 Intent,使您能够执行后台工作。
由于大多数启动服务都不必须同时处理多个请求,因此使用IntentService类实现服务也许是最好的选择。
IntentService执行以下操作:
- 创建默认的工作线程,用于在应用的主线程外执行传递给onStartCommand()的所有Intent
- 创建工作队列,用于讲一个Intent逐一传递给onHandleIntent()实现,不要担心多线程问题
- 在处理完所有启动后停止服务,永远不用调用stopSelf()
- 提供onBind()的默认实现
- 提供onstartCommand()的默认实现,可将Intent依次发送给工作队列和onHandleIntent()
 下面给一个IntentService的例子
public class MyIntentService extends IntentService {
    private final String TAG = MyIntentService.class.getName();
    public MyIntentService() {
	      //此构造函数一定要实现  super(MyIntentService.class.getName());
    }
    @Override
    protected void onHandleIntent(Intent intent) {
        String action = intent.getExtras().getString("param");
        if("s1".equals(action)) Log.i(TAG, "启动s1");
        if("s2".equals(action)) Log.i(TAG, "启动s2");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    @Override
    public void onCreate() {
        Log.i(TAG,"onCreate");
        super.onCreate();
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG,"onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }
    @Override
    public void setIntentRedelivery(boolean enabled) {
        super.setIntentRedelivery(enabled);
        Log.i(TAG,"setIntentRedelivery");
    }
    @Override
    public void onDestroy() {
        Log.i(TAG,"onDestroy");
        super.onDestroy();
    }
}
在Activity中的onCreate()方法中加入如下代码
 Intent it1 = new Intent(this,MyIntentService.class);
        Bundle b1 = new Bundle();
        b1.putString("param", "s1");
        it1.putExtras(b1);
        Intent it2 = new Intent(this,MyIntentService.class);
        Bundle b2 = new Bundle();
        b2.putString("param", "s2");
        it2.putExtras(b2);
        startService(it1);
        startService(it2);
运行结果如下
I/com.shiqifeng.servicetest.MyIntentService: onCreate
I/com.shiqifeng.servicetest.MyIntentService: onStartCommand
I/com.shiqifeng.servicetest.MyIntentService: 启动s1
I/com.shiqifeng.servicetest.MyIntentService: onStartCommand
I/com.shiqifeng.servicetest.MyIntentService: 启动s2
I/com.shiqifeng.servicetest.MyIntentService: onDestroy
至此Service的基本使用全部结束
Service基础使用的更多相关文章
- REST Service 基础 A further step.
		1. REST Service虽然实现简单, 但也功能丰富, 可以用来实现各种基于Web的服务(service). 2. REST Service的一些特点: 1)平台无关 2) 语言无关 3)基于H ... 
- Android Service基础
		Service Service 是一个组件,用来执行长时间的后台操作,不提供用户界面. 另一个应用组件可以启动一个Service,它将持续地在后台运行,即便是用户转移到另一个应用它也不会停止. 另外, ... 
- C# Windows Service 基础
		Windows Service这一块并不复杂,但是注意事项太多了,网上资料也很凌乱,偶尔自己写也会丢三落四的.所以本文也就产生了,本文不会写复杂的东西,完全以基础应用的需求来写,所以不会对Window ... 
- Web Service基础——规范及三要素
		1. Java中的Web Service规范 Java 中共有三种WebService 规范,分别是JAX-WS(JAX-RPC).JAX-RS.JAXM&SAAJ(废弃). 1.1 JAX- ... 
- Web Service基础——基础概念
		1. Web Service基本概念 Web Service(Web服务)是一种远程调用技术,他的作用就是从远程系统中获取业务数据.具体来说,Web Service可以让你的网站使用其他网站的资源,比 ... 
- Android笔记之 Web Service 基础
		一.Web Service是什么? 就是网络服务.依据W3C的定义,WebServices(Web服务)是一个用于支持网络间不同机器互操作的软件系统,它是一种自包括.自描写叙述和模块化的应用程序,它能 ... 
- Web service基础
		Web service是Web应用程序 平台是XML+http XML是不同平台和不同编程语言之间的语言,用于编解码数据. http是因特网协议 XML是web service的基础 Web serv ... 
- Android Service 基础
		启动方式 startService(Intent) 这种方式启动的Service可以在后台无限期的运行,与启动它的组件没有关系. bindService 绑定Service.它提供了一种类似C/S结构 ... 
- web service基础知识
		Web服务基础 用户访问网站的基本流程 我们每天都会用web客户端上网,浏览器就是一个web客户端,例如谷歌浏览器,以及火狐浏览器等. 当我们输入www.oldboyedu.com/时候,很快就能看到 ... 
随机推荐
- for in 结构
			in 运算符也是一个二元运算符,但是对运算符左右两个操作数的要求比较严格.in 运算符要求第 1 个(左边的)操作数必须是字符串类型或可以转换为字符串类型的其他类型,而第 2 个(右边的)操作数必须是 ... 
- 字典树+博弈 CF 455B A Lot of Games(接龙游戏)
			题目链接 题意: A和B轮流在建造一个字,每次添加一个字符,要求是给定的n个串的某一个的前缀,不能添加字符的人输掉游戏,输掉的人先手下一轮的游戏.问A先手,经过k轮游戏,最后胜利的人是谁. 思路: 很 ... 
- php备份数据库
			php备份数据库原理和方法 原理 查找所有表 查找所有字段,列出所有字段名 字段类型等信息 查找所有数据 读取后注意特殊符号转换addslashes() 生成sql 把数据库格式化生成对应sql 相关 ... 
- 基于孪生卷积网络(Siamese CNN)和短时约束度量联合学习的tracklet association方法
			基于孪生卷积网络(Siamese CNN)和短时约束度量联合学习的tracklet association方法 Siamese CNN Temporally Constrained Metrics T ... 
- C++常用特性原理解析
			在我的早期印象中,C++这门语言是软件工程发展过程中,出于对面向对象语言级支持不可或缺的情况下,一群曾经信誓旦旦想要用C统治宇宙的极客们妥协出来的一个高性能怪咖. 它驳杂万分,但引人入胜,出于多(mi ... 
- python基础之初始python
			初始python之基础一 一.Python 介绍 1.python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹打发时间,决心开发 ... 
- windows下python的tar.gz文件安装
			windows下下载了django,PIL,web.py发现都是tar.gz格式的文件,网上查找也非常系统的方法,总结一下其他大神的方法,归纳于此. 首先下载tar.gz文件,比如web.py,下载后 ... 
- java爬虫:在请求body中增加json数据采集
			1,http://www.hqepay.com/public/expressquery.html 查询快递不是将键值对post过去,而是将json数据放到body中发送过去.抓包如下: 2,需要导入一 ... 
- PHP:Xdebug配置
			在配置Xdebug时,之前经历了无数次失败,终于配置成功! 以下是配置失败的原因: 1.下载时,选用Xdebug的版本不正确: 2.配置时,Xdebug文件名或文件的路径不正确: 在参考 http:/ ... 
- MAC apache配置
			启动 apache:在terminal中输入命令,sudo apachectl start 启动成功后访问lcoalhost会显示“It works”. 更改默认路径:命令行输入“sudo vim / ... 
