一、概述

Service是四大组件之一。它主要用于在后台执行耗时的逻辑,即使用户切换到其他应用甚至退出应用,它也能继续在后台运行。

下面主要介绍了service的两种形式启动和绑定 ,并通过简单例子说明了主要过程和用法。还包含服务与线程,服务的强制停止与前台服务等。

二、Service的主要过程

1.Service启动有两种形式:

(1).通过 startService() 启动 服务。一旦启动,服务即处于“启动”状态,服务即可在后台无限期运行,即使启动服务的组件已被销毁也不受影响。 已启动的服务通常是执行单一操作,而且不会将结果返回给调用方。

(2).通过 bindService() 绑定 到服务时,服务即处于“绑定”状态。绑定服务提供了一个客户端-服务器接口,允许组件与服务进行交互、发送请求、获取结果,甚至是利用进程间通信 (IPC) 跨进程执行这些操作。 仅当与另一个应用组件绑定时,绑定服务才会运行。 多个组件可以同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。

接下来,通过简单代码 说明下这两种形式的大致过程。下图是Service的生命周期,比较清晰。

          图1

2. Service基本用法:

(1) Service最重要的是自定义的服务类,继承android.app.Service。实现上述图片 Service生命周期包含的主要过程的方法,onCreate()  onStartCommand()  onBind()  onUnbind()  onDestroy()。

onStartCommand()
当另一个组件(如 Activity)通过调用 startService() 请求启动服务时,系统将调用此方法。一旦执行此方法,服务即会启动并可在后台无限期运行。 如果您实现此方法,则在服务工作完成后,需要由您通过调用 stopSelf() 或 stopService() 来停止服务。(如果您只想提供绑定,则无需实现此方法。)
onBind()
当另一个组件想通过调用 bindService() 与服务绑定时,系统将调用此方法。在此方法的实现中,您必须通过返回 IBinder 提供一个接口,供客户端用来与服务进行通信。请务必实现此方法,但如果您并不希望允许绑定,则应返回 null。
onCreate()
首次创建服务时,系统将调用此方法来执行一次性设置程序(在调用 onStartCommand() 或 onBind() 之前)。如果服务已在运行,则不会调用此方法。
onDestroy()
当服务不再使用且将被销毁时,系统将调用此方法。服务应该实现此方法来清理所有资源,如线程、注册的侦听器、接收器等。 这是服务接收的最后一个调用。

下面通过简单的例子,大致说明下启动服务(startService)和绑定服务(bindService)

(2).启动服务--startService(Intent intent)

创建TestService服务类,仅在主要方法里添加一些log.

package com.flx.testservice;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log; public class TestService extends Service {
final private static String TAG = "flx_TestServer"; @Override
public void onCreate() {
Log.d(TAG, "TestServer thread id =" + Thread.currentThread().getId());
Log.d(TAG, "onCreate");
super.onCreate();
} @Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand flags=" + flags + ";startId=" + startId);
stopSelf();
/*返回变量 用于描述系统应该如何在服务终止的情况下继续运行服务
START_NOT_STICKY
除非有挂起 Intent 要传递,否则系统不会重建服务。这是最安全的选项,可以避免在不必要时以及应用能够轻松重启所有未完成的作业时运行服务。
START_STICKY
会重建服务并调用onStartCommand(),但不会重新传递最后一个 Intent。这适用于不执行命令、但无限期运行并等待作业的媒体播放器(或类似服务)。
START_REDELIVER_INTENT
会重建服务,并通过传递给服务的最后一个 Intent 调用 onStartCommand()。这适用于主动执行应该立即恢复的作业(例如下载文件)的服务。
*/
return super.onStartCommand(intent, flags, startId);
} @Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind");
return null;
} @Override
public boolean onUnbind(Intent intent) {
Log.d(TAG, "onUnbind");
return super.onUnbind(intent);
} @Override
public void onDestroy() {
Log.d(TAG, "onDestroy");
super.onDestroy();
}
}

