Android 四大组件之Service(上)

1.Service简介

  Service是Android四大组件中最与Activity相似的组件,他们都代表可执行的程序。Service一直运行于后台,不会与用户交互,可用来处理一些耗时的任务(比如:后台播放音乐,I/O操作等)。它的创建、配置与Activity基本相似,下面将详细介绍Android Service的开发。

2.创建、配置Service

  2.1 定义一个继承Service类的子类

  2.2 在AndroidManifest.xml中配置该Service

  需要注意的是 Service和Activity都是从Context类派生出来的(建议可以了解下Context这个类,了解之后,学习后面的一些组件、类也是很轻松的),因此它们都可以调用Context中getResources()、getContentResolver()等方法;

  Service中定义的系列生命周期的方法:

    IBinder onBind(Intent intent):该方法是Service必须实现的一个方法,该方法返回一个IBinder对象,应用程序可以通过该对象与Service组件通讯

    void onCreate():当Service第一次被创建后,系统将立即回调该方法

    void onDestory():当Service被关闭之前会回调该方法

    void onStartCommand(Intent intent,int flags,int startId):该方法的早期版本(pre-2.0)是onStart(Intent intent,int startId)【onStartCommand(intent,flags,startId)里面已经调用了onStart()方法】,每次客户端调用startService(Intent intent)启动Service都会回调该方法。下面是Service类中该方法的源码:

1 @Override
2     public int onStartCommand(Intent intent, int flags, int startId) {
3         onStart(intent, startId);
4         return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
5     }

    boolean onUnbind(Intent intent):当该Service上绑定的客户端都断开链接时,会回调该方法

    下面的类定义了一个Service组件:

 1 package com.example.administrator.servicedemo;
 2
 3 import android.app.Service;
 4 import android.content.Intent;
 5 import android.os.IBinder;
 6
 7 /**
 8  * Created by Administrator on 2015/2/23.
 9  */
10 public class ServiceTest  extends Service{
11     //Service必须实现的方法
12     @Override
13     public IBinder onBind(Intent intent) {
14         return null;
15     }
16     //Service第一次被创建的时回调该方法
17     @Override
18     public void onCreate() {
19         super.onCreate();
20     }
21     //Service被启动时回调该方法
22     @Override
23     public int onStartCommand(Intent intent, int flags, int startId) {
24         return super.onStartCommand(intent, flags, startId);
25     }
26     //Service被关闭之前回调该方法
27     @Override
28     public void onDestroy() {
29         super.onDestroy();
30     }
31
32 }

    定义了Service之后,接下来需要在AndroidManifest.xml中配置该Service,配置Service使用<Service .../>元素

    

1 <service android:name=".ServiceTest" >
2             <intent-filter>
3                 <!-- 为Service组件的intent-filter配置action -->
4                 <action android:name="com.example.administrator.servicedemo.SERVICE_TEST"></action>
5             </intent-filter>
6         </service>

3.启动和停止Service

  Android系统启动Service有两种方式:

    > 通过Context的startService(Intent intent)方法:这种方法启动的Service,访问者和Service之间没有关联,即使访问者退出了,该Service仍然运行。(停止Service:stopService(Intent intent))

    > 通过Context的bindService(Intent intent)方法:这种方法启动的Service,访问者和Service绑定在了一起,一旦访问者退出,该Service也会停止。(取消绑定Service:unBind(Intent intent))

