1.Service简介android
Service是Android四大组件中最与Activity类似的组件,他们都表明可执行的程序。Service一直运行于后台,不会与用户交互,可用来处理一些耗时的任务(好比:后台播放音乐,I/O操做等)。它的建立、配置与Activity基本类似,下面将详细介绍Android Service的开发。多线程
2.建立、配置Serviceapp
2.1 定义一个继承Service类的子类异步
2.2 在AndroidManifest.xml中配置该Serviceide
须要注意的是 Service和Activity都是从Context类派生出来的(建议能够了解下Context这个类,了解以后,学习后面的一些组件、类也是很轻松的),所以它们均可以调用Context中getResources()、getContentResolver()等方法;布局
Service中定义的系列生命周期的方法:学习
IBinder onBind(Intent intent):该方法是Service必须实现的一个方法,该方法返回一个IBinder对象,应用程序能够经过该对象与Service组件通信测试
void onCreate():当Service第一次被建立后,系统将当即回调该方法ui
void onDestory():当Service被关闭以前会回调该方法this
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中建立一个线程去处理耗时任务。