在AndroidManifest.xml中声明service

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.flx.testservice"> <application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name="com.flx.testservice.MainActivity"
android:label="@string/title_activity_main"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity> /*
android:exported="false"表示阻止被其他应用隐式调用,只能自己应用调用
*/
<service android:name=".TestService"
android:exported="true" /> </application> </manifest>

添加MainActivity类和布局

package com.flx.testservice;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button; public class MainActivity extends Activity implements View.OnClickListener {
final private static String TAG = "flx_TestServer";
private Button mStartServerBtn;
private Button mStopServerBtn; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); Log.d(TAG, "MainActivity thread id =" + Thread.currentThread().getId()); setContentView(R.layout.activity_main); mStartServerBtn = findViewById(R.id.start_service_btn);
mStopServerBtn = findViewById(R.id.stop_service_btn); mStartServerBtn.setOnClickListener(this);
mStopServerBtn.setOnClickListener(this);
} @Override
public void onClick(View v) {
Intent serverIntent = new Intent(this, TestService.class);
switch (v.getId()) {
case R.id.start_service_btn:
startService(serverIntent);
break;
case R.id.stop_service_btn:
stopService(serverIntent);
break;
}
}
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" > <Button
android:id="@+id/start_service_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:text="StartService" /> <Button
android:id="@+id/stop_service_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:text="StopService" />
</LinearLayout>

Activity界面效果:

            图2

启动服务:

点击StartService按钮,在点击StopService按钮。打印出来的log如下:

2019-07-28 04:08:53.307 19866-19866/com.flx.testservice D/flx_TestServer: onCreate
2019-07-28 04:08:53.312 19866-19866/com.flx.testservice D/flx_TestServer: onStartCommand flags=0;startId=1
2019-07-28 04:10:10.025 19866-19866/com.flx.testservice D/flx_TestServer: onDestroy

从代码和log看,通过点击StartService按钮,Acitivity组件调用startService(Intent intent)启动服务, 然后onCreate()  onStartCommand()依次执行,Service的具体执行逻辑就可以放在这两个里面。点击StopService按钮,组件调用stopService(Intent intent) 停止服务,onDestroy()被回调。符合图1 左边部分(启动服务生命周期)过程。

点击StartService按钮3次,在点击StopService按钮。打印出来的log如下:

2019-07-28 04:13:02.272 19866-19866/com.flx.testservice D/flx_TestServer: onCreate
2019-07-28 04:13:02.277 19866-19866/com.flx.testservice D/flx_TestServer: onStartCommand flags=0;startId=1
2019-07-28 04:13:04.025 19866-19866/com.flx.testservice D/flx_TestServer: onStartCommand flags=0;startId=2
2019-07-28 04:13:04.714 19866-19866/com.flx.testservice D/flx_TestServer: onStartCommand flags=0;startId=3
2019-07-28 04:13:15.569 19866-19866/com.flx.testservice D/flx_TestServer: onDestroy

Service中的onCreate()只在首次创建服务时调用, 如果服务已经在运行了则不会再调用。它在onStartCommand()(和onBind() 后面可以看到)之前。 

停止服务:

启动服务 可在后台无限运行,即使启动服务的组件已经销毁(除非系统资源紧张,系统收回了内存资源而被销毁)。因此,服务必须自己停止,两种方式,1是服务自身调用stopSelf()自行停止运行,另一种是组件通过调用stopService(Intent intent)来停止。

*但是,如果服务同时处理多个 onStartCommand() 请求,则不应在处理完一个启动请求之后停止服务,因为可能已经收到了新的启动请求(在第一个请求结束时停止服务会终止第二个请求)。为了避免这一问题,可以使用 stopSelf(int) 确保服务停止请求始终是最近的启动请求。也就说,在调用 stopSelf(int) 时,传递与停止请求的 ID 对应的启动请求的 ID(传递给 onStartCommand() 的 startId)。如果调用的 stopSelf(int) 与之前服务收到了新的启动请求,ID 不匹配,服务也就不会停止

做个简单的验证:

如点击3次StartService,在点击StopService,在点击StartService,log如下

