Service 学习

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与通信

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,670评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,928评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,926评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,238评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,112评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,138评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,545评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,232评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,496评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,596评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,369评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,226评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,600评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,906评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,185评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,516评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,721评论 2 335

推荐阅读更多精彩内容