大凡一个可以在后台执行长时间运作操作而不以用户界面的利用组件。启动之生命周期调用。

Service

Service,四怪组件有,是一个足以当后台执行长时间运作操作而不以用户界面的下组件。服务可由于其余使用组件启动,而且就是用户切换到外应用,服务按将以后台继续运行。
此外,组件可以绑定到服务,以同之进行互,甚至是实施过程之中通信 (IPC)。
例如,服务可拍卖网络工作、播放音乐,执行文书 I/O
或同情提供程序交互,而具备这整个均只是每当后台进行。

可必须使取的凡,虽然身为后台,但是Service运行于主线程!
PS:Service的合法文档有中文翻译了!!真是个特别好的消息!

服务的生命周期

图片 1

生命周期

跟Activity类似,service也产生协调的生命周期,但是简单了一些.

service_lifecycle

劳之分类

  • 长途服务—->运行于不同的过程被的劳务。
    经过对android:process=”:service”属性指定不同进程。
  • 地面服务—->运行于同进程中之服务。

以调用方式分类。

  • startService启动,即使开行它的采用组建销毁了,服务吗会见存在。不开展通信。停止服务用stopService(不管而调用了稍稍次startService);

  • bindService调用启动,当启动它的组装销毁,服务呢会见跟着销毁。可以开展通信。停止服务用unbindService;

  • startService、bindService
    同时开动,停止服务承诺同时使用stopService与unbindService
    脚来形容一个劳动,在其的生命周期回调方法被分别打印日志。代码如下:

      public class MyService1 extends Service {
          public static final String TAG = MyService1.class.getSimpleName();
    
          @Override
          public void onCreate() {
              super.onCreate();
              Log.e(TAG, TAG + "-->onCreate()");
          }
    
          @Nullable
          @Override
          public IBinder onBind(Intent intent) {
              Log.e(TAG, TAG + "-->onBind()");
              return null;
          }
    
          @Override
          public int onStartCommand(Intent intent, int flags, int startId) {
              Log.e(TAG, TAG + "-->onStartCommand()");
              return super.onStartCommand(intent, flags, startId);
          }
    
          @Override
          public void onDestroy() {
              super.onDestroy();
              Log.e(TAG, TAG + "-->onDestroy()");
          }
    
          @Override
          public boolean onUnbind(Intent intent) {
              Log.e(TAG, TAG + "-->onUnbind()");
              return super.onUnbind(intent);
          }
      }
    

转忘了以清单配置文件里部署。<service
android:name=”.services.MyService1″></service>接着我们来拘禁一下startService,startService、bindService
启动之生命周期调用。其中MainActivity的布局文件代码:

    <?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:id="@+id/activity_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:orientation="vertical"
        tools:context="com.example.serviceexample.MainActivity">

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:onClick="start"
            android:text="start启动服务" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:onClick="stop"
            android:text="stop停止服务" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:onClick="bind"
            android:text="bind启动服务" />

        <Button
            android:onClick="unbind"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:text="unbind停止服务" />


    </LinearLayout>

Service的基本采用

点的生命周期已经提醒到了,使用Service有零星栽方式,启动/停止,绑定/解绑,一一对应:

  1. startService stopService(启动)
  2. bindService unbindService(绑定)
  3. 还有平等种不畏是就调用start,又调用bind(又开动以绑定)

马上几乎单办法还起啊分别也?
莫急急,咱慢慢来,一一解答.

我们先勾勒个MyService,继承service,重写他的各种方式,并在打印日志(这是自修太常用之艺术).
写几只按钮调用不同方法,再加个ServiceConnection,代码就非给全了,没难度,不过如果顾Service要在xml里配置

<service
    android:name=".service.MyService"
    android:enabled="true"
    android:exported="false">
</service>

解释一下xml的习性:

  1. enabled: 是否能够为网实例化,false就因此非了了
  2. exported:
    其他以之零件是否能够同她相,false表示私有只能自己使用使用,true表示可给别以调起

