一、前言
引用官方一句话:
A service is an application component that can perform long-running operations in the background and does not provide a user interface。
大概翻译就是:服务是一个应用程序组件,可以在后台执行长时间运行的操作,不提供用户界面。(英语不好)
Service作为Android四大组件之一,必定有它独特的作用。Service与Activity最为相似,但是又有不同。它们的区别是:
1)Activity可以与用户交互,而Service是不能与用户交互,但是长期潜伏在后台执行一些比较耗时的工作(开启新的线程)。
2)Service和Activity都有自己的生命周期,但是Service生命周期比较简单。
3)Service可以实现进程间通信,而Activity只能在同一个进程中调用。
4)Activity在进程被杀死之后就会结束,而Service在后台继续保持运行状态。
相信很多开发者都知道Service如何使用,但是并不是每一位都能理解透彻,希望这篇文章会让大家有所收获。
二、Service基础
说到service,首先要先知道它的生命周期,如下图所示:
根据这张图,我们有必要对这些回调方法进行分析一下:
onStartCommand()
:当其他组件调用startService()
方法请求启动Service时,该方法被回调。一旦Service启动,它会在后台独立运行。当Service执行完以后,需调用stopSelf()
或 stopService()
方法停止Service。(若您只希望bind Service,则无需调用这些方法)onBind()
:当其他组件调用bindService()
方法请求绑定Service时,该方法被回调。该方法返回一个IBinder
接口,该接口是Service与绑定的组件进行交互的桥梁。若Service未绑定其他组件,该方法应返回null。onCreate()
:当Service第一次创建时,回调该方法。该方法只被回调一次,并在onStartCommand()
或 onBind()
方法被回调之前执行。若Service处于运行状态,该方法不会回调。onDestroy()
:当Service被销毁时回调,在该方法中应清除一些占用的资源,如停止线程、接触绑定注册的监听器或broadcast
receiver 等。该方法是Service中的最后一个回调。通过上面,相信大家对Service生命周期有一定的认识了,在这里我做一些个人总结:
1)可以看出Service启动有两种方式,第一种用startService启动stopService停止,另外一种是用绑定
bindService和unbindService解绑。但是无论有什么方式,对于生命周期中的onCreate和onDestroy来说,都会被调用。
2)如果service是被开启的,那么它的活动生命周期和整个生命周期一同结束。如果service是被绑定的,那么它的活动生命周期是在onUnbind()方法返回后结束。
3)无论是那种启动方式,onCreate都只会调用一次。
三、Service基本使用
下面通过一个项目来看看Service是怎么执行的?
新建一个TestService继承Service,并重写以下方法:
public class TestService extends Service { private static final String TAG = "test"; @Override public void onCreate() { super.onCreate(); //打印线程ID Log.d(TAG,"TestService Thread:"+Thread.currentThread().getId()); Log.d(TAG,"onCreate"); } @Override public IBinder onBind(Intent intent) { Log.d(TAG,"onBind"); return new MyBinder(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.d(TAG,"onStartCommand"); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { super.onDestroy(); Log.d(TAG,"onDestroy"); } @Override public boolean onUnbind(Intent intent) { Log.d(TAG,"onUnbind"); return super.onUnbind(intent); } public class MyBinder extends Binder { public void load() { Log.d(TAG,"执行下载了!"); } } }
然后在ServiceActivity中做启动、停止、绑定、解绑动作。
public class ServiceActivity extends AppCompatActivity { private Button start,stop,bind,unbind; private TestService.MyBinder myBinder; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_service); initUI(); //打印线程ID Log.d("test","activity Thread:"+Thread.currentThread().getId()); } /** * 界面初始化 * @author hjy * created at 2016/12/15 13:46 */ private void initUI() { start = (Button) findViewById(R.id.start); stop = (Button) findViewById(R.id.stop); bind = (Button) findViewById(R.id.bind); unbind = (Button) findViewById(R.id.unbind); //开启服务 start.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(ServiceActivity.this, TestService.class); startService(intent); } }); //停止服务 stop.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(ServiceActivity.this, TestService.class); stopService(intent); } }); //绑定服务 bind.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(ServiceActivity.this, TestService.class); //BIND_AUTO_CREATE表示在Activity和Service建立关联后自动创建Service, // 这会使得MyService中的onCreate()方法得到执行,但onStartCommand()方法不会执行。 bindService(intent,connection,BIND_AUTO_CREATE); } }); //解绑服务 unbind.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //Intent intent = new Intent(ServiceActivity.this, TestService.class); unbindService(connection); } }); } //Activity与Service建立关联与接触关联时候被调用 private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { myBinder = (TestService.MyBinder)iBinder; myBinder.load(); } @Override public void onServiceDisconnected(ComponentName componentName) { } }; }
在布局文件中,布局4个按钮,分别是startService,stopService,bindService,unbindService。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/activity_service" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <Button android:id="@+id/start" android:layout_width="wrap_content" android:layout_height="40dp" android:text="start Service"/> <Button android:id="@+id/stop" android:layout_width="wrap_content" android:layout_height="40dp" android:text="stop Service"/> <Button android:id="@+id/bind" android:layout_width="wrap_content" android:layout_height="40dp" android:text="bind Service"/> <Button android:id="@+id/unbind" android:layout_width="wrap_content" android:layout_height="40dp" android:text="unbind Service"/> </LinearLayout>
别忘记四大组件在AndroidManifest.xml配置:
<service android:name="com.hjyProject.service.TestService" />
1、点击startService按钮,观察一下log打印。
从上面可以看出,点击startService按钮,会执行onCreate-->onStartCommand。眼尖的小伙伴会观察出,activity的线程id与service线程id一样,都是1。顺便说明一点,Service是执行在主线程UI线程中,具体我们下面会做讨论。
2、接着上面一步,我们在继续多点几次startService按钮,观察一下log打印。
从上面可以看出,只要启动了Service服务,不管你以后执行多少次startService都只会执行onStartCommand方法,也能说明,onCreate只执行一次。
3、执行stopService按钮,观察一下log打印。
从上面可以看出,点击stopService,执行了onDestroy方法,说明服务结束。
4、执行bindService按钮,观察一下log打印。
从上面可以看出,点击了bindService按钮,会执行onCreate-->onBind-->Bind类中的下载方法。
5、绑定过得Service,继续点击bindService按钮,观察一下log打印。
无打印现象。。。
从这个现象说明,服务仅能绑定一次。
6、执行unBindService按钮,观察一下log打印。
从上面可以看出,点击了unBindService按钮,会执行onUnbind-->onDestroy,服务解绑。
7、执行startService按钮,在执行bindService按钮,在执行stopService按钮或者执行unBindService按钮,观察一下log打印。
从上面可以看出,不管你执行了stopService按钮还是执行了unBindService按钮,都不会打印出onUnBind方法。
奇怪的是,同时点击了这两个stopService按钮和unBindService按钮,就会出现onUnBind方法和onDestroy方法。
从上面可以得出,onBindService和startService同时执行的时候,必须通过unBindService解绑和onstopService停止服务,服务才能真正的结束。
通过上面的例子,相信大家应该知道服务有两种启动方式,服务结束,以及服务的与Activity之前的通信调用。接下来,来讲一下服务与线程之间关系。
四、服务与线程
通过上面我们也先知道了服务所执行的线程与UI主线程是同一个ID。这大概也能说明一点,service想执行比较耗时的事件,必须开启新的子线程,不然会导致UI线程的堵塞。
既然在Service里也要创建一个子线程,那为什么不直接在Activity里创建呢?
这是因为Activity很难对Thread进行控制,当Activity被销毁之后,就没有任何其它的办法可以再重新获取到之前创建的子线程的实例。而且在一个Activity中创建的子线程,另一个Activity无法对其进行操作。但是Service就不同了,所有的Activity都可以与Service进行关联,然后可以很方便地操作其中的方法,即使Activity被销毁了,之后只要重新与Service建立关联,就又能够获取到原有的Service中Binder的实例。因此,使用Service来处理后台任务,Activity就可以放心地finish,完全不需要担心无法对后台任务进行控制的情况。
在MyBinder类中开启一条新的线程去执行比较耗时的工作。
public class MyBinder extends Binder { public void load() { Log.d(TAG,"执行下载了!"); new Thread(new Runnable() { @Override public void run() { ...... } }).start(); } }
好了!Service基本使用大概就讲到这,后边我会讲Service进程间的通信(AIDL)。如果有出错或者需要改进的地方,欢迎指点或者交流。
作者:qq_21126979 发表于2016/12/15 17:10:09 原文链接
阅读:23 评论:0 查看评论