2019-07-27 10:05:49.677 28103-28103/com.flx.testservice D/flx_TestServer: onCreate
2019-07-27 10:05:49.683 28103-28103/com.flx.testservice D/flx_TestServer: onStartCommand flags=0;startId=1
2019-07-27 10:05:51.205 28103-28103/com.flx.testservice D/flx_TestServer: onStartCommand flags=0;startId=2
2019-07-27 10:05:51.866 28103-28103/com.flx.testservice D/flx_TestServer: onStartCommand flags=0;startId=3
2019-07-27 10:05:54.610 28103-28103/com.flx.testservice D/flx_TestServer: onDestroy
2019-07-27 10:05:55.603 28103-28103/com.flx.testservice D/flx_TestServer: TestServer thread id =2
2019-07-27 10:05:55.603 28103-28103/com.flx.testservice D/flx_TestServer: onCreate
2019-07-27 10:05:55.607 28103-28103/com.flx.testservice D/flx_TestServer: onStartCommand flags=0;startId=1

可以看出startId是onStartCommand执行的次数有关。点击StopService是组件调用的stopService,不管执行了几次启动服务,都会直接停止服务。

下面不点击StopService的按钮,在onStartCommand中有加stopSelf(5); 当startId=5时,ID匹配了会自己停止服务,其他情况不会停止。log如下,是符合的。

2019-07-27 10:11:51.214 28103-28103/com.flx.testservice D/flx_TestServer: onCreate
2019-07-27 10:11:51.218 28103-28103/com.flx.testservice D/flx_TestServer: onStartCommand flags=0;startId=1
2019-07-27 10:11:55.993 28103-28103/com.flx.testservice D/flx_TestServer: onStartCommand flags=0;startId=2
2019-07-27 10:11:56.662 28103-28103/com.flx.testservice D/flx_TestServer: onStartCommand flags=0;startId=3
2019-07-27 10:11:57.405 28103-28103/com.flx.testservice D/flx_TestServer: onStartCommand flags=0;startId=4
2019-07-27 10:11:58.159 28103-28103/com.flx.testservice D/flx_TestServer: onStartCommand flags=0;startId=5
2019-07-27 10:11:58.181 28103-28103/com.flx.testservice D/flx_TestServer: onDestroy

(3) 绑定服务---bindService

最开始已经介绍了启动服务和绑定服务。

要创建绑定服务,首先必须定义指定客户端如何与服务通信的接口。 服务与客户端之间的这个接口必须是 IBinder 的实现,并且服务必须从 onBind() 回调方法返回它。一旦客户端收到 IBinder,即可开始通过该接口与服务进行交互。

多个客户端可以同时绑定到服务。客户端完成与服务的交互后,会调用 unbindService() 取消绑定。一旦没有客户端绑定到该服务,系统就会销毁它(不必按通过 onStartCommand() 启动的服务那样来停止绑定服务)。

上述代码添加绑定服务相关代码和log,由于模拟多个客户端,所以创建了2个组件和ServiceConnection.

TestService.java

package com.flx.testservice;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log; public class TestService extends Service {
final private static String TAG = "flx_TestServer"; @Override
public void onCreate() {
Log.d(TAG, "TestServer thread id =" + Thread.currentThread().getId());
Log.d(TAG, "onCreate");
super.onCreate();
} @Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand flags=" + flags + ";startId=" + startId);
stopSelf();
/*返回变量 用于描述系统应该如何在服务终止的情况下继续运行服务
START_NOT_STICKY
除非有挂起 Intent 要传递,否则系统不会重建服务。这是最安全的选项,可以避免在不必要时以及应用能够轻松重启所有未完成的作业时运行服务。
START_STICKY
会重建服务并调用onStartCommand(),但不会重新传递最后一个 Intent。这适用于不执行命令、但无限期运行并等待作业的媒体播放器(或类似服务)。
START_REDELIVER_INTENT
会重建服务,并通过传递给服务的最后一个 Intent 调用 onStartCommand()。这适用于主动执行应该立即恢复的作业(例如下载文件)的服务。
*/
return super.onStartCommand(intent, flags, startId);
} @Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind");
return binder;
} @Override
public boolean onUnbind(Intent intent) {
Log.d(TAG, "onUnbind");
return super.onUnbind(intent);
} @Override
public void onDestroy() {
Log.d(TAG, "onDestroy");
super.onDestroy();
} private MyBinder binder = new MyBinder();
int testNum = ;
class MyBinder extends Binder{
public void test(int num) {
Log.d(TAG, "MyBinder test()="+(testNum+=
num));
}
}

}