对此xml的布置,官方有些建议:

  1. 为了保下的安全性,请始终以显式 Intent 启动或绑定
    Service,且不要也服务声明 Intent 过滤器。
  2. 补给加 android:exported 属性并将那安为
    “false”,确保服务才适用于公的运用。这可有效阻止其他以启动您的劳动,即便在使显式
    Intent 时也这么。

点击事件:

@OnClick({R.id.start_service, R.id.stop_service, R.id.bind_service, R.id.unbind_service})
public void onClick(View view) {

    Intent intent = new Intent(ServiceActivity.this,MyService.class);
    switch (view.getId()) {
        case R.id.start_service:
            startService(intent);
            break;
        case R.id.stop_service:
            stopService(intent);
            break;
        case R.id.bind_service:
            bindService(intent,con, Service.BIND_AUTO_CREATE);
            break;
        case R.id.unbind_service:
            unbindService(con);
            break;
    }
}

//bindservice 需要
ServiceConnection con = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        Log.d(TAG, "onServiceConnected() called with: " + "name = [" + name + "], service = [" + service + "]");
        ((MyService.MyBinder)service).dosth();
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        Log.d(TAG, "onServiceDisconnected() called with: " + "name = [" + name + "]");
    }
};

PS:bindService的参数BIND_AUTO_CREATE表示于Activity和Service建立涉后自行创建Service,这会使得MyService中的onCreate()方法赢得执行,但onStartCommand()方法不见面执行。(来自guolin的博客)

startService

public void start(View view) {
    Intent intent = new Intent(this, MyService1.class);
    startService(intent);
}

public void stop(View view) {
    Intent intent = new Intent(this, MyService1.class);
    stopService(intent);
}

点击start启动服务,点击stop停止服务。就看一下它的生命周期。onCreate()–>onStartCommand()–>onDestroy();

图片 2

勤点击start启动服务,会是什么状况?

图片 3

公会意识便调用了同等次等onCreate(),这是由onCreate()方法才会以Service第一次于为创造的时刻调用,如果手上Service已经于创造了了,
不顾调用startService()方法,onCreate()方法还不见面再也履行,而onStartCommand()不是。

startService&stopService

bindService

public class MainActivity extends AppCompatActivity {
    private ServiceConnection connection;//服务连接
    public static final String TAG = MainActivity.class.getSimpleName();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //实现连接的回调
        connection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
                Log.e(TAG, "onServiceConnected()+");
            }

            @Override
            public void onServiceDisconnected(ComponentName componentName) {

            }
        };
    }


    public void bind(View view) {
        Intent intent = new Intent(this, MyService1.class);
        bindService(intent, connection, BIND_AUTO_CREATE);
    }

    public void unbind(View view) {
        unbindService(connection);
    }


}

此间bindService需要传三单参数,第1单参数中将Intent传递给bindService()函数,声明需要启动之Service
第二独参数是前方创建有之ServiceConnection的实例,
勿可知吧空,第3单参数Context.BIND_AUTO_CREATE表明要绑定在,就活动建立Service。
点击bind启动服务,点击unbind停止服务。就看一下她的生命周期。onCreate()–>onBind()–>onUnbind()–>onDestroy();

图片 4

startService

使用startService启动service:
先是坏开行service会调用onCreate,onStartCommand,而背后的虽未会见再度调用onCreate而是onStartCommand,并且每次startId不同.

注意是启动,启动后,这样以手机安装-正在运行界面会显示出MyService存在.

D/MyService: onCreate:
D/MyService: onStartCommand()
//第二次startService
D/MyService: onStartCommand()
劳务是运作在主线程遭遇的,不信仰而得独家于MainActivity和MyService1的onCreate()方法中打印Log.e(TAG, TAG +”Thread id: “+ Thread.currentThread().getId());它们的线程ID是一样的。

stopService

调用stopService,情况如下:

  1. 若果service已经通过startService启动,则onDestroy
  2. 只要service没启动,则没什么意义

 D/MyService: onDestroy:

stopService之后,正在运行界面不会见发MyService存在了.

PS:如果未调用stop,直接关掉Activity对Service没影响,即双方的生命周期没有关联.

有关劳动的onStartCommand()方法。

onStartCommand()替换了onStart()方法,这里最主要介绍一下onStartCommand()方法返回值的意思,它有四独返回值:START_STICKY、START_NOT_STICKY、START_REDELIVER_INTENT、START_STICKY_COMPATIBILITY。

  • 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&unbindService

就此到bind跟之前的startService不同,我们尚用重新写onBind,添加Bind类:

@Override
public IBinder onBind(Intent intent) {
    Log.d(TAG, "onBind: ");
    return new MyBinder();
}

public class MyBinder extends Binder{

    public void dosth(){
        Log.d(TAG, "dosth: ");
    }
}

bindService

bindService作用是暨service进行绑定.
文档介绍:
绑定服务是客户端-服务器接口中之服务器。
绑定服务而吃组件(例如
Activity)绑定到劳动、发送请求、接收响应,甚至推行进程之中通信 (IPC)。
绑定服务普通仅于啊另外使用组件服务经常处于活动状态,不见面无限期在后台运行。

点击bind按钮,发现MyService调用了onCreateonBind,并且之前的ServiceConnection里的onServiceConnected呢被调用了.
注意:

  1. 及startService不同的凡,多次调用bindService没有效力,不会见重复多调用onBind**
  2. 如果onBind里我们返回null那么onServiceConnected未见面吃调用
  3. 差让startService,bind调用后,设置-正在周转里是看不到有Service运行在的.

D/MyService: onCreate:
D/MyService: onBind:
D/MyService: onServiceConnected()
D/MyService: dosth:

unbindService

unbindService是用于解绑,取消关联

  1. 若是没用bindService启动过service(注意:即便是startService启动的吧要命),直接调用unbindService,则会倒:

java.lang.IllegalArgumentException: Service not registered: yifeiyuan.practice.practicedemos.service.ServiceActivity$1@535f696c
  1. 若都用bindService启动了,则会已service

D/MyService: onUnbind:
D/MyService: onDestroy:

PS:如果非调用onUnbind,直接关掉Activity,跟unBind效果同样,也就是说两者生命周期相同,共存亡.

总的来看此间,我发现不行奇怪的是,我们ServiceConnection里的onServiceDisconnected方并没于调用.
于是乎跟了转艺术的说明:

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 <em>not</em> remove the ServiceConnection itself -- this
binding to the service will remain active, and you will receive a call
to {@link #onServiceConnected} when the Service is next running.

官方文档中也来提到:
Android
系统会当与劳务之连意外中断时(例如当服务崩溃或吃终止时)调用该方式。当客户端取消绑定时,系统“绝对不见面”调用该办法。

友善尝试去装界面已服务,强杀应用,也无察觉其调用!.

startService和bindService组合启动

先start后bind:

D/MyService: onCreate:
D/MyService: onStartCommand:
D/MyService: onBind:
D/MyService: onServiceConnected()
D/MyService: dosth:

品尝了解绑service:

  1. 先stop 效果:
    Service停止了(运行界面看不到Service),但是尚未onDestory的日志,即没有销毁

  2. 再unbind 效果: 输出onUnbindonDestroy,并销毁

  3. 先unbind 效果:输出日志onUnbind,没销毁

  4. 后stop 效果:输出日志onDestroy Service停止了,并销毁

结果: unbind后出现onUnbind,stop后出现onDestroy.

这就是说是是为何呢?
因为:服务产生零星种状态,一种已启动,另外一栽已绑定,并且当且仅当服务没有状态时才见面销售毁.

start和bind的区别

  1. start启动之service与组件生命周期无关,bind的service与组件的生命周期绑定,共存亡
  2. start给service一栽既开行之状态,bind给的是绑定状态
  3. 广播不克绑定service,但能启动service

此外有回调

我随Home回桌面的时光,回调了onTrimMemory,其他小不知.

D/MyService: onCreate:
D/MyService: onBind:
D/MyService: onServiceConnected()
D/MyService: dosth:
D/MyService: onTrimMemory:

于前台运行服务

眼前说及service是后台,所以呢service可能会见为大死.
前台服务让看是用户积极发现及的平栽服务,因此在内存不足时,系统也不见面设想用那个停止。
前台服务得也状态栏提供通知!

这种异常广阔,比如网易云音乐广播音乐的下即便见面出通知于通知栏~

通过startForeground来受服务运行为前台:

Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),System.currentTimeMillis());
Intent notificationIntent = new Intent(this, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, getText(R.string.notification_title),getText(R.string.notification_message), pendingIntent);
startForeground(ONGOING_NOTIFICATION_ID, notification);

