美文网首页
Service 学习

Service 学习

作者: 我是来捕鱼的 | 来源:发表于2016-10-22 15:47 被阅读60次

A Service is an application component representing either an application's desire to perform a longer-running operation while not interacting with the user or to supply functionality for other applications to use. Each service class must have a corresponding <service> declaration in its package'sAndroidManifest.xml. Services can be started with Context.startService() and Context.bindService().
Note that services, like other application objects, run in the main thread of their hosting process. This means that, if your service is going to do any CPU intensive (such as MP3 playback) or blocking (such as networking) operations, it should spawn its own thread in which to do that work. More information on this can be found in Processes and Threads. The IntentService class is available as a standard implementation of Service that has its own thread where it schedules its work to be done.

从官方文档上可以看出,Service服务是不与用户交互,长时间在后台运行的一个组件。但是所在线程是在主线程,如果要处理耗时操作如播放音乐,处理网络请求的话需要启动一个子线程来处理。


一、启动与销毁

  • 启动Service
    启动Service有两种方法:
    ①startService()
Intent intent = new Intent(MainActivity.this,TestService.class);
startService(intent);

生命流程:onCreate() → onStartCommand() → onDestory()
注意: onCreate()方法只会执行一次,多次调用StartService()方法只会在第一次调用onCreate(),而onStartCommand()会多次调用。
当服务被启动后,Service与Activity就没有了关系,Activity退出后Service还会执行。
②bindService()

bindService(intent,mcon,BIND_AUTO_CREATE);
public MCon mcon = new MCon();
public class MCon implements ServiceConnection{     
      @Override    
      public void onServiceConnected(ComponentName name, IBinder service) {        
            myBinder = (TestService.MyBinder)service;    
      }    
      @Override    
      public void onServiceDisconnected(ComponentName name) {

      }
}
onServiceConnected()
系统调用这个来传送在service的onBind()中返回的IBinder.
OnServiceDisconnected()
Android系统在同service的连接意外丢失时调用这个.比如当service崩溃了或被强杀了.
当客户端解除绑定时,这个方法不会被调用. 类ServiceConnection中的onServiceDisconnected()方法在正常情况下是不被调用的,
它的调用时机是当Service服务被异外销毁时,例如内存的资源不足时这个方法才被自动调用。

生命流程: onCreate() → onBind() → onUnbind() → onDestory()
多次调用bindService()并不会再次调用onCreate() 和onBind()。
当服务被启动后,Service与Activity就绑定在了一起,当Activity退出之后Service也退出。

  • 销毁service
    使用startService()启动之后调用stopService()来销毁服务。
    使用bindService()绑定之后调用unbindService()来销毁服务。
    如果同时调用startService()与bindService(),销毁时需要同时调用stopService()与unbindService()来销毁。
           
    1.如果先bindService,再startService:
    在bind的Activity退出的时候,Service会执行unBind方法而不执行onDestory方法,因为有startService方法调用过,所以Activity与Service解除绑定后会有一个与调用者没有关连的Service存在
    2.如果先bindService,再startService,再调用Context.stopService
    Service的onDestory方法不会立刻执行,因为有一个与Service绑定的Activity,但是在Activity退出的时候,会执行onDestory,如果要立刻执行stopService,就得先解除绑定 
     
    要注意合理中断Service中的线程,最好设置变量检测中断(先挖个坑)。

  • onStartCommand返回值
    START_STICKY:如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到service,那么参数Intent将为null。
    START_NOT_STICKY:“非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务
    START_REDELIVER_INTENT:重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。
    START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保证服务被kill后一定能重启。

  • **bindService参数 **
    BIND_AUTO_CREATE:一般为这个,代表Service不存在时自动创建该Service。

二、Service与Activity通信

  • 采用onBind与接口方式双向通信
public interface BinderInterface {    
      int getI();    
      void setI(int a);
}          
            
class MyBinder extends Binder implements BinderInterface{    
      @Override    
      public int getI() {        
      return i;    
      }    
      @Override    
      public void setI(int a) {        
      i = a;        
      mtThread.interrupt();    
      }
}
   
public MyBinder mBinder = new MyBinder();    
public IBinder onBind(Intent intent) { 
      return mBinder;    
}

利用obBind()将一个Binder对象传递给Activity。

