四大组件之service

来源:互联网 发布:淘宝试用报告草稿在哪 编辑:程序博客网 时间:2024/06/06 00:50

服务

service是一个可以在后台执行长时间运行操作而不提供用户界面的应用组件。服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。 此外,组件可以绑定到服务,以与之进行交互,甚至是执行进程间通信 (IPC)。 例如,服务可以处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序交互,而所有这一切均可在后台进行。

本地服务:服务和启动它的组件在同一个进程
远程服务:服务和启动它的组件不在同一个进程
远程服务只能隐式启动,在清单文件中配置Service标签时,必须配置intent-filter子节点,并指定action子节点

启动

服务的启动可以分为两种方式:启动、绑定

  • startService
开始服务,会使进程变成为服务进程,启动服务的activity和服务不再有任何关系。已启动的服务通常是执行单一操作,而且不会将结果返回给调用方。例如,它可能通过网络下载或上传文件。 操作完成后,服务会自行停止运行。
  • bindService
绑定服务不会使进程变成服务进程。绑定服务,是Activity与服务建立连接,如果Activity销毁了,服务也会被解绑并销毁,但是如果服务被销毁,Activity不会被销毁
绑定服务和解绑服务的生命周期方法:onCreate->onBind->onUnbind->onDestroy
  • 在服务类中创建一个内部类继承Binder,在该内部类中添加操作服务的方法,在onBind方法中返回给内部类的实例
  • 在调用服务的类中,创建意图,然后调用bindService(intent, connection, BIND_AUTO_CREATE)绑定服务
  • 其中connection通过 new ServiceConnection(){ }; 获取,重写两个方法:
    • onServiceDisconnected(CompontName name)
    • onServiceConnected(CompontName name, Ibinder service)
    • Ibinder 对象就是服务类中返回的 binder 对象,通过该对象就可以访问服务中的方法
同时,服务还支持上述两种方式的混合,例如用服务实现音乐播放时,因为音乐播放必须运行在服务进程中,可是音乐服务中的方法,需要被前台Activity所调用,所以需要混合启动音乐服务
先startService,再bindService,销毁时先unbind,在stop。

创建服务