MainActivity.java

package com.flx.testservice;

import android.app.Activity;
import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.widget.Button; public class MainActivity extends Activity implements View.OnClickListener {
final private static String TAG = "flx_TestServer"; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); Log.d(TAG, "MainActivity thread id =" + Thread.currentThread().getId()); setContentView(R.layout.activity_main); Button mStartServerBtn = findViewById(R.id.start_service_btn);
Button mStopServerBtn = findViewById(R.id.stop_service_btn);
Button mBindServerBtn = findViewById(R.id.bind_service_btn);
Button mBindServerBtn2 = findViewById(R.id.bind_service_btn2);
Button mUnbindServerBtn = findViewById(R.id.unbind_service_btn);
Button mUnbindServerBtn2 =
findViewById(R.id.unbind_service_btn2); mStartServerBtn.setOnClickListener(this);
mStopServerBtn.setOnClickListener(this);
mBindServerBtn.setOnClickListener(this);
mBindServerBtn2.setOnClickListener(this);
mUnbindServerBtn.setOnClickListener(this);
mUnbindServerBtn2.setOnClickListener(this
);
} @Override
public void onClick(View v) {
Intent serverIntent = new Intent(this, TestService.class);
switch (v.getId()) {
case R.id.start_service_btn:
startService(serverIntent);
break;
case R.id.stop_service_btn:
stopService(serverIntent);
break;
case R.id.bind_service_btn:
bindService(serverIntent, mServerConnect, Service.BIND_AUTO_CREATE);
break;
case R.id.bind_service_btn2:
bindService(serverIntent, mServerConnect2, Service.BIND_AUTO_CREATE);
break;
case R.id.unbind_service_btn:
unbindService(mServerConnect);
break;
case R.id.unbind_service_btn2:
unbindService(mServerConnect2);
break
;
}
} private ServiceConnection mServerConnect2 = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG, "ServiceConnection2 onServiceConnected");
TestService.MyBinder myBinder = (TestService.MyBinder) service;
myBinder.test();
} @Override
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG, "ServiceConnection2 onServiceDisconnected");
}
}; private ServiceConnection mServerConnect = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG, "ServiceConnection onServiceConnected");
TestService.MyBinder myBinder = (TestService.MyBinder) service;
myBinder.test();
} @Override
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG, "ServiceConnection onServiceDisconnected"
);
}
};

}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" > <Button
android:id="@+id/start_service_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:text="StartService" /> <Button
android:id="@+id/stop_service_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:text="StopService" /> <Button
android:id="@+id/bind_service_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:text="BindService" /> <Button
android:id="@+id/bind_service_btn2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:text="BindService2"/> <Button
android:id="@+id/unbind_service_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:text="UnbindService"/> <Button
android:id="@+id/unbind_service_btn2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:text="UnbindService2"/>

</LinearLayout>

效果界面

            图3

点击BindService按钮,组件调用的bindService()绑定服务。再点击UnbindService按钮,组件调用unbindService解除绑定。

2019-07-28 04:45:52.546 22060-22060/com.flx.testservice D/flx_TestServer: onCreate
2019-07-28 04:45:52.549 22060-22060/com.flx.testservice D/flx_TestServer: onBind
2019-07-28 04:45:52.577 22060-22060/com.flx.testservice D/flx_TestServer: ServiceConnection onServiceConnected
2019-07-28 04:45:52.577 22060-22060/com.flx.testservice D/flx_TestServer: MyBinder test()=10
2019-07-28 04:45:55.043 22060-22060/com.flx.testservice D/flx_TestServer: onUnbind
2019-07-28 04:45:55.045 22060-22060/com.flx.testservice D/flx_TestServer: onDestroy