得经过stopForeground(boolean removeNotification)来停止.
removeNotification代表 是否为抹状态栏通知
要小心的凡: 此方法绝对免会见已服务。
但是,如果你于服务在前台运行时用那息,则通呢会见给删。

Service通信

Service与Activity通信的不外乎前所说的bind进行绑定之外,还足以选择:

  1. 发送广播
  2. 利用EventBus/Otto等事件订阅发送框架(推荐者,更加方便)

越进程通信(IPC):

  1. AIDL
  2. Messenger

法定材料:
运Messenger是实行过程中通信 (IPC) 的极度简便方法,因为 Messenger
会在单一线程中创造包含有请求的排,这样您就不必对服务开展线程安全设计。

这些AIDL跟Messenger的例子官网还起,就无写了,官方的素材总是太好的~

PS: Android Interface Definition Language (AIDL)

处理Service的onStartCommand返回值

来自官方文档:
onStartCommand()
方法必须返回整型数,用于描述系统应怎当服务已的图景下连续运行服务.

打 onStartCommand() 返回的价值必须是以下常量之一:

  • START_NOT_STICKY
    如果系统在 onStartCommand() 返回后止劳动,则只有有悬挂于 Intent
    要传送,否则系统 不见面重建服务
    及时是极其安全之选取项,可以
    避免以非必要经常与以能够轻松又开所有未到位的课业时运行服务
  • START_STICKY
    倘系统于 onStartCommand() 返回后停劳动,则会 重建服务并调用
    onStartCommand()
    ,可是绝对不见面重传递最后一个 Intent.
    反而,除非有悬挂于 Intent 要启动服务(在这种状况下,将传递这些 Intent
    ),否则系统会透过 空Intent 调用 onStartCommand()。
    当下适用于
    切莫执行命令、但无限期运行并等候作业的媒体播放器(或相近服务)
  • START_REDELIVER_INTENT
    若果系统以 onStartCommand() 返回后止服务,则会 重建服务,并通过
    传递让服务之尾声一个 Intent 调用 onStartCommand()
    旁挂于 Intent
    均依次传递。这适用于主动履行相应马上过来的作业(例如下载文件)的服务。

小结:

  1. START_STICKY,START_REDELIVER_INTENT 会重开服务
  2. START_STICKY 会传递null的intent
  3. START_REDELIVER_INTENT 会传递最后一个intent

总结

诶,学android一年了才来学Service也算为跪了,平时啊略用到service就就此来下充斥文件.
前面说到service是主线程运行的,还欲团结开班线程,而且基本上线程不安全,很坑,还好我们还有IntentService.
属下去就上IntentService去~

IntentService的记已写了了,在这里,欢迎阅读~~

再次多材料

  1. 绑定服务
  2. Android Interface Definition
    Language(AIDL)
  3. http://blog.csdn.net/guolin\_blog/article/details/11952435
  4. http://blog.csdn.net/guolin\_blog/article/details/9797169

除此以外欢迎关注:
我的Github
自家之微博
自身的微信公众号:

微信公众号

相关文章