Android Service的用法
为什么要使用Service?
一般在没有界面显示的Service是Android中实现程序后台运行的解决方案,非常适合用于去执行哪些不需要和用户交互而且还要求长期运行的任务。不能运行在一个独立的进程当中,而是依赖与创建服务时所在的应用程序进程。只能在后台运行,并且可以和其他组件进行交互。
Service可以在很多场合使用,比如播放多媒体的时候用户启动了其他Activity,此时要在后台继续播放;比如检测SD卡上文件的变化;比如在后台记录你的地理信息位置的改变等等,总之服务是藏在后台的。
服务不会自动开启线程,我们需要在服务的内部手动创建子线程,并在这里执行具体的任务。
那么这里就有一个疑问:我们直接在Activity或者其它组件中直接开辟一条新的线程用于后台服不就行了?但是这里存在一个问题:由于手机的内存限制,Dalvik虚拟机会在内存紧张的时候,将那些没有和任何可见组件关联的线程强制关闭,那么如果宿主进程被终止,则这个进程中所有的子线程就有被关闭的危险,那么这些子线程中的任务就不能够被执行完毕,引入Service解决了这样的一个危险,同时是程序的结构更加合理
简单的Service的创建(Activity和Service之间不需要实时数据的交换)方法一:
1、创建Service和创建Activity基本是一致的,只要继承Service类即可创建一个Service的子类,Service也有自己的生命周期,在一个生命周期中的不同阶段会回调各个方法
2、创建了Service之后,就要在Manifest.xml文件中对Service进行配置,指定方法是使用<service…./>元素
3、之后就能够在其它组件中通过startService(Intent intent)启动Intent指定的Service了,调用stopService(Intent intent)就能够终止一个Service
停止一个started服务有两种方法:
(1)在外部使用stopService()
(2)在服务内部(onStartCommand方法内部)使用stopSelf()方法。
内部停止