绑定及解除绑定依次执行了onCreate(),onBind(),onUnbind(),onDestory()。符合图1右边部分的 绑定服务的生命周期。绑定过的组件,再次点击也是无效的,不能多此绑定。

点击BindService按钮,再点击BindService2按钮,点击UnbindService按钮或者点击UnbindService2按钮,效果如下:

2019-07-28 04:59:18.137 22837-22837/com.flx.testservice D/flx_TestServer: onCreate
2019-07-28 04:59:18.139 22837-22837/com.flx.testservice D/flx_TestServer: onBind
2019-07-28 04:59:18.152 22837-22837/com.flx.testservice D/flx_TestServer: ServiceConnection onServiceConnected
2019-07-28 04:59:18.152 22837-22837/com.flx.testservice D/flx_TestServer: MyBinder test()=10
2019-07-28 04:59:19.029 22837-22837/com.flx.testservice D/flx_TestServer: ServiceConnection2 onServiceConnected
2019-07-28 04:59:19.029 22837-22837/com.flx.testservice D/flx_TestServer: MyBinder test()=20

所以如果不是所有绑定的都解除绑定,服务是不会销毁停止。当两个绑定都解除绑定后,服务会被销毁(BindService->BindService2->UnbindService->UnbindService2)

2019-07-28 05:01:50.802 23164-23164/com.flx.testservice D/flx_TestServer: onCreate
2019-07-28 05:01:50.803 23164-23164/com.flx.testservice D/flx_TestServer: onBind
2019-07-28 05:01:50.815 23164-23164/com.flx.testservice D/flx_TestServer: ServiceConnection onServiceConnected
2019-07-28 05:01:50.815 23164-23164/com.flx.testservice D/flx_TestServer: MyBinder test()=10
2019-07-28 05:01:51.453 23164-23164/com.flx.testservice D/flx_TestServer: ServiceConnection2 onServiceConnected
2019-07-28 05:01:51.453 23164-23164/com.flx.testservice D/flx_TestServer: MyBinder test()=20
2019-07-28 05:01:52.738 23164-23164/com.flx.testservice D/flx_TestServer: onUnbind
2019-07-28 05:01:52.745 23164-23164/com.flx.testservice D/flx_TestServer: onDestroy

注:如果服务已解除绑定,再执行解除绑定会报错。

java.lang.IllegalArgumentException: Service not registered: com.flx.testservice.MainActivity$2@72e6895

bindService是有返回值的,所以在解除绑定前做一个判断就可以避免了。

返回值的说明---true if the system is in the process of bringing up a service that your client has permission to bind to; false if the system couldn't find the service or if your client doesn't have permission to bind to it. If this value is true, you should later call unbindService(ServiceConnection) to release the connection.

ManiActivity中修改如下即可:

   private boolean mIsConn = false;
private boolean mIsConn2 = false
;
@Override
public void onClick(View v) {
Intent serverIntent = new Intent(this, TestService.class);
switch (v.getId()) {
case R.id.start_service_btn:
startService(serverIntent);
break;
case R.id.stop_service_btn:
stopService(serverIntent);
break;
case R.id.bind_service_btn:
mIsConn=bindService(serverIntent, mServerConnect, Service.BIND_AUTO_CREATE);
break;
case R.id.bind_service_btn2:
mIsConn2=bindService(serverIntent, mServerConnect2, Service.BIND_AUTO_CREATE);
break;
case R.id.unbind_service_btn:
if (mIsConn){
mIsConn = false
;
unbindService(mServerConnect);
}
break;
case R.id.unbind_service_btn2:
if (mIsConn2) {
mIsConn2 = false
;
unbindService(mServerConnect2);
}
break;
}
Log.d(TAG, "MainActivity after click mIsConn="+mIsConn+";mIsConn2="+mIsConn2);
}

三、其他注意

1.Service和线程