public TestService.MyBinder myBinder;
public MCon mcon = new MCon();
public class MCon implements ServiceConnection{     
      @Override    
      public void onServiceConnected(ComponentName name, IBinder service) {        
            myBinder = (TestService.MyBinder)service;    
      }    
      @Override    
      public void onServiceDisconnected(ComponentName name) {

      }
}

转化为MyBinder对象之后就可以使用MyBinder中的方法来相互通信了。

myBinder.setI(1000);
int i = myBinder.getI();
  • 使用Intent通信
    使用Intetnt在Activity启动Service时,将数据放入Intent之中,之后在Service中的onStartCommand(Intent intent, int flags, int startId)方法中获取到Intetnt并提取出数据。
Activity中:
Intent intent = new Intent(MainActivity.this,TestService.class)
intent.putExtra("name","li");
startService(intent);
    
Service中
public int onStartCommand(Intent intent, int flags, int startId) {    
      String name  = (intent.getExtras()).getString("name");        
      return START_STICKY;
}

三、前台服务

  • 提升为前台服务
    什么是前台服务

A foreground service(前台服务) is a service that's considered to be(被用户所认可的) something the
user is actively aware of and thus not a candidate for(而不是一个候选的,可以在内存不足时,被系统杀死
的) the system to kill when low on memory. A foreground service must provide a notification for the status
bar(前台服务必须提供一个显示通知), which is placed under the "Ongoing" heading(它是不可以忽略的), >which means that the notification cannot be dismissed unless the service is either stopped or removed from >the foreground.(意思是通知信息不能被忽略,除非服务停止或主动移除,否则将一直显示)

前台服务是那些被认为用户知道(用户认可所认可)且在系统内存不足的时候不允许系统杀死的服务。 前台服务必须给状态栏提供一个通知,它被放到正在运行(Ongoing)标题之下——这就意味着通知只有在这个服务被终止或从前台主动移除通知后才能被解除。
如果我们希望Service可以一直保持运行状态且不会在内存不足的情况下被回收时,可以选择将需要保持运行的Service设置为前台服务
   
创建Notifition

private void bulidNotifition() {    
      notificationBuilder = new Notification.Builder(this);    
      Intent intent = new Intent(this,MainActivity.class);    
      notification = notificationBuilder.setContentIntent(PendingIntent.getActivity(this,0,intent,0))
              .setLargeIcon(BitmapFactory.decodeResource(this.getResources(),R.mipmap.ic_launcher))
              .setContentTitle("前台Serviece")            
              .setContentText("内容")           
              .setWhen(System.currentTimeMillis()).build();
}

在onStartCommand中启动前台服务

public int onStartCommand(Intent intent, int flags, int startId) {    
      bulidNotifition();    
      startForeground(100,notification);    //100表示前台服务的id  当使用的通知ID一致时,只会更新当前Notification
      return START_STICKY;
}

停止前台服务

stopForeground(true);

启动服务之后,就会看到提示框那里有个提示栏,说明我们的Service已经成为前台服务了。

四、IntentService

开启一个线程来处理用户的intent请求,采用队列等待,一个时间只有一个intent请求被执行。

主要方法:onHandleIntent(Intent intent)

此方法在具有请求的工作线程上被调用。 每次只处理一个Intent,但是处理发生在独立于其他应用程序逻辑运行的工作线程上。 所以,如果这段代码需要很长时间,它会阻止对同一IntentService的其他请求,但它不会阻止任何其他。 当所有请求都被处理后,IntentService停止自己,所以你不应该调用stopSelf()。

button1.setOnClickListener(new View.OnClickListener() {
    @Override    
    public void onClick(View v) {
        Intent intentservice1 = new Intent(MainActivity.this,MyIntentService.class);
        intentservice1.putExtra("action",1);
        startService(intentservice1);
    }
});

button2.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Intent intentservice2 = new Intent(MainActivity.this,MyIntentService.class);
        intentservice2.putExtra("action",2);
        startService(intentservice2);
    }
}
);
protected void onHandleIntent(Intent intent) {
    Log.d("intent",intent.getIntExtra("action",0)+"");
    try {
         Log.d("A1sleep","A1sleep");
         Thread.sleep(2000);
         Log.d("sleep down","sleep down");
    } catch (InterruptedException e) {
         e.printStackTrace();
    }
}
依次按下按钮,intent依次执行

五、跨进程Service与通信

相关文章

网友评论

      本文标题:Service 学习

      本文链接:https://www.haomeiwen.com/subject/gfqhuttx.html