4.绑定本地Service并与之通讯

  当程序通过startService()和stopService()启动和停止Service时,访问者和Service之间基本没有什么联系,因此它们之间也就无法进行通讯、数据交换。

  如果访问者和Service之间需要进行方法调用或数据交换,那么这时应该使用bindService()和unbindService()进行启动和关闭Service。

  Context 的bindService()方法的完整方法签名为:bindService(Intent intent,ServiceConnection conn,int flags),该方法的三个参数解释如下:

    Intent:该参数通过Intent启动指定的Service

    conn:该参数是一个ServiceConnection对象,该对象用于监听访问者和Service之间的链接情况。当访问者与Service之间链接成功时,将回调该对象的onServiceConnected(ComponentName name,IBinder service)方法,当Service所在的宿主线程因异常终止,或其它异常终止导致访问者与Service之间断开链接时回调该对象的onServiceDisconnected(ComponentName name)方法

    注意:当访问者主动通过unBindService()方法断开与Service的链接时ServiceConnection的onServiceDisconnected(ComponnentName name)并不会被调用。

    flags:指定绑定时是否自动创建Service,该参数可指定为0(不创建)或BIND_AUTO_CREATE(自动创建)

    该ServiceConnection的onServiceConnected方法中有一个IBinder对象,该对象可以实现与被绑定Service之间的通讯,下面程序示范如何在本地绑定Service,并和Service进行通讯

    MainActivity类主要用于启动、关闭Service和显示BindService类中的count

 1 package com.example.administrator.servicedemo;
 2
 3 import android.content.ComponentName;
 4 import android.content.Intent;
 5 import android.content.ServiceConnection;
 6 import android.os.IBinder;
 7 import android.support.v7.app.ActionBarActivity;
 8 import android.os.Bundle;
 9 import android.util.Log;
10 import android.view.View;
11 import android.widget.Toast;
12
13
14 public class MainActivity extends ActionBarActivity {
15     private static final String SERVICE_BINDER = "com.example.administrator.servicedemo.SERVICE_BINDER";
16     public static final String TAG = "MainActivity";
17     private BindService.MyBind myBind;//声明BindService类中内部类MyBind
18     @Override
19     protected void onCreate(Bundle savedInstanceState) {
20         super.onCreate(savedInstanceState);
21         setContentView(R.layout.activity_main);
22     }
23
24     //访问者与Service通信的桥梁
25     private ServiceConnection conn = new ServiceConnection() {
26         //连接成功
27         @Override
28         public void onServiceConnected(ComponentName name, IBinder service) {
29             Log.i(TAG,"connection is succeed");
30             myBind = (BindService.MyBind)service;
31         }
32         //因异常而断开链接
33         @Override
34         public void onServiceDisconnected(ComponentName name) {
35             Log.i(TAG,"connection is failed");
36         }
37     };
38     //启动service
39     public void startService(View view){
40         Intent intent = new Intent();
41         intent.setAction(SERVICE_BINDER);
42         bindService(intent,conn,BIND_AUTO_CREATE);
43     }
44     //解除绑定
45     public void stopService(View view){
46         Intent intent = new Intent();
47         intent.setAction(SERVICE_BINDER);
48         unbindService(conn);
49     }
50     //实时显示count
51     public void showCount(View view){
52         Toast.makeText(MainActivity.this,"从BindService获取到的count:"+myBind.getCount(),Toast.LENGTH_SHORT).show();
53     }
54
55 }

    BindService类中启动一个新线程对count自增  

 1 package com.example.administrator.servicedemo;
 2
 3 import android.app.Service;
 4 import android.content.Intent;
 5 import android.os.Binder;
 6 import android.os.IBinder;
 7
 8 /**
 9  * Created by Administrator on 2015/2/23.
10  */
11 public class BindService extends Service {
12     private int count;
13     private boolean quit;
14     //自定义一个Binder
15     class MyBind extends Binder{
16         public int getCount(){
17             return count;//实时获取count的值
18         }
19     }
20     @Override
21     public IBinder onBind(Intent intent) {
22         return new MyBind();//返回给访问者的Binder
23     }
24
25     @Override
26     public void onCreate() {
27         new Thread(new Runnable() {
28             @Override
29             public void run() {
30                 while (!quit){
31                     try {
32                         Thread.sleep(2000);
33                     } catch (InterruptedException e) {
34                         e.printStackTrace();
35                     }
36                     count++;
37                 }
38             }
39         }).start();
40     }
41
42     @Override
43     public void onDestroy() {
44         super.onDestroy();
45         this.quit = true;
46     }
47 }

    layout布局文件中添加了启动、关闭、显示的按钮

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
 3     android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
 4     android:paddingRight="@dimen/activity_horizontal_margin"
 5     android:paddingTop="@dimen/activity_vertical_margin"
 6     android:orientation="vertical"
 7     android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
 8
 9     <Button
