android四大组件之Service

最近因为还没找到工作所以也趁着现在有时间,将以前的只是整理下,要不然总容易遗忘,今天就来讲解下Service的用法。作为Android的四大组件之一,其重要性可想而知。在应用中我们主要是用来进行一些后台操作,不需与应用UI进行交互,执行耗时任务等。

官方文档中这样说:

Service 是一个可以在后台执行长时间运行操作而不提供用户界面的应用组件。服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。

此外,组件可以绑定到服务,以与之进行交互,甚至是执行进程间通信 (IPC)。 例如,服务可以处理网络事务、播放音乐,执行文件 I/O

或与内容提供程序交互,而所有这一切均可在后台进行。

Service的用途:

1.在后台执行耗时操作,但不需要与用户进行交互。2.一个应用暴露出来的一些供其他应用使用的功能。

这里需要声明一点,Service是运行在主线程中,因而如果需要进行耗时操作或者访问网络等操作,需要在Service中再开启一个线程来执行(使用IntentService的话则不需要在自己手动开启线程)。

启动Service

启动一个Service有两种方式:


  1. Context.startService() 

  1. Context.bindService()  

(图片截取自官方文档:https://developer.android.com...)

startService()方式启动Service,我们启动之后是没有办法再对Service进行控制的,而且启动之后该Service是一直在后台运行的,即使它里面的一些代码执行完毕,我们要想终止该Service,就需要在他的代码里面调用stopSelf()方法或者直接调用stopService() 方法。而通过bindService()方法启动的Service,客户端将获得一个到Service的持久连接,客户端会获取到一个由Service的onBind(Intent)方法返回来的IBinder对象,用来供客户端回调Service中的回调方法。

我们无论使用那种方法,都需要定义一个类,让它继承Service类,并重写其中的几个方法,如果我们是采用startService()方式启动的话,只需要重写onCreate() 、onStartCommand(Intent intent, int flags, int startId)、onDestroy()方法即可(其实我们也可以重写),而如果采用的是bindService()方法启动的话,我们就需要重写onCreate() 、onBind(Intent intent)、 onUnbind(Intent intent)方法.注意,作为四大组件之一,Service使用之前要在清单文件中进行配置。


  1. <application> 
  2.        ...... 
  3.        <service 
  4.            android:name=".MyService"> 
  5.        </service> 
  6.    </application>  

Context.startService()

MyService.java的代码:


  1. public class MyService extends Service { 
  2.     public MyService() { 
  3.     } 
  4.  
  5.     @Override 
  6.     public void onCreate() { 
  7.         super.onCreate(); 
  8.  
  9.         Log.i("test","onCrete executed !"); 
  10.     } 
  11.  
  12.     @Override 
  13.     public int onStartCommand(Intent intent, int flags, int startId) { 
  14.  
  15.         Log.i("test","onStartComand executed !"); 
  16.         return super.onStartCommand(intent, flags, startId); 
  17.     } 
  18.  
  19.     @Override 
  20.     public void onDestroy() { 
  21.         super.onDestroy(); 
  22.         Log.i("test","onDestroy executed !"); 
  23.     } 
  24. }  

MainActivity.java的代码如下:


  1. public class MainActivity extends AppCompatActivity implements View.OnClickListener{ 
  2.  
  3.     Button btnStart,btnStop; 
  4.     @Override 
  5.     protected void onCreate(Bundle savedInstanceState) { 
  6.         super.onCreate(savedInstanceState); 
  7.         setContentView(R.layout.activity_main); 
  8.  
  9.         btnStart = (Button) findViewById(R.id.btn_start); 
  10.         btnStop = (Button) findViewById(R.id.btn_stop); 
  11.         btnStart.setOnClickListener(this); 
  12.         btnStop.setOnClickListener(this); 
  13.     } 
  14.  
  15.  
  16.     @Override 
  17.     public void onClick(View view) { 
  18.  
  19.         Intent mIntent = new Intent(MainActivity.this,MyService.class); 
  20.  
  21.         switch (view.getId()){ 
  22.             case R.id.btn_start: 
  23.                 startService(mIntent); 
  24.                 break; 
  25.             case R.id.btn_stop: 
  26.                 stopService(mIntent); 
  27.                 break; 
  28.         } 
  29.     } 
  30. }  

主界面就两个按钮,一个用来启动Service,一个用来停止Service:

下面我们先点击START按钮,Log信息如下:

可以看出,onCreate()方法先执行,然后onStartCommand()方法紧接着执行,那么如果我们再次点击启动按钮呢?结果如下图:

我们可以看到,这次onCreate()方法没有再执行,而是直接执行了onStartCommand()方法,这是因为Service只在第一次创建的时候才执行onCreate()方法,如果已经创建了,那之后再次调用startService()启动该Service的时候,只会去执行onStartCommand()方法方法,而不会再执行onCreate()方法。

接下来我们点击停止按钮,可以看到,onDestroy()方法被执行了:

注意,如果我们不点击停止按钮手动停止该Service的话,该Service会一直在后台运行,即使它的onStartCommand()方法中的代码已经执行完毕,在下图中我们可以看到:

这时候我们的这个Service是一直在后台执行的,即使它的onStartCommand()方法中的代码已经执行完了。如果我们想要它自动停止的话,可以将onStartCommand()方法中的代码修改如下:


  1. @Override 
  2.    public int onStartCommand(Intent intent, int flags, int startId) { 
  3.  
  4.        Log.i("test","onStartComand() executed !"); 
  5.        stopSelf(); 
  6.        return super.onStartCommand(intent, flags, startId); 
  7.    }  

Context.bindService()

采用该方法的代码就稍微比以前的多了,因为我们需要在客户端对Service进行控制,因而会在MainActivity中创建一个匿名内部类ServiceConnection,然后会在bindService()方法和unbindService()方法中将其传入。MyService.java 中的代码如下:


  1. public class MyService extends Service { 
  2.     private MyBinder myBinder = new MyBinder(); 
  3.  
  4.     public MyService() { 
  5.     } 
  6.  
  7.     @Override 
  8.     public void onCreate() { 
  9.         super.onCreate(); 
  10.         Log.i("test","onCreate() executed !"); 
  11.     } 
  12.  
  13.     @Override 
  14.     public void onDestroy() { 
  15.         super.onDestroy(); 
  16.         Log.i("test","onDestroy() executed !"); 
  17.     } 
  18.  
  19.     @Override 
  20.     public boolean onUnbind(Intent intent) { 
  21.  
  22.         Log.i("test","onUnbind executed !"); 
  23.         return super.onUnbind(intent); 
  24.     } 
  25.  
  26.     @Override 
  27.     public IBinder onBind(Intent intent) { 
  28.         Log.i("test","onBind() executed !"); 
  29.         return myBinder; 
  30.     } 
  31.  
  32.     class MyBinder extends Binder{ 
  33.         public void startDownload(){ 
  34.  
  35.             Log.i("test", "MyBinder中的startDownload() executed !"); 
  36.             // 执行具体的下载任务,需开启一个子线程,在其中执行具体代码 
  37.         } 
  38.     } 
  39. }  

MainActivity.java 的代码如下:


  1. public class MainActivity extends AppCompatActivity implements View.OnClickListener{ 
  2.  
  3.     Button btnBind,btnUnBind; 
  4.     MyService.MyBinder myBinder ; 
  5.     @Override 
  6.     protected void onCreate(Bundle savedInstanceState) { 
  7.         super.onCreate(savedInstanceState); 
  8.         setContentView(R.layout.activity_main); 
  9.  
  10.         btnBind = (Button) findViewById(R.id.bind); 
  11.         btnUnBind = (Button) findViewById(R.id.btn_unBind); 
  12.         btnBind.setOnClickListener(this); 
  13.         btnUnBind.setOnClickListener(this); 
  14.  
  15.     } 
  16.  
  17.     ServiceConnection mServiceConnection = new ServiceConnection() { 
  18.         @Override 
  19.         public void onServiceConnected(ComponentName componentName, IBinder iBinder) { 
  20.             // 将IBinder向下转型为我们的内部类MyBinder 
  21.             myBinder = (MyService.MyBinder) iBinder; 
  22.             // 执行下载任务 
  23.             myBinder.startDownload(); 
  24.         } 
  25.  
  26.         @Override 
  27.         public void onServiceDisconnected(ComponentName componentName) { 
  28.  
  29.         } 
  30.     }; 
  31.  
  32.     @Override 
  33.     public void onClick(View view) { 
  34.  
  35.         Intent mIntent = new Intent(MainActivity.this,MyService.class); 
  36.  
  37.         switch (view.getId()){ 
  38.             case R.id.bind: 
  39.                 // 绑定Service 
  40.                 bindService(mIntent,mServiceConnection,BIND_AUTO_CREATE); 
  41.                 break; 
  42.             case R.id.btn_unBind: 
  43.                 // 取消绑定Service 
  44.                 unbindService(mServiceConnection); 
  45.                 break; 
  46.         } 
  47.     } 
  48. }  

点击绑定按钮;

点击取消绑定按钮:

注意,如果我们没有先点击绑定,而是直接点击的取消绑定,程序会直接crash,报以下错误:


  1. java.lang.IllegalArgumentException: Service not registered: com.qc.admin.myserializableparceabledemo.MainActivity$1@8860e28 
  2.  at android.app.LoadedApk.forgetServiceDispatcher(LoadedApk.java:1120) 
  3.  at android.app.ContextImpl.unbindService(ContextImpl.java:1494) 
  4.  at android.content.ContextWrapper.unbindService(ContextWrapper.java:616) 
  5.  at com.qc.admin.myserializableparceabledemo.MainActivity.onClick(MainActivity.java:71)  

细心的你也许早就发现了,Log中并没有打印"onServiceDisconnected executed !"这句,也就是说没有调用onServiceDisconnected()方法?从字面理解,onServiceConnected()方法是在Service建立连接的时候调用的,onServiceDisconnected()不就应该是在Service断开连接的时候调用的吗?其实不然,我们查看该方法的文档就知道了:

Called when a connection to the Service has been lost. This typically happens when the process hosting the service has crashed or been killed. This does not remove the ServiceConnection itself -- this binding to the service will remain active, and you will receive a call to onServiceConnected(ComponentName, IBinder) when the Service is next running.

意思就是:当绑定到该Service的连接丢失的时候,该方法会被调用,典型的情况就是持有该Service的进程crash掉了,或者被杀死了。但是这并不会移除ServiceConnection 自身--它仍然是保持活跃状态,当Service下次被执行的时候,onServiceConnected(ComponentName, IBinder) 方法仍然会被调用。

但是要注意,如果我们按照刚才说的,不是先点击 bindService()方法,而是直接点击unbindService()方法,程序虽然也是crash掉了,但onServiceDisconnected()方法并不会被调用,这个很容易理解,毕竟都没有建立连接呢,谈何断开连接啊。但是如果我们已经绑定了Service,然后在后台直接终止该Service呢?结果会怎样?答案是onServiceDisconnected()方法仍然不会调用。这里我觉得应该是只有在意外的情况下进程结束,是由系统自动调用的,而非我们手动停止的。我们可以查看该方法内部的注释:

This is called when the connection with the service has been

unexpectedly disconnected -- that is, its process crashed.Because it

is running in our same process, we should never see this happen.

这段文字清楚的说明了该方法执行的场景:异常情况下导致断开了连接。也就是进程crash掉了。因为它运行在我们应用程序所在的进程中,因而我们将永远不希望看到这种情况发生。

Context.startService()和Context.bindService()同时使用

这两种方式是可以同时使用的,但是要注意,startService()和stopService()方法是对应的,而bindService()和unBind()方法是对应的,也就是说如果我们先调用startService()之后调用bindService()方法,或者相反,那么我们如果只调用stopService()或者只调用bindService()都无法停止该Service,只有同时调用才可以。

下面来看下具体代码:

MainActivity.java


  1. public class MainActivity extends AppCompatActivity implements View.OnClickListener{ 
  2.  
  3.     Button btnStart,btnStop,btnBind,btnUnBind; 
  4.     MyService.MyBinder myBinder ; 
  5.     @Override 
  6.     protected void onCreate(Bundle savedInstanceState) { 
  7.         super.onCreate(savedInstanceState); 
  8.         setContentView(R.layout.activity_main); 
  9.  
  10.         btnStart = (Button) findViewById(R.id.btn_start); 
  11.         btnStop = (Button) findViewById(R.id.btn_stop); 
  12.         btnBind = (Button) findViewById(R.id.btn_bind); 
  13.         btnUnBind = (Button) findViewById(R.id.btn_unBind); 
  14.  
  15.         btnStart.setOnClickListener(this); 
  16.         btnStop.setOnClickListener(this); 
  17.         btnBind.setOnClickListener(this); 
  18.         btnUnBind.setOnClickListener(this); 
  19.  
  20.     } 
  21.  
  22.     ServiceConnection mServiceConnection = new ServiceConnection() { 
  23.         @Override 
  24.         public void onServiceConnected(ComponentName componentName, IBinder iBinder) { 
  25.             // 将IBinder向下转型为我们的内部类MyBinder 
  26.             myBinder = (MyService.MyBinder) iBinder; 
  27.             // 执行下载任务 
  28.             myBinder.startDownload(); 
  29.  
  30.         } 
  31.  
  32.         @Override 
  33.         public void onServiceDisconnected(ComponentName componentName) { 
  34.  
  35.             Log.i("test","onServiceDisconnected executed !"); 
  36.         } 
  37.     }; 
  38.  
  39.     @Override 
  40.     public void onClick(View view) { 
  41.  
  42.         Intent mIntent = new Intent(MainActivity.this,MyService.class); 
  43.  
  44.         switch (view.getId()){ 
  45.             case R.id.btn_start: 
  46.                 // 启动Service 
  47.                 startService(mIntent); 
  48.                 break; 
  49.             case R.id.btn_stop: 
  50.                 // 终止Service 
  51.                 stopService(mIntent); 
  52.                 break; 
  53.             case R.id.btn_bind: 
  54.                 // 绑定Service 
  55.                 bindService(mIntent,mServiceConnection,BIND_AUTO_CREATE); 
  56.                 break; 
  57.             case R.id.btn_unBind: 
  58.                 // 取消绑定Service 
  59.                 unbindService(mServiceConnection); 
  60.                 break; 
  61.         } 
  62.     } 
  63. }  

MyService.java的代码:


  1. public class MyService extends Service { 
  2.     private MyBinder myBinder = new MyBinder(); 
  3.  
  4.     public MyService() { 
  5.     } 
  6.  
  7.     @Override 
  8.     public void onCreate() { 
  9.         super.onCreate(); 
  10.         Log.i("test","onCreate() executed !"); 
  11.     } 
  12.  
  13.     @Override 
  14.     public int onStartCommand(Intent intent, int flags, int startId) { 
  15.  
  16.         Log.i("test","onStartComand() executed !"); 
  17.         return super.onStartCommand(intent, flags, startId); 
  18.     } 
  19.  
  20.     @Override 
  21.     public void onDestroy() { 
  22.         super.onDestroy(); 
  23.         Log.i("test","onDestroy() executed !"); 
  24.     } 
  25.  
  26.     @Override 
  27.     public boolean onUnbind(Intent intent) { 
  28.  
  29.         Log.i("test","onUnbind executed !"); 
  30.         return super.onUnbind(intent); 
  31.     } 
  32.  
  33.     @Override 
  34.     public IBinder onBind(Intent intent) { 
  35.         Log.i("test","onBind() executed !"); 
  36.         return myBinder; 
  37.     } 
  38.  
  39.     class MyBinder extends Binder{ 
  40.         public void startDownload(){ 
  41.  
  42.             Log.i("test", "MyBinder中的startDownload() executed !"); 
  43.             // 执行具体的下载任务 
  44.         } 
  45.     } 
  46. }  

a.下面是依次点击start、bind、stop、unBind 按钮的输出结果:

b.下面是依次点击start、bind、unbind、stop 按钮时的输出结果:

在前台运行服务

我们上面一直说Service一般是用来在后台执行耗时操作,但是要知道,Service也是可以运行在前台的。后台Service的优先级比较低,容在内存不足等情况下被系统杀死,通过将其设置为前台,可以大大降低其被杀死的机会。前台Service会在系统通知栏显示一个图标,我们可以在这里进行一些操作。前台Service比较常见的场景有音乐播放器和天气预报等:

那么接下来我们就直接上代码:


  1. @Override 
  2.     public void onCreate() { 
  3.         super.onCreate(); 
  4.         Log.i("test", "onCreate() executed !"); 
  5.  
  6.         Intent mIntent = new Intent(this, SecondActivity.class); 
  7.         PendingIntent mPendingIntent = PendingIntent.getActivity(this, 0, mIntent, 0); 
  8.         Notification mNotification = new NotificationCompat.Builder(this) 
  9.                 .setSmallIcon(R.mipmap.ic_launcher) 
  10.                 .setContentTitle("My Notification ") 
  11.                 .setContentText("Hello World ! ") 
  12.                 .setContentIntent(mPendingIntent) 
  13.                 .build(); 
  14.  
  15.         // 注意:提供给 startForeground() 的整型 ID 不得为 0。 
  16.         // 要从前台移除服务,请调用 stopForeground()。此方法采用一个布尔值,指示是否也移除状态栏通知。 
  17.         // 然而stopForeground()不会停止服务。 但是,如果您在服务正在前台运行时将其停止,则通知也会被移除。 
  18.         startForeground(1, mNotification); 
  19.     }  

其实这里的实现很简单,就是将一个Notification通过startForeground(1, mNotification);传进去,从而将Notification与 Service建立起关联。我们点击这个通知,就会跳转到第二个Activity(但是该Notification并不会消失),截图如下:

作者:i_seek_u

来源:51CTO

时间: 2024-09-30 21:25:01

android四大组件之Service的相关文章

Android四大组件之Service(服务)实例详解_Android

本文实例讲述了Android四大组件之服务用法.分享给大家供大家参考,具体如下: 很多情况下,一些与用户很少需要产生交互的应用程序,我们一般让它们在后台运行就行了,而且在它们运行期间我们仍然能运行其他的应用. 为了处理这种后台进程,Android引入了Service的概念.Service在Android中是一种长生命周期的组件,它不实现任何用户界面. 基本概念 Ÿ   Service是一种在后台运行,没有界面的组件,由其他组件调用开始. Ÿ   创建Service,定义类继承Service,An

Android四大组件之Service(服务)实例详解

本文实例讲述了Android四大组件之服务用法.分享给大家供大家参考,具体如下: 很多情况下,一些与用户很少需要产生交互的应用程序,我们一般让它们在后台运行就行了,而且在它们运行期间我们仍然能运行其他的应用. 为了处理这种后台进程,Android引入了Service的概念.Service在Android中是一种长生命周期的组件,它不实现任何用户界面. 基本概念 Ÿ   Service是一种在后台运行,没有界面的组件,由其他组件调用开始. Ÿ   创建Service,定义类继承Service,An

Android四大组件之——ContentProvider(一)

Android四大组件之--ContentProvider(一) 本人邮箱:JohnTsai.Work@gmail.com,欢迎交流讨论. 欢迎转载,转载请注明网址:http://www.cnblogs.com/JohnTsai 个人博客地址:http://johntsaiandroid.github.io 目录 1.ContentProvider * 1.1ContentProvider简介 * 1.2为什么有ContentProvider * 1.3Android官方的ContentProv

Android四大组件之——Activity(一)定义、状态和后退栈(图文详解)

什么是Activity       关键字:应用组件.四大组件.用户界面,交互. An Activity is an application component that provides a screen with which users can interact in order to do something       每个Android应用打开,一般都有界面与用户进行交互,以完成输入,输出等一些功能.提供这个功能的就是Android四大组件之一,Activity.       Acti

Android四大组件之——Activity的开启:StartActivity()和StartActivityForResult()(图文详解)

      如需转载请在文章开头处注明本博客网址:http://www.cnblogs.com/JohnTsai       联系方式:JohnTsai.Work@gmail.com         [Android四大组件学习系列Activity篇]        1.Android四大组件之--Activity(一)定义.状态和后退栈(图文详解)        2.Android四大组件之--Activity的生命周期(图文详解)        3.Android四大组件之--Activit

Android四大组件之——Activity的生命周期(图文详解)

      转载请在文章开头处注明本博客网址:http://www.cnblogs.com/JohnTsai       联系方式:JohnTsai.Work@gmail.com       [Android四大组件学习系列Activity篇]       1.Android四大组件之--Activity(一)定义.状态和后退栈(图文详解)       2.Android四大组件之--Activity的生命周期(图文详解)      上一篇文章讲了Activity的定义.状态和后退栈,现在讲讲A

Android开发四大组件Activity/Service/Broadcast Receiver/Content Provider详解

Android开发的四大组件一.Activity详解二.Service详解三.Broadcast Receiver详解四.Content Provider详解外加一个重要组件 intent的详解. 一.Activity详解 Activty的生命周期的也就是它所在进程的生命周期. 一个Activity的启动顺序: onCreate()-->onStart()-->onResume() 当另一个Activity启动时:第一个Activity onPause()-->第二个Activity  

Android实训案例(七)——四大组件之一Service初步了解,实现通话录音功能,抽调接口

Service Service的神奇之处,在于他不需要界面,一切的操作都在后台操作,所以很多全局性(手机助手,语音助手)之类的应用很长需要这个,我们今天也来玩玩 我们新建一个工程--ServiceDemo 1.启动服务 服务是怎么启动的,我们先定义一个按钮吧 <Button android:id="@+id/startservice" android:layout_width="wrap_content" android:layout_height="

Android四大组件之——ContentProvider(二)

Content Resolver介绍:    开发者文档中这么定义的: This class provides applications access to the content model. 这个类为应用提供访问Content模型的功能. Content Resolver是我们应用里单一全局实例,为我们访问我们自己的应用或其他应用的Content Provider.就如同名字所描述的:Content Resolver接收来自客户的请求,然后解决它们的请求,通过将请求指向特定主机名的Conte