转载

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组件:

Android 四大组件之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 }
View Code

定义了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

Android 四大组件之Service(上)
 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 }
View Code

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

Android 四大组件之Service(上)
 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 }
View Code

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

Android 四大组件之Service(上)
 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>
View Code

程序运行后的结果:

Android 四大组件之Service(上)

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

点击show count

Android 四大组件之Service(上)

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

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

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

5. Service的声明周期:

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

Android 四大组件之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类

Android 四大组件之Service(上)
 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 }
View Code

MyService类

Android 四大组件之Service(上)
 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 }
View Code

MyIntentService类

Android 四大组件之Service(上)
 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 }
View Code

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

Android 四大组件之Service(上) Android 四大组件之Service(上) Android 四大组件之Service(上) Android 四大组件之Service(上)

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

正文到此结束
Loading...