10         android:layout_width="wrap_content"
11         android:layout_height="wrap_content"
12         android:text="start service"
13         android:onClick="startService"/>
14     <Button
15         android:layout_width="wrap_content"
16         android:layout_height="wrap_content"
17         android:text="stop service"
18         android:onClick="stopService"/>
19
20     <Button
21         android:layout_width="wrap_content"
22         android:layout_height="wrap_content"
23         android:text="show count"
24         android:onClick="showCount"/>
25 </LinearLayout>

    程序运行后的结果:

      

    点击 start service 后将启动BindService,可通过BindService的MyBind内部类的getCount()方法获取当前count的值

    点击show count

         

    

    对于Service中onBind()方法所返回的Ibinder对象来说,他可被当成该Service组件所返回的代理对象,Service允许客户端通过IBinder来访问Service内部数据,这样可以实现客户端与Service之间的通信。

    当程序调用unBindService()方法解除对Service的绑定时,系统先回调onUnbind()方法,然后在回调onDestroy()方法.

    与多次调用startService()方法启动Service不同的是,多次调用bindService()方法并不会执行重复绑定。而前一个程序,只要用户点击启动Service,系统就会回调onStartCommand()方法一次.对于这个示例,不管用户点击多少次绑定Service,系统都只会回调一次onBind()方法。

5. Service的声明周期:

  下图分别是startService()、bindService()两种方式启动Service的生命周期

  

   这里还有一种特殊的情况:

    如果Service已由某个客户端通过startService()启动了,接下来其它客户端再调用bindService()方法绑定到Service上,再调用unbindService()解除绑定,最后有调用bindService()方法再次绑定到这个Service,这个过程所出发的生命周期如下:

    onCreate()-->onStartCommand()-->onBind()-->onUnbind()[重写该方法时返回true]-->onRebind()

    要想onRebind()方法被回调,除了已startService()方法启动Service之外,还要在重写Service的onUnbind()方法时返回true.

    从上面可以看到整个过程中并没有调用onDestroy()方法,这是因为该Service是以startService()方式启动的而不是以bindService()方法启动,因此当Activity调用unBindService()方法取消与Service的绑定时,该Service也不会终止

    由此可见,当Activity通过bindService()绑定一个以启动的Service时,系统只是把该Service的IBinder对象传给Activity,并不会将Service的生命周期"绑定"到该Activity

,因此当Activity调用unBindService()方法取消与Service的绑定时,也只是切断该Activity与Service之间的关联,并不能停止Service组件。

6. 使用IntentService

  IntentService 类是Service类的子类,它比普通的Service类增加了额外的功能

  先看下Service本身存在的两个问题.

    1>Service不会专门启动一条单独的进程,Service与它所在应用位于同一个进程中

    2>Service不是专门一条新的线程,因此不能在Service中处理耗时的任务

  而IntentService可以解决上述两个不足:IntentService会使用队列来管理请求Intent,每当客户端通过Intent请求启动IntentService时,IntentService会将请求放入到队列,然后开启一条新的worker线程来处理intent.对于异步的startService()请求,IntentService会按次序依次处理队列中的Intent请求,该线程保证同一时刻只处理一个Intent。由于IntentService使用worker线程处理耗时请求,因此不会阻塞主线程。

  归纳起来,IntentService具有如下特征:

    1>IntentService会创建单独的worker线程来处理所有的Intent请求

    2>IntentService会创建单独的worker线程来处理onHandlerIntent()方法实现的代码,开发者无需处理多线程问题

    3>当所有请求处理完之后,IntentService会自动停止,因此开发者无需调用stopSelf()方法停止该Service

    4>为Service的onBind()方法提供了默认实现,默认是实现的onBind()方法返回null

    5>为Service的onStartCommand()方法提供了默认实现,该实现会将请求Intent添加到队列中

  因此,在重写IntentService类时只需重写onHandlerIntent()方法即可。

  下面写一个demo测试一下

  MainActivity类

 1 package com.example.administrator.intentservicetest;
 2
 3 import android.content.Intent;
 4 import android.support.v7.app.ActionBarActivity;
 5 import android.os.Bundle;
 6 import android.view.Menu;
 7 import android.view.MenuItem;
 8 import android.view.View;
 9 import android.widget.Toast;