启动服务由另一个组件通过调用 startService() 启动,这会导致调用服务的 onStartCommand() 方法。服务启动之后,其生命周期即独立于启动它的组件,并且可以在后台无限期地运行,即使启动服务的组件已被销毁也不受影响。 因此,服务应通过调用stopSelf() 结束工作来自行停止运行,或者由另一个组件通过调用 stopService() 来停止它。
应用组件(如 Activity)可以通过调用 startService() 方法并传递 Intent 对象(指定服务并包含待使用服务的所有数据)来启动服务。服务通过 onStartCommand() 方法接收此 Intent。例如,假设某 Activity 需要将一些数据保存到在线数据库中。该 Activity 可以启动一个协同服务,并通过向 startService() 传递一个 Intent,为该服务提供要保存的数据。服务通过 onStartCommand() 接收 Intent,连接到互联网并执行数据库事务。事务完成之后,服务会自行停止运行并随即被销毁。默认情况下,服务与服务声明所在的应用运行于同一进程,而且运行于该应用的主线程中。 因此,如果服务在用户与来自同一应用的 Activity 进行交互时执行密集型或阻止性操作,则会降低 Activity 性能。 为了避免影响应用性能,应该在服务内启动新线程。
创建服务可以创建一个类继承Service或者继承IntentService:
继承Service:这是适用于所有服务的基类。扩展此类时,必须创建一个用于执行所有服务工作的新线程,因为默认情况下,服务将使用应用的主线程,这会降低应用正在运行的所有 Activity 的性能。
public class HelloService extends Service {  private Looper mServiceLooper;  private ServiceHandler mServiceHandler;  private final class ServiceHandler extends Handler {      public ServiceHandler(Looper looper) {          super(looper);      }      @Override      public void handleMessage(Message msg) {          try {              Thread.sleep(5000);          } catch (InterruptedException e) {              Thread.currentThread().interrupt();          }          stopSelf(msg.arg1);      }  }  @Override  public void onCreate() {    HandlerThread thread = new HandlerThread("ServiceStartArguments",            Process.THREAD_PRIORITY_BACKGROUND);    thread.start();    mServiceLooper = thread.getLooper();    mServiceHandler = new ServiceHandler(mServiceLooper);  }  @Override  public int onStartCommand(Intent intent, int flags, int startId) {      Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();      Message msg = mServiceHandler.obtainMessage();      msg.arg1 = startId;      mServiceHandler.sendMessage(msg);      return START_STICKY;  }  @Override  public IBinder onBind(Intent intent) {      return null;  }  @Override  public void onDestroy() {    Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();  }}
onStartCommand() 方法必须返回整型数。整型数是一个值,用于描述系统应该如何在服务终止的情况下继续运行服务(如上所述,IntentService 的默认实现将为您处理这种情况,不过您可以对其进行修改)。从 onStartCommand() 返回的值必须是以下常量之一:
START_NOT_STICKY:如果系统在 onStartCommand() 返回后终止服务,则除非有挂起 Intent 要传递,否则系统不会重建服务。这是最安全的选项,可以避免在不必要时以及应用能够轻松重启所有未完成的作业时运行服务。
START_STICKY:如果系统在 onStartCommand() 返回后终止服务,则会重建服务并调用 onStartCommand(),但不会重新传递最后一个 Intent。相反,除非有挂起 Intent 要启动服务(在这种情况下,将传递这些 Intent ),否则系统会通过空 Intent 调用 onStartCommand()。这适用于不执行命令、但无限期运行并等待作业的媒体播放器(或类似服务)。
START_REDELIVER_INTENT:如果系统在 onStartCommand() 返回后终止服务,则会重建服务,并通过传递给服务的最后一个 Intent 调用 onStartCommand()。任何挂起 Intent 均依次传递。这适用于主动执行应该立即恢复的作业(例如下载文件)的服务。
继承IntentService 类:可以自动开启子线程处理耗时操作并且在操作完成之后自动关闭服务。IntentService 执行以下操作:
创建默认的工作线程,用于在应用的主线程外执行传递给 onStartCommand() 的所有 Intent。
创建工作队列,用于将 Intent 逐一传递给 onHandleIntent() 实现,这样您就永远不必担心多线程问题。
在处理完所有启动请求后停止服务,因此您永远不必调用 stopSelf()。
提供 onBind() 的默认实现(返回 null)。
提供 onStartCommand() 的默认实现,可将 Intent 依次发送到工作队列和 onHandleIntent() 实现。
public class HelloService extends IntentService {    //无参构造函数显式调用父类的有参构造函数    public MyIntentService() {        super("MyIntentService");    }    @Override    protected void onHandleIntent(Intent intent) {        //执行耗时操作    }    @Override    public void onDestroy() {        super.onDestroy();    }}
调用以下代码显示启动服务:
Intent intent = new Intent(this, HelloService.class);startService(intent);
隐式启动服务
Intent intent = new Intent();//创建远程的intentintent.setAction("com.gkk.homeActivity");//双引号中是点击改图标之后需要跳转到的activity过滤的意图


停止服务
启动服务必须管理自己的生命周期。也就是说,除非系统必须回收内存资源,否则系统不会停止或销毁服务,而且服务在 onStartCommand() 返回后会继续运行。因此,服务必须通过调用 stopSelf() 自行停止运行,或者由另一个组件通过调用 stopService() 来停止它。一旦请求使用 stopSelf() 或 stopService() 停止服务,系统就会尽快销毁服务。但是,如果服务同时处理多个 onStartCommand() 请求,则您不应在处理完一个启动请求之后停止服务,因为您可能已经收到了新的启动请求(在第一个请求结束时停止服务会终止第二个请求)。为了避免这一问题,您可以使用 stopSelf(int) 确保服务停止请求始终基于最近的启动请求。也就说,在调用 stopSelf(int) 时,传递与停止请求的 ID 对应的启动请求的 ID(传递给 onStartCommand() 的 startId)。然后,如果在您能够调用 stopSelf(int) 之前服务收到了新的启动请求,ID 就不匹配,服务也就不会停止。为了避免浪费系统资源和消耗电池电量,应用必须在工作完成之后停止其服务。 如有必要,其他组件可以通过调用 stopService() 来停止服务。即使为服务启用了绑定,一旦服务收到对 onStartCommand() 的调用,始终须亲自停止服务。
创建绑定的服务
绑定服务允许应用组件通过调用 bindService() 与其绑定,以便创建长期连接(通常不允许组件通过调用 startService() 来启动它)。如需与 Activity 和其他应用组件中的服务进行交互,或者需要通过进程间通信 (IPC) 向其他应用公开某些应用功能,则应创建绑定服务。要创建绑定服务,必须实现 onBind() 回调方法以返回 IBinder,用于定义与服务通信的接口。然后,其他应用组件可以调用 bindService() 来检索该接口,并开始对服务调用方法。服务只用于与其绑定的应用组件,因此如果没有组件绑定到服务,则系统会销毁服务(您不必按通过 onStartCommand() 启动的服务那样来停止绑定服务)。要创建绑定服务,首先必须定义指定客户端如何与服务通信的接口。 服务与客户端之间的这个接口必须是 IBinder 的实现,并且服务必须从 onBind() 回调方法返回它。一旦客户端收到 IBinder,即可开始通过该接口与服务进行交互。多个客户端可以同时绑定到服务。客户端完成与服务的交互后,会调用 unbindService() 取消绑定。一旦没有客户端绑定到该服务,系统就会销毁它。
创建前台服务
有时候运行在后台的服务会被系统回收,为了使服务运行的更加稳定,需要提高服务的优先级,创建前台服务。
startForeground()方法会使一个服务变为前台服务:
//设置前台进程Intent intent = new Intent();//创建远程的intentintent.setAction("com.gkk.homeActivity");//双引号中是点击改图标之后需要跳转到的activity过滤的意图//四个参数分别为上下文;请求码;意图,标志位(flags);PendingIntent pIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, 0);Notification notification = new NotificationCompat.Builder(this);.setContentIntent(pIntent);.setSmallIcon(R.drawable.main_icon);//图标.setTicker("gkk");.setContentTitle("gkk-mobile");//标题.setContentText("gkk-mobile-safe");//内容.build();startForeground(1, notification);//如果id设置为0,会导致不能设置为前台service

生命周期

服务的整个生命周期从调用 onCreate() 开始起,到 onDestroy() 返回时结束。与 Activity 类似,服务也在 onCreate() 中完成初始设置,并在 onDestroy() 中释放所有剩余资源。例如,音乐播放服务可以在 onCreate() 中创建用于播放音乐的线程,然后在 onDestroy() 中停止该线程。无论服务是通过 startService() 还是 bindService() 创建,都会为所有服务调用 onCreate() 和 onDestroy() 方法。
服务的有效生命周期从调用 onStartCommand() 或 onBind() 方法开始。每种方法均有 {Intent 对象,该对象分别传递到 startService() 或 bindService()。对于启动服务,有效生命周期与整个生命周期同时结束(即便是在 onStartCommand() 返回之后,服务仍然处于活动状态)。对于绑定服务,有效生命周期在 onUnbind() 返回时结束。


在服务中启动Activity

由于服务没有任务栈,而Activity启动之后需要放在任务栈中,所以在服务中启动Activity会抛出异常,故在服务中启动Activity需要手动设置任务栈

Intent intent = new  Intent(service.this,activity.class);//服务没有任务栈,需要添加任务栈才能启动activity.intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);startActivity(intent);


原创粉丝点击