2019-07-28 07:26:21.978 27802-27802/com.flx.testservice D/flx_TestServer: MainActivity thread id =2
2019-07-28 07:26:24.663 27802-27802/com.flx.testservice D/flx_TestServer: MainActivity after click mIsConn=true;mIsConn2=false
2019-07-28 07:26:24.703 27802-27802/com.flx.testservice D/flx_TestServer: TestServer thread id =2

上述例子中有打印Activity和Service的线程id, 是一样的。

默认情况下,服务是在应用的主线程中运行的。服务在其托管进程的主线程中运行,它既不创建自己的线程,也不在单独的进程中运行(除非另行指定)。因此,如果服务执行的是密集型或阻塞性操作,则仍应在服务内创建新线程。服务和线程没有直接关系。

服务如果不停止会一直运行在后台(特殊情况下面说),即使Activity被销毁,只要进程还在 服务就能一直运行,这是线程做不到的。

2.强制停止服务

如果系统内存不足,达到一定条件,一直运行的服务可能被强制停止。如果不主动停止,服务在后台一直运行下去,随着服务在后台运行时间越来越长,系统会不断降低服务在后台列表的位置,当系统资源不足情况下,会越容易被强制停止 释放资源被系统回收。

那么如何尽量保证服务不会被强制停止呢?(比较正常合理的情况)

(1)如果服务绑定到具有用户焦点的Activity上,则不太可能被强制停止。

(2)onStartCommand的返回值 可以决定当系统资源 再次足够可用了,是否重启服务或已什么方式重启服务。具体的值在上述TestService中onStartCommand()方法中 注释里详细说明了。

(3)设置为前台服务。

前台服务被认为是用户主动意识到的一种服务,因此在内存不足时,系统也不会考虑将其终止。 前台服务必须为状态栏提供通知,除非服务停止或从前台移除,否则不能清除通知。例如,状态栏中的通知可能表示正在播放的歌曲,并允许用户启动 Activity 来与音乐播放器进行交互。

设置前台服务:

startForeground(int id, Notification notification), 注意,id不能为0

大致如下,在Service类onCreate()中添加的。

@Override
public void onCreate() {
Log.d(TAG, "TestServer thread id =" + Thread.currentThread().getId());
Log.d(TAG, "onCreate");
String CHANNEL_ID = "test_service_channelId";
String CHANNEL_NAME = "test_service";
NotificationChannel notificationChannel = new NotificationChannel(CHANNEL_ID,CHANNEL_NAME, NotificationManager.IMPORTANCE_LOW);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.createNotificationChannel(notificationChannel);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentTitle("TestService Notification ABC")
.setContentText("AAAAA")
.setCategory(Notification.CATEGORY_SERVICE)
.build();
startForeground(
, notification);
super.onCreate();
}

因为用的Andoid P调试的,通知的创建如上代码。 注意别忘了添加权限。<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

效果如图

                图4

即使最近任务中关闭应用,任务也是运行的,通知栏一直存在。停止任务后才会消失。

停止前台服务:

停止前台服务使用stopForeground(boolean removeNotification),方法中的boolean值表示是否移除通知栏的通知,该方法不会停止服务。但如果服务被停止了,则前台服务的通知也会被移除。