10
11
12 public class MainActivity extends ActionBarActivity {
13
14     @Override
15     protected void onCreate(Bundle savedInstanceState) {
16         super.onCreate(savedInstanceState);
17         setContentView(R.layout.activity_main);
18     }
19
20     public void startService(View view){
21         Intent intent = new Intent(this,MyService.class);
22         Toast.makeText(this,"您点击了--启动service按钮",Toast.LENGTH_LONG).show();
23         startService(intent);
24     }
25
26     public void startIntentService(View view){
27         Intent intent = new Intent(this,MyIntentService.class);
28         Toast.makeText(this,"您点击了--启动intentService按钮",Toast.LENGTH_LONG).show();
29         startService(intent);
30     }
31
32 }

  MyService类

 1 package com.example.administrator.intentservicetest;
 2
 3 import android.app.Service;
 4 import android.content.Intent;
 5 import android.os.IBinder;
 6 import android.util.Log;
 7
 8 /**
 9  * Created by Administrator on 2015/2/15.
10  */
11 public class MyService extends Service {
12     @Override
13     public IBinder onBind(Intent intent) {
14         return null;
15     }
16
17     @Override
18     public void onCreate() {
19         super.onCreate();
20     }
21
22     @Override
23     public int onStartCommand(Intent intent, int flags, int startId) {
24         long currentTime = System.currentTimeMillis();
25         long endTime = currentTime + 20*1000;
26         //模拟一个耗时操作
27         while (currentTime < endTime){
28             synchronized (this){
29                 try {
30                     wait(endTime - currentTime);
31                 } catch (InterruptedException e) {
32                     e.printStackTrace();
33                 }
34             }
35         }
36         return super.onStartCommand(intent, flags, startId);
37     }
38 }

  MyIntentService类

 1 package com.example.administrator.intentservicetest;
 2
 3 import android.app.IntentService;
 4 import android.content.Intent;
 5 import android.util.Log;
 6
 7 /**
 8  * Created by Administrator on 2015/2/15.
 9  */
10 public class MyIntentService extends IntentService {
11     public MyIntentService(String name) {
12         super("MyIntentService");
13     }
14
15
16
17     @Override
18     protected void onHandleIntent(Intent intent) {
19         long currentTime = System.currentTimeMillis();
20         long endTime = currentTime + 20*1000;
21         //模拟一个耗时操作
22         while (currentTime < endTime){
23             synchronized (this){
24                 try {
25                     wait(endTime - currentTime);
26                 } catch (InterruptedException e) {
27                     e.printStackTrace();
28                 }
29             }
30         }
31     }
32 }

    运行应用程序后:               点击启动service,可以看到出现假死的状况       过会弹出                                          点击启动IntentService

                                                                  

  总结:可以看出当点击启动service按钮时,程序出现了假死状况,这是因为Service中进行了耗时操作,前面说到Service是运行在主线程中的,所以该耗时任务阻塞了主线程。点击启动intentService时,未出现阻塞状况,因为IntentService会启动一个worker线程进行处理耗时操作,并不是在主线程中处理。所以,一般遇到耗时情况时,首先想到的是IntentService,这个类已经帮我们做了很好的处理,无需自己在Service中创建一个线程去处理耗时任务。

    

时间: 2024-10-29 19:07:01

Android 四大组件之Service(上)的相关文章

Android 四大组件之Service详解

                   Android四大组件之Service详解    来这实习已经10多天了,今天整理整理学习时的Android笔记.正所谓好记性不如烂笔头,今天来说说service组件. service可以在和多场合的应用中使用,比如播放多媒体的时候用户启动了其他Activity这个时候程序要在后台继续播放,比如检测SD卡上文件的变化,再或者在后台记录你地理信息位置的改变等等,总之服务嘛,总是藏在后头的. Service是在一段不定的时间运行在后台,不和用户交互应用组件.每个

