start启动服务 功能: 点击start按钮开启一个服务,点击stop按钮停止一个按钮。
代码: 布局的xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android ="http://schemas.android.com/apk/res/android" xmlns:tools ="http://schemas.android.com/tools" android:orientation ="vertical" android:layout_width ="match_parent" android:layout_height ="match_parent" android:paddingLeft ="@dimen/activity_horizontal_margin" android:paddingRight ="@dimen/activity_horizontal_margin" android:paddingTop ="@dimen/activity_vertical_margin" android:paddingBottom ="@dimen/activity_vertical_margin" tools:context =".MainActivity" > <Button android:layout_height ="wrap_content" android:layout_width ="match_parent" android:id ="@+id/start" android:text ="startService" android:onClick ="doClick" /> <Button android:layout_height ="wrap_content" android:layout_width ="match_parent" android:id ="@+id/stop" android:text ="destroyService" android:onClick ="doClick" /> </LinearLayout >
和Activity一样,Service也需要在配置文件中注册:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android ="http://schemas.android.com/apk/res/android" package ="com.demoniaccube.chobits.pracetice_service" > <application android:allowBackup ="true" android:icon ="@mipmap/ic_launcher" android:label ="@string/app_name" android:supportsRtl ="true" android:theme ="@style/AppTheme" > <activity android:name =".MainActivity" > <intent-filter > <action android:name ="android.intent.action.MAIN" /> <category android:name ="android.intent.category.LAUNCHER" /> </intent-filter > </activity > <service android:name =".MyService" > </service > </application > </manifest >
一个Activity类,用于启动服务和提供按钮界面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class MainActivity extends AppCompatActivity { private Intent intent1; @Override protected void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void doClick (View v) { switch (v.getId()) { case R.id.start: intent1 = new Intent(MainActivity.this , MyService.class); startService(intent1); break ; case R.id.stop: stopService(intent1); break ; } } }
一个自定义的Service子类,用于继承Service类,用于实现Service的具体内容,这里只是简单的打印了文字。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class MyService extends Service { @Override public void onCreate () { super .onCreate(); Log.d("ZXB" , "Service_onCreate()" ); } @Override public int onStartCommand (Intent intent, int flags, int startId) { Log.d("ZXB" , "Service_onStartCommand()" ); return super .onStartCommand(intent, flags, startId); } @Override public void onDestroy () { Log.d("ZXB" , "Service_onDestroy()" ); super .onDestroy(); } @Override public IBinder onBind (Intent intent) { Log.d("ZXB" , "Service_onBind()" ); return null ; } }
启动一个服务很简单,总结一下: 1、继承Service类,现实其方法。 2、在配置文件中注册Service。 3、在Service的启动源(这里是Activity)中使用startService()方法启动Service,stopService停止服务。这和跳转Activity的方法类似,用了Intent的显示用法。
bind启动服务 功能: 点击bind按钮绑定服务,unbind按钮解除绑定。点击播放、暂停等按钮打印对应的日志。这里的播放、暂停等方法是写在Service里的。这里用bind使Service和Activity建立了联系。
代码: xml布局文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android ="http://schemas.android.com/apk/res/android" xmlns:tools ="http://schemas.android.com/tools" android:orientation ="vertical" android:layout_width ="match_parent" android:layout_height ="match_parent" android:paddingLeft ="@dimen/activity_horizontal_margin" android:paddingRight ="@dimen/activity_horizontal_margin" android:paddingTop ="@dimen/activity_vertical_margin" android:paddingBottom ="@dimen/activity_vertical_margin" tools:context =".MainActivity" > <Button android:layout_height ="wrap_content" android:layout_width ="match_parent" android:id ="@+id/start" android:text ="startService" android:onClick ="doClick" /> <Button android:layout_height ="wrap_content" android:layout_width ="match_parent" android:id ="@+id/stop" android:text ="destroyService" android:onClick ="doClick" /> <Button android:layout_height ="wrap_content" android:layout_width ="match_parent" android:id ="@+id/bind" android:text ="bindService" android:onClick ="doClick" /> <Button android:layout_height ="wrap_content" android:layout_width ="match_parent" android:id ="@+id/unbind" android:text ="unbindService" android:onClick ="doClick" /> <Button android:layout_height ="wrap_content" android:layout_width ="match_parent" android:id ="@+id/play" android:text ="播放" android:onClick ="doClick" /> <Button android:layout_height ="wrap_content" android:layout_width ="match_parent" android:id ="@+id/pause" android:text ="暂停" android:onClick ="doClick" /> <Button android:layout_height ="wrap_content" android:layout_width ="match_parent" android:id ="@+id/previous" android:text ="上一首" android:onClick ="doClick" /> <Button android:layout_height ="wrap_content" android:layout_width ="match_parent" android:id ="@+id/next" android:text ="下一首" android:onClick ="doClick" /> </LinearLayout >
Activity类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 public class MainActivity extends AppCompatActivity { private Intent intent1; private Intent intent2; MyBindService myBindService; ServiceConnection conn = new ServiceConnection() { @Override public void onServiceConnected (ComponentName name, IBinder service) { myBindService = ((MyBindService.MyBinder)service).getService(); } @Override public void onServiceDisconnected (ComponentName name) { Log.d("ZXB" ,"error" ); } }; @Override protected void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); intent1 = new Intent(MainActivity.this , MyService.class); intent2 = new Intent(MainActivity.this , MyBindService.class); } public void doClick (View v) { switch (v.getId()) { case R.id.start: startService(intent1); break ; case R.id.stop: stopService(intent1); break ; case R.id.bind: bindService(intent2, conn, BIND_AUTO_CREATE); break ; case R.id.unbind: unbindService(conn); break ; case R.id.play: myBindService.play(); break ; case R.id.pause: myBindService.pause(); break ; case R.id.previous: myBindService.previous(); break ; case R.id.next: myBindService.next(); break ; } } }
Service子类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 public class MyBindService extends Service { class MyBinder extends Binder //Binder 实现了Ibinder 接口,所以可以作为onBind 的返回值 { public MyBindService getService () { return MyBindService.this ; } } @Override public void onCreate () { super .onCreate(); Log.d("ZXB" , "BindService_onCreate()" ); } @Override public int onStartCommand (Intent intent, int flags, int startId) { Log.d("ZXB" , "BindService_onStartCommand()" ); return super .onStartCommand(intent, flags, startId); } @Override public IBinder onBind (Intent intent) { Log.d("ZXB" , "BindService_onBind()" ); return new MyBinder(); } @Override public boolean onUnbind (Intent intent) { Log.d("ZXB" , "BindService_onUnbind()" ); return super .onUnbind(intent); } @Override public void onDestroy () { super .onDestroy(); Log.d("ZXB" , "BindService_onDestroy()" ); } public void play () { Log.d("ZXB" , "播放" ); } public void pause () { Log.d("ZXB" , "暂停" ); } public void previous () { Log.d("ZXB" , "上一首" ); } public void next () { Log.d("ZXB" , "下一首" ); } }
总结: bind启动的服务的流程和start类似,都是要先继承Service类,现实其方法;然后在配置文件中注册Service;在启动源中用bindService绑定并启动服务,unbindService解除绑定服务。而与start不同的是,在继承Service的时候,要实现IBinder接口(即继承Binder类,写个内部类),将得到的Binder子类实例作为onBind的返回值。而在启动源(Service)中需要实例化ServiceConnection类,这个类起到连接Service和Activity的作用,Activity可以通过ServiceConnection得到Service实例,从而控制Service。 注意:如果不使用ServiceConnection的话,绑定后直接退出应用或解除绑定会报错。
另外我试了一下。 1、当我把使用start和bind混合启动Service后,又解除了绑定,依然可以使用Service的播放、暂停等方法。这个地方我有点奇怪,既然已经解除绑定为什么还可以调用服务里的方法? 2、当我把使用start和bind混合启动后,又stop了Service,依然可以使用Service的播放、暂停等方法。
关于服务的详细博文 引用一下他讲的比较好的地方:
1). Thread:Thread 是程序执行的最小单元,它是分配CPU的基本单位。可以用 Thread 来执行一些异步的操作。 2). Service:Service 是android的一种机制,当它运行的时候如果是Local Service,那么对应的 Service 是运行在主进程的 main 线程上的。如:onCreate,onStart 这些函数在被系统调用的时候都是在主进程的 main 线程上运行的。如果是Remote Service,那么对应的 Service 则是运行在独立进程的 main 线程上。因此请不要把 Service 理解成线程,它跟线程半毛钱的关系都没有!
Service的生命周期
1). 被启动的服务的生命周期:如果一个Service被某个Activity 调用 Context.startService 方法启动,那么不管是否有Activity使用bindService绑定或unbindService解除绑定到该Service,该Service都在后台运行。如果一个Service被startService 方法多次启动,那么onCreate方法只会调用一次,onStart将会被调用多次(对应调用startService的次数),并且系统只会创建Service的一个实例(因此你应该知道只需要一次stopService调用)。该Service将会一直在后台运行,而不管对应程序的Activity是否在运行,直到被调用stopService,或自身的stopSelf方法。当然如果系统资源不足,android系统也可能结束服务。 2). 被绑定的服务的生命周期:如果一个Service被某个Activity 调用 Context.bindService 方法绑定启动,不管调用 bindService 调用几次,onCreate方法都只会调用一次,同时onStart方法始终不会被调用。当连接建立之后,Service将会一直运行,除非调用Context.unbindService 断开连接或者之前调用bindService 的 Context 不存在了(如Activity被finish的时候),系统将会自动停止Service,对应onDestroy将被调用。 3). 被启动又被绑定的服务的生命周期:如果一个Service又被启动又被绑定,则该Service将会一直在后台运行。并且不管如何调用,onCreate始终只会调用一次,对应startService调用多少次,Service的onStart便会调用多少次。调用unbindService将不会停止Service,而必须调用 stopService 或 Service的 stopSelf 来停止服务。 4). 当服务被停止时清除服务:当一个Service被终止(1、调用stopService;2、调用stopSelf;3、不再有绑定的连接(没有被启动))时,onDestroy方法将会被调用,在这里你应当做一些清除工作,如停止在Service中创建并运行的线程。
特别注意: 1、你应当知道在调用 bindService 绑定到Service的时候,你就应当保证在某处调用 unbindService 解除绑定(尽管 Activity 被 finish 的时候绑定会自动解除,并且Service会自动停止); 2、你应当注意 使用 startService 启动服务之后,一定要使用 stopService停止服务,不管你是否使用bindService; 3、同时使用 startService 与 bindService 要注意到,Service 的终止,需要unbindService与stopService同时调用,才能终止 Service,不管 startService 与 bindService 的调用顺序,如果先调用 unbindService 此时服务不会自动终止,再调用 stopService 之后服务才会停止,如果先调用 stopService 此时服务也不会终止,而再调用 unbindService 或者 之前调用 bindService 的 Context 不存在了(如Activity 被 finish 的时候)之后服务才会自动停止;