这是一个非常标准的简单服务的格式,一般我们都将简单服务写在onStartCommand中,由于使用startService方法启动的Service,在执行完服务后不会自动停止,所以要自行加入stopSelf()方法,或者在Service外部即Activity中调用stopService,一般采用前者
4、使用startService(Intent intent)方法启动一个Service的时候,启动者和Service之间没有关联,即使启动者已经退出,Service还会依然运行(这就存在一个问题,如果Service没有和任何一个可见的组件相关联的话,那么在内存紧张时,Service就会被强行终止)
5、下面介绍Service生命周期中的一些方法 :
public IBinder onBind(Intent intent);
这个方法是Service子类必须实现的一个方法,该方法返回的IBinder对象用来在启动者和Service之间进行通信(以后会具体讲解)
public void onCreate()
当一个Service在其生命周期中第一次被创建后,这个方法会立即被回调
public int onStartCommand(Intent intent , int flag , int startId)
每次调用startService(Intent intent)方法之后,onStartCommand都会被调用,
需要注意的是,Activity通过startService(Intent intent)启动Service之后,那个Intent对象就会传到onStartCommand方法中的 Intent intent参数中,这样,Activity 就能够通过Intent给Service传递数据了,但是在Service的其他的方法中是不能够调用,如getIntent()方法的,所以如果通过Intent向Service中传递数据,那么onStartCommand方法唯一的入口,但是有时我们想要在Service的其他的地方使用Intent中的数据,怎么办呢?这非常的简单,只要正在Service中设置一个全局变量,之后在onStartCommand中为这个全局变量为这个全局变量赋值即可
public void onDestroy() 当Service结束的时候就会回调这个方法
下面举一个例子:
MainActivity中有两个按钮,一个用来启动Service,一个用来关闭Service
public class MainActivity extends Activity { final static String ACTION_VIEW_SERVICE = "action.ACTION_VIEW_SERVICE" ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button startButton = (Button) findViewById(R.id.start); Button endButton = (Button) findViewById(R.id.end); final Intent intent = new Intent() ; intent.setAction(MainActivity.ACTION_VIEW_SERVICE); startButton.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { startService(intent); } }); endButton.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { stopService(intent); } }); }
}
Simple_Service.java 文件,这是一个简单的Service,用来测试用的
public class Simple_Service extends Service{ @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate(){ super.onCreate(); Log.d("Tag","onCreate"); } @Override public int onStartCommand(Intent intent , int flag , int startId){ Log.d("Tag" , "onStartCommand");
//如果外部不使用stopActivity的话,最好在这里使用stopSelf()方法 return 0 ; } @Override public void onDestroy(){ super.onDestroy(); Log.d("Tag","onDestory"); } }
之后我们就要在Manifest.xml文件中对Service进行配置
<service android:name=".Simple_Service"> <intent-filter > <action android:name="action.ACTION_VIEW_SERVICE"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </service>
程序分析:
①我们点击MainActivity的启动Service按钮的时候,在Log控制台输出:
onCreate
onStartCommand
我们发现虽然Simple_Service中的onCreate( )方法非常的简单,仅仅是输出一行测试字符串,那么Simple_Servicey的实际的执行应该很快的结束,但是并没有输出“onDestroy”这说明虽然Simple_Service的实际工作已经执行完毕,但是在堆中的匿名的Service实例变量并没用被回收,
②在点击了一次启动按钮之后,如果我们再次点击启动按钮的话,将会输出
“onStartCommand”就不会再调用onCreate()方法了,
③当点击关闭按钮的时候,就会输出“onDestroy”
简单的Service的创建(Activity和Service之间不需要实时数据的交换)方法二:
我们发现,使用Service创建简单的服务的一个问题是:需要创建一条单独的线程,需要想着调用stopSelf(),有时还得想着线程的同步问题,Android中提供了一种更加简单的方式——IntentService,IntentService是Service的一个子类,这个类相对于Service的优点在于:
④IntentService中的onHandleIntent()方法是用来放服务处理代码的,Intent发来请求时,就会毁掉这个方法,执行这部分的代码
①当有Intent发来启动服务请求时,IntentService会创建单独的线程来处理IntentService中的服务,因此无需自己创建线程
②当有多个Intent发来请求的话,IntentService会将这些Intent请求放入队列中利用上面开辟的线程一个一个的处理,
③当所有的Intent请求都完成的时候,IntnetService会自动停止,因此开发者无需调用stopSelf()方法
⑤IntentService无需重写onBind、onStartCommand方法,只要重写onHandleIntent()方法,实现具体服务即可
下面是一个典型的IntentService服务:
public class MyIntentService extends IntentService{ public MyIntentService(){ super("MyInstent"); } protected void onHandleIntent(Intent intent){ 。。。。。。耗时任务。。。。。。。 } }
如何实现启动方和Service之间实现互通信息(以Activity 和Service为例)
上面介绍的通过startService和stopService启动和关闭Service时,Service和访问者之间基本上不存在太多的关联,只能够通过Intent传递数据,如果想要在Activity和Service之间互传数据的话,就要使用Context的bindService(参数)和unbindservice(参数)方法
1、Context的两个方法的具体参数如下:
public void bindService(Intent service , ServiceConnection conn , int flag);
①参数Intent service:通过该参数指定需要启动的Service
②参数conn:该参数是一个ServiceConnection对象,该对象用于监听访问者与Service之间的连接情况。当访问者与Service之间连接成功时将马上回调这个对象中的onServiceConnected(ComponentName name , IBinder service)方法,并将Service中的IBinder onBind(Intent intent)方法返回的IBinder对象赋给onServiceConnected方法的IBinder service参数,这样通过这个IBinder对象就能够再Activity和Service之间互通数据
③当Service所在的宿主进程由于异常终止或其他原因终止的话,导致Service和访问者之间断开连接时,将会回调该ServiceConnection对象的onServiceDisconnected(ComponentName name)方法,但是当调用这主动地通过使用unBinderService()方法与Service断开连接时,该方法将不会被调用
④参数flag:指定绑定一个Service的时候是否自动创建Service,
0——不创建
BIND_AUTO_CREATE——自动创建
这是为什么呢?因为同一个Service可能被多个Activity绑定,所以,如果Service刚开始还没有被绑定的时候,一个Activity通过bindService()方法绑定这个Service的时候,那么当然需要将flag设为BIND_AUTO_CREATE,之后的Activity如果在想要绑定这个已经启动的Service,那么flag就要设置为 0
2、public void unbindService(ServiceConnection conn);
参数conn:就是上一个方法传入的ServiceConnection对象,
3、还要有一点说明的是,在Service的生命周期中还有另外的一个方法
boolean onUnbind(Intent inten ) ;
一个Service可以被多个客户端绑定,当这些所有的客户端都断开连接时,将会回调该方法;由于使用bindService方法后,应该使用unbindService方法解除绑定,不使用stopService,那么这种情况下,当所有的客户端都调用unbindService与该Service解除绑定之后,这个Service就会先调用onUnbind,之后直接调用onDestroy方法
4、当开发Service的时候必须实现IBinder onBind(Intent intent)方法,那么就来介绍一下这个IBinder 的使用方法:
IBinder是一个接口,在实际中我们往往通过继承他的子类Binder,来创建IBinder子类,如:public class MyBinder extends Binder{……..};
通过下面的实例来将上面的方方面面穿起来:
BindService.java 文件
public class BindService extends Service{ //定义数据交换对象 public class SendBinder extends Binder{ public BindService getService(){ return BindService.this ; } } private SendBinder sendBinder = new SendBinder() ; int count = 0 ; boolean isQuit = false; @Override public IBinder onBind(Intent intent) { return sendBinder ; } //定义该Service执行的具体任务 public void changeCount(){ new Thread(){ public void run(){ while(!isQuit){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } count++ ; } } }.start(); } //获取BindService中的count当前的数值 public int getCount(){ return count ; } @Override public boolean onUnbind(Intent intent){ Log.d("Tag" , "onUnbind"); return true ; } @Override public void onDestroy(){ this.isQuit = true ; } }
MainActivity.java 文件
这个Activity的布局文件中有三个按钮,分别用来启动Service中的changeCount()方法,和Service解除绑定,或取当前Service的count的值
public class MainActivity extends Activity { final static String INTENT_SERVICE= "action.SERVICE_VIEW"; BindService bindService ; //定义内部类ServiceConnection private ServiceConnection conn = new ServiceConnection(){ @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.d("Tag", "onServiceConnected"); MainActivity.this.bindService = ((BindService.SendBinder)service).getService() ; } @Override public void onServiceDisconnected(ComponentName name) { Log.d("Tag" ,"onServiceDisConnected"); } } ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button startButton = (Button) findViewById(R.id.startButton); Button endButton = (Button)findViewById(R.id.endButton); Button getCountButton = (Button) findViewById(R.id.getCountButton); final TextView textView = (TextView)findViewById(R.id.textView); final Intent intent = new Intent(); intent.setAction(INTENT_SERVICE); bindService(intent,conn,Service.BIND_AUTO_CREATE); startButton.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { MainActivity.this.bindService.changeCount(); } }); getCountButton.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { textView.setText("Service中当前的Count值是:" + bindService.getCount()); } }); endButton.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { unbindService(conn); } }); } }
至于配置文件就不在多说了
程序分析:
1、我们在Service的onBind()方法中返回的是SendBinder对象
//定义数据交换对象 public class SendBinder extends Binder{ public BindService getService(){ return BindService.this ; } } private SendBinder sendBinder = new SendBinder() ; int count = 0 ; boolean isQuit = false; @Override public IBinder onBind(Intent intent) { return sendBinder ; }
需要注意的是这个sendBinder对象中方法我们写的是
return BindService.this ;
即返回的是当前的BindService的实例,这样做非常有用,因为这样的话,我们就能够在MainActivity中获得这个Service的对象,这样就能够在MainActivity中按时机有选择的调用Service中的方法,当然,我们也可以不返回整个Service对像,而是只返回需要的Service中的数据
2、还要注意的一点是在MainActivity中调用bindService(intent,conn,Service.BIND_AUTO_CREATE);的位置,之前我把这句写在了startButton的监听器的onClick方法中,结果不能够正常的绑定,这个问题有待解决
如何实现Activity和Service之间的数据的实时交互
参见之前的博客
Service的生命周期
一旦在项目的任何位置调用了Context的startService()方法,相应的服务就会启动起来,并回调onstartCommand()方法。如果这个服务之前还没有创建过,onCreate()方法会先于onstartCommand()方法执行。服务启动过后,会一直保持运行状态,直到stopService()或stopself()方法被调用。注意虽然每次调用一次startService()方法,onstartCommand()方法就会以执行一次,但实际上每个服务都只会存在一个实例。所以不管你调用了多少次startService()方法,只需调用一次stopService()或stopself()方法,服务就会停止。
另外,还可以调用Context的bindService()来获取一个服务的持久连接,这时就会回调服务中的onBind()方法。类似地,如果这个服务之前还没有创建过,onCreate()方法会先于onBind()方法执行。之后调用方可以获取到onBind()方法里返回的IBinder对象的实例,这样,就能自由地和服务进行通信了。只要调用方和服务之间的连接没有断开,服务就会一直保持运行状态。
需要注意的是,使用简单的Service服务,要调用stopSelf,使用绑定的方式要记得调用unbindService方法,
在上面已经对这些作了说明,就不再多讲了

浙公网安备 33010602011771号