【Android的从零单排开发日记】之入门篇(五)——Android四大组件之Service

这几天忙着驾校考试,连电脑都碰不到了,今天总算告一段落了~~Service作为Android的服务组件,默默地在后台为整个程序服务,辅助应用与系统中的其他组件或系统服务进行沟通.它跟Activity的级别差不多,但不能自己运行只能后台运行.service可以在很多场合的应用中使用,比如播放多媒体的时候用户启动了其他Activity这个时候程序要在后台继续播放,比如检测SD卡上文件的变化,再或者在后台记录你地理信息位置的改变等等, 总之服务总是藏在后台的. ps:Service运行在主线程中的,所

Android 四大组件 (二) Service 使用

一. Service 介绍 Service属于android四大组件之一,在很多地方经常被用到.开启Service有两种不同的方式:startService和bindService.不同的开启方式,Service执行的生命周期方法也不同. 分 显示/隐示调用 ,但是官网推荐用显式的方式启动Service.下面 service使用 用的就是显示调用:注意事项用的就是隐示调用,在5.0系统上隐示调用会报错.所以这里只介绍使用显示调用. 不能再service里做耗时操作,否则ANR:需要开辟子线程进行

Android 四大组件之service与Broadcast

Android 四大组件之一:service: Service有五个生命周期:onCreat,onStartCommand, onBind,onUnbind, onDestroy 主要有绑定和非绑定两种方式 首相在Activity中设置四个Button,用于测试绑定和非绑定两种方式,按下Button播放音乐,停止音乐,非绑定用StopService停止,绑定方式用Bind Service启动,解绑用unbindService停止. 非绑定:Intent intent=new Intent(Mai

Android四大组件之一Service介绍-android学习之旅(十二)

基本概念: service是android四大组件之一,运行在后台执行耗时操作,并不提供用户界面.其他组件如acticity可以通过startService启动该组件,也可以通过bindService启动并把绑定该组件进行通信. 使用场景 后台下载文件,以及播放音乐等 注意 service运行在主线程中,他不会创建属于自己的线程,也不是运行在独立的线程中,所以在使用的时候,需要自己创建线程,而不应该直接使用,这样会造成ANR错误. service的两种形式 started service 其他组

Android成长日记-Android四大组件之Service组件的学习

1.什么是Service? Service是Android四大组件中与Activity最相似的组件,它们都代表可执行的程序,Service与Activity的区别在于:Service一直在后台运行,它没有用户界面,所以绝不会到前台来.一旦Service被启动起来,它就与Activity一样.它完全具有自己的生命周期. A Service is an application component that can perform long-running operations in the back

Android 四大组件之Service

---恢复内容开始--- 1,Service的生命周期 onCreate第一次创建service的时候调用. onStartCommand启动service的时候调用. onStart(This method was deprecated in API level 5. Implement onStartCommand(Intent, int, int) instead.) onDestroy销毁的时候调用. 2,进程优先级(由高到低):(红色字体的两个进程是经常被系统回收的两个进程)    1

Android四大组件之Service的介绍

Service的基本认识 Service是一个可以在后台执行长时间运行操作而不使用用户界面的应用组件.Service可由其他应用组件启动,而且即使用户切换到其他应用,Service仍将在后台继续运行.Service主要用于在后台处理一些耗时的逻辑,或者去执行某些需要长期运行的任务.必要的时候我们甚至可以在程序退出的情况下,让Service在后台继续保持运行状态. Service和Activity很相似,但是区别在于:Service一直在后台运行,没有用户界面,所以不会到前台,如果Service被

android四大组件之service生命周期

和activity一样,service服务同为android的四大组件之一.而和activity不同的是,service并不会显示出来,也就是没有用户界面,它是后台运行的,但需要activity或其它context来触发. 简单的一个例子是android手机里的音乐播放器,打开应用看得到的界面是activity,点击播放音乐启动的音乐服务则是service(听得到但看不到.例如舞台上的幕后服务者,为大家操作着音响和灯光,却从不亮相).而且就算退出了音乐播放器,却依然能够在桌面或其它应用里面听得到