Android_四大组件之Service的更多相关文章

  1. Android四大组件之Service

    Android四大组件之Service Android支持服务的概念,服务是在后台运行的组件,没有用户界面,Android服务可用有与活动独立的生命周期.Android支持两种类型的服务: 本地服务: ...

  2. Java乔晓松-android的四大组件之一Service(服务的绑定)

    android的四大组件之一Service(服务的绑定) 怎么绑定服务,又怎么解除服务,代码如下: MainActivity.java源码: package com.example.lesson14_ ...

  3. 【Android开发日记】之入门篇(五)——Android四大组件之Service

    这几天忙着驾校考试,连电脑都碰不到了,今天总算告一段落了~~Service作为Android的服务组件,默默地在后台为整个程序服务,辅助应用与系统中的其他组件或系统服务进行沟通.它跟Activity的 ...

  4. Android 四大组件之Service

    ---恢复内容开始--- 1,Service的生命周期

  5. Android成长日记-Android四大组件之Service组件的学习

    1.什么是Service? Service是Android四大组件中与Activity最相似的组件,它们都代表可执行的程序,Service与Activity的区别在于:Service一直在后台运行,它 ...

  6. 谈Android四大组件之Service篇

    Service简介 Service是Android系统中的四大组件之一,它是一种长生命周期的,没有可视化界面,运行于后台的一种服务程序.Service必须在AndroidManifest.xml中声明 ...

  7. Android 四大组件之service与Broadcast

    Android 四大组件之一:service: Service有五个生命周期:onCreat,onStartCommand, onBind,onUnbind, onDestroy 主要有绑定和非绑定两 ...

  8. Android四大组件之一Service介绍-android学习之旅(十二)

    基本概念: service是android四大组件之一,运行在后台执行耗时操作,并不提供用户界面.其他组件如acticity可以通过startService启动该组件,也可以通过bindService ...

  9. 四大组件之Service小结

    总结提高,与君共勉! 1.Service是什么 Service 是看不到界面的,,就是一个没有界面的Activity, 并且长期在后台运行的一个组件.. 由于ANR对Activity和Broadcas ...

随机推荐

  1. HTML(css 样式)

    1.CSS 可以通过以下方式添加到 HTML 中: 内联样式 -- 在 HTML 元素中使用 "style" 属性 内部样式表 -- 在 HTML 文档头部 <head> ...

  2. RabbitMQ的使用(一)- RabbitMQ服务安装

    RabbitMQ的使用(一)- RabbitMQ服务安装 作者:markjiang7m2 原文地址:https://www.cnblogs.com/markjiang7m2/p/12769627.ht ...

  3. socket编程之并发回射服务器3

    在socket编程之并发回射服务器一文中,服务器采用多进程的方式实现并发,本文采用多线程的方式实现并发. 多线程相关API: // Compile and link with -pthread int ...

  4. Circle of Monsters(贪心)

    n个怪物围成一圈,每个怪物有自己的血量和爆炸伤害. 怪物在死后会对下一个怪物造成爆炸伤害,又死了又可以爆炸...... 你每发子弹可以对怪物造成1点伤害,求杀死所有怪物的最小子弹数. 传送门 \(\c ...

  5. P2309(逆序对)

    传送门 描述:给定一个序列长n,求多少子串和大于零. \(一开始一定会想到根据前缀和优化,枚举起点和中点O(n)解决\) \(那更高效的方法呢?实际上,我们上面就是要求S_i-S_j>0的数量\ ...

  6. 基于KepServer实现与S7-1200PLC之间的通信

    对于学习上位机开发,有一种通信方式是必须要了解的,那就是OPC是OLE for Process Control的简称,然而随着技术的不断发展,人们开始对它有了新的定义,比如Open Platform ...

  7. 201771010113 李婷华 《面向对象程序设计(Java)》第十七周总结

    一.理论知识部分 Java 的线程调度采用优先级策略:优先级高的先执行,优先级低的后执行:多线程系统会自动为每个线程分配一个优先级,缺省时,继承其父类的优先级: 任务紧急的线程,其优先级较高: 同优先 ...

  8. thrift的使用

    简介 thrift 原来是facebook的rpc框架,根据数据结构和接口描述生成多种语言的接口,方便使用多种语言进行开发,详细信息这里不再赘述,下文以一个简单的代码(C++)示例来介绍使用方法. 示 ...

  9. 【不断更新】mysql经典50道题自我练习

    mysql经典50道题自我练习 测试数据和练习题均转载自CSDN博主@启明星的指引的文章sql语句练习50题(Mysql版),用于mysql的每日自我练习 表名和字段 –1.学生表 Student(s ...

  10. 图形学_opengl纹理映射

    学了半学期的图形学,除了几个用python或是matlab比较方便的实验外,用的大多数是opengl,在这总结一下纹理贴图实验中opengl的用法. 1.编译器连接静态库 有用到glaux.h的程序, ...