enabled="true" android:
name=".MyService" />
其中android:
enabled属性的值为true,表示MyService服务处于激活状态。
虽然目前MyService是激活的,但系统仍然不会启动MyService,要想启动这个服务。
必须显式地调用startService方法。
如果想停止服务,需要显式地调用stopService方法,代码如下:
1.public void onClick(View view)
2.{
3. switch (view.getId())
4. {
5. case R.id.btnStartService:
6. startService(serviceIntent);
// 单击【Start Service】按钮启动服务
7. break;
8. case R.id.btnStopService:
9. stopService(serviceIntent);
// 单击【Stop Service】按钮停止服务
10. break;
11. }
12.}
其中serviceIntent是一个Intent对象,用于指定MyService服务,创建该对象的代码如下:
1.serviceIntent = new Intent(this, MyService.class);
运行本节的例子后,会显示如图8.1所示的界面。
图8.1 开始和停止服务
第1次单击【StartService】按钮后,在DDMS透视图的LogCat视图的Message列会输出如下两行信息:
1.onCreate
2.onStart
然后单击【StopService】按钮,会在Message列中输出如下信息:
1.onDestroy
下面按如下的单击按钮顺序的重新测试一下本例。
【StartService】→【StopService】→【StartService】→【StartService】→【StartService】→【StopService】
测试完程序,就会看到如图8.2所示的输出信息。
可以看出,只在第1次单击【StartService】按钮后会调用onCreate方法,如果在未单击【StopService】按钮时多次单击【StartService】按钮,系统只在第1次单击【StartService】按钮时调用onCreate和onStart方法,再单击该按钮时,系统只会调用onStart方法,而不会再次调用onCreate方法。
图8.2 服务的生命周期方法的调用情况
在讨论完服务的生命周期后,再来总结一下创建和开始服务的步骤。
创建和开始一个服务需要如下3步:
(1)编写一个服务类,该类必须从android.app.Service继承。
Service类涉及到3个生命周期方法,但这3个方法并不一定在子类中覆盖,读者可根据不同需求来决定使用哪些生命周期方法。
在Service类中有一个onBind方法,该方法是一个抽象方法,在Service的子类中必须覆盖。
这个方法当Activity与Service绑定时被调用(将在8.1.3节详细介绍)。
(2)在AndroidManifest.xml文件中使用标签来配置服务,一般需要将标签的android:
enabled属性值设为true,并使用android:
name属性指定在第1步建立的服务类名。
(3)如果要开始一个服务,使用startService方法,停止一个服务要使用stopService方法。
8.1.2 绑定Activity和Service
本节的例子代码所在的工程目录是src\ch08\ch08_serviceactivity
如果使用8.1.1节介绍的方法启动服务,并且未调用stopService来停止服务,这个服务就会随着Android系统的启动而启动,随着Android系统的关闭而关闭。
也就是服务会在Android系统启动后一直在后台运行,直到Android系统关闭后服务才停止。
但有时我们希望在启动服务的Activity关闭后服务自动关闭,这就需要将Activity和Service绑定。
通过bindService方法可以将Activity和Service绑定。
bindService方法的定义如下:
1.public boolean bindService(Intent service,
ServiceConnection conn, int flags)
该方法的第1个参数表示与服务类相关联的Intent对象,第2个参数conn是一个ServiceConnection类型的变量,负责连接Intent对象指定的服务。
通过ServiceConnection对象可以获得连接成功或失败的状态,并可以获得连接后的服务对象。
第3个参数是一个标志位,一般设为Context.BIND_AUTO_CREATE。
下面重新编写8.1.1节的MyService类,在该类中增加了几个与绑定相关的事件方法。
1.package net.blogjava.mobile.service;
2.
3.import android.app.Service;
4.import android.content.Intent;
5.import android.os.Binder;
6.import android.os.IBinder;
7.import android.util.Log;
8.
9.public class MyService extends Service
10.{
11. private MyBinder myBinder = new MyBinder();
12. // 成功绑定后调用该方法
13. @Override
14. public IBinder onBind(Intent intent)
15. {
16. Log.d("MyService", "onBind");
17. return myBinder;
18. }
19. // 重新绑定时调用该方法
20. @Override
21. public void onRebind(Intent intent)
22. {
23. Log.d("MyService", "onRebind");
24. super.onRebind(intent);
25. }
26. // 解除绑定时调用该方法
27. @Override
28. public boolean onUnbind(Intent intent)
29. {
30. Log.d("MyService", "onUnbind");
31. return super.onUnbind(intent);
32. }
33. @Override
34. public void onCreate()
35. {
36. Log.d("MyService", "onCreate");
37. super.onCreate();
38. }
39. @Override
40. public void onDestroy()
41. {
42. Log.d("MyService", "onDestroy");
43. super.onDestroy();
44. }
45. @Override
46. public void onStart(Intent intent, int startId)
47. {
48. Log.d("MyService", "onStart");
49. super.onStart(intent, startId);
50. }
51. public class MyBinder extends Binder
52. {
53. MyService getService()
54. {
55. return MyService.this;
56. }
57. }
58.}
现在定义一个MyService变量和一个ServiceConnection变量,代码如下:
1.private MyService myService;
2.private ServiceConnection serviceConnection = new ServiceConnection()
3.{
4. // 连接服务失败后,该方法被调用
5. @Override
6. public void onServiceDisconnected(ComponentName name)
7. {
8. myService = null;
9. Toast.makeText(Main.this, "Service
Failed.", Toast.LENGTH_LONG).show();
10. }
11. // 成功连接服务后,该方法被调用。
在该方法中可以获得MyService对象
12. @Override
13. public void onServiceConnected(ComponentName name, IBinder service)
14. {
15. // 获得MyService对象
16. myService = ((MyService.MyBinder) service).getService();
17. Toast.makeText(Main.this, "Service
Connected.", Toast.LENGTH_LONG).show();
18. }
19.};
最后使用bindService方法来绑定Activity和Service,代码如下:
1.bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
如果想解除绑定,可以使用下面的代码:
1.unbindService(serviceConnection);
在MyService类中定义了一个MyBinder类,该类实际上是为了获得MyService的对象实例的。
在ServiceConnection接口的onServiceConnected方法中的第2个参数是一个IBinder类型的变量,将该参数转换成MyService.MyBinder对象,并使用MyBinder类中的getService方法获得MyService对象。
在获得MyService对象后,就可以在Activity中随意操作MyService了。
运行本节的例子后,单击【BindService】按钮,如果绑定成功,会显示如图8.3所示的信息提示框。
关闭应用程序后,会看到在LogCat视图中输出了onUnbind和onDestroy信息,表明在关闭Activity后,服务先被解除绑定,最后被销毁。
如果先启动(调用startService方法)一个服务,然后再绑定(调用bindService方法)服务,会怎么样呢?
在这种情况下,虽然服务仍然会成功绑定到Activity上,但在Activity关闭后,服务虽然会被解除绑定,但并不会被销毁,也就是说,MyService类的onDestroy方法不会被调用。
图8.3 绑定服务
8.1.3 在BroadcastReceiver中启动Service
本节的例子代码所在的工程目录是src\ch08\ch08_startupservice
在8.1.1节和8.1.2节都是先启动了一个Activity,然后在Activity中启动服务。
如果是这样,在启动服务时必须要先启动一个Activity。
在很多时候这样做有些多余,阅读完第7章的内容,会发现实例43可以利用BroadcastReceiver在Android系统启动时运行一个Activity。
也许我们会从中得到一些启发,既然可以在BroadcastReceiver中启动Activity,为什么不能启动Service呢?
说做就做,现在让我们来验证一下这个想法。
先编写一个服务类,这个服务类没什么特别的,仍然使用前面两节编写的MyService类即可。
在AndroidManifest.xml文件中配置MyService类的代码也相同。
下面来完成最关键的一步,就是建立一个BroadcastReceiver,代码如下:
1.package net.blogjava.mobile.startupservice;
2.
3.import android.content.BroadcastReceiver;
4.import android.content.Context;
5.import android.content.Intent;
6.
7.public class StartupReceiver extends BroadcastReceiver
8.{
9. @Override
10. public void onReceive(Context context, Intent intent)
11. {
12. // 启动一个Service
13. Intent serviceIntent = new Intent(context, MyService.class);
14. context.startService(serviceIntent);
15. Intent activityIntent = new Intent(context, MessageActivity.class);
16. // 要想在Service中启动Activity,必须设置如下标志
17. activityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
18. context.startActivity(activityIntent);
19. }
20.}
在StartupReceiver类的onReceive方法中完成了两项工作:
启动服务和显示一个Activity来提示服务启动成功。
其中MessageActivity是一个普通的Activity类,只是该类在配置时使用了"@android:
style/Theme.Dialog"主题,因此,如果服务启动成功,会显示如图8.4所示的信息。
图8.4 在BroadcastReceiver中启动服务
如果安装本例后,在重新启动模拟器后并未出现如图8.4所示的信息提示框,最大的可能是没有在AndroidManifest.xml文件中配置BroadcastReceiver和Service,下面来看一下AndroidManifest.xml文件的完整代码。
1.
xml version="1.0" encoding="utf-8"?
>
2.android="
3. package="net.blogjava.mobile.startupservice"
android:
versionCode="1"
4. android:
versionName="1.0">
5. icon="@drawable/icon"
android:
label="@string/app_name">
6.