一、Service是什么
Service是Android中实现程序后台运行的解决方案,他非常适合是去执行那些不需要和用户交互而且还要长期运行的任务。Service的运行不依赖于任何用户界面,即使程序被切换到后台,或者用户打开了另一个应用程序,Service仍然能够保持独立运行。不过需要注意的是,Service并不是运行在一个独立的进程当中,而是依赖于创建Service时所在的应用程序进程。当某个应用程序被杀掉时,所有依赖该进程的Service也会停止运行。
Service基本上分为两种形式:
-
本地Service
该服务依附在主进程上而不是独立的进程,这样在一定程度上节约了资源,另外本地服务因为是在同一进程因此不需要IPC
,也不需要AIDL
。相应bindService
会方便很多,当主进程被Kill后,服务便会终止。一般使用在音乐播放器播放等不需要常驻的服务。指的是服务和启动服务的activity在同一个进程中。 -
远程Service
该Service是独立的进程,对应进程名格式为所在包名加上你指定的android:process字符串。一般定义方式android:process=":service"
由于是独立的进程,因此在activity所在进程被Kill的时候,该Service依然在运行,不受其他进程影响,有利于为多个进程提供服务,具有较高的灵活性。由于是独立的进程,会占用一定资源,并且使用AIDL
进行IPC
比较麻烦。一般用于系统的Service,这种Service是常驻的。指的是Service和启动Service的activity不在同一个进程中。
注意(启动本地Service用的是显式启动; 远程Service的启动要用到隐式启动)
二、Service的两种状态
-
启动状态
当应用组件(如 Activity)通过调用startService()
启动Service时,Service即处于“启动”状态。一旦启动,Service即可在后台无限期运行,即使启动Service的组件已被销毁也不受影响,除非手动调用才能停止Service, 已启动的Service通常是执行单一操作,而且不会将结果返回给调用方。 -
绑定状态
当应用组件通过调用bindService()
绑定到Service时,Service即处于“绑定”状态。绑定Service提供了一个客户端-服务器接口
,允许组件与服务进行交互、发送请求、获取结果,甚至是利用进程间通信 (IPC) 跨进程执行这些操作。 仅当与另一个应用组件绑定时,绑定服务才会运行。 多个组件可以同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。
三、Service的声明
不管是哪一种的 service ,也都需要在 AndroidManifest.xml中声明
<service android:name=".myservice"
android:enabled="true"
android:exported="true"
android:icon="@drawable/background_blue"
android:label="string"
android:process="string"
android:permission="string">
</service>
属性 | 作用 |
---|---|
android:exported | 表示是否允许除了当前程序之外的其他程序访问这个服务 |
android:enabled | 表示是否启用这个服务 |
android:permission | 是权限声明 |
android:process | 是否需要在单独的进程中运行,当设置为android:process=”:remote”时,代表Service在单独的进程中运行。 注意:冒号 : 很重要,它的意思是指要在当前进程名称前面附加上当前的包名,所以remote 和:remote 不是同一个意思,前者的进程名称为remote ,而后者的进程名称为App-packageName:remote
|
android:isolatedProcess | 设置 true 意味着,服务会在一个特殊的进程下运行,这个进程与系统其他进程分开且没有自己的权限。与其通信的唯一途径是通过服务的API(bind and start)。 |
四、Service 启动服务 以及 终止服务
首先要创建服务,必须创建 Service 的子类(或使用它的一个现有子类如IntentService)。在实现中,我们需要重写一些回调方法,以处理服务生命周期的某些关键过程,下面我们通过简单案例来分析需要重写的回调方法有哪些?
public class MyService extends Service {
private static final String TAG = "myservice";
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
Log.e(TAG, "onCreate:");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand:");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.e(TAG, "onDestroy:");
super.onDestroy();
}
}
启动:
Intent start = new Intent(this, MyService.class);
startService(start);
关闭:
Intent stop = new Intent(this, MyService.class);
stopService(stop);
回调接口:
-
onBind()
当另一个组件想通过调用bindService()
与Service
绑定(例如执行 RPC)时,系统将调用此方法。在此方法的实现中,必须返回 一个IBinder
接口的实现类,供客户端用来与服务进行通信。无论是启动状态还是绑定状态,此方法必须重写,但在启动状态的情况下直接返回 null。 -
onCreate()
首次创建Service时,系统将调用此方法来执行一次性设置程序(在调用onStartCommand()
或onBind()
之前)。如果Service已在运行,则不会调用此方法,该方法只调用一次。 -
onStartCommand()
当另一个组件(如 Activity)通过调用startService()
请求启动Service时,系统将调用此方法。一旦执行此方法,Service即会启动并可在后台无限期运行。 如果自己实现此方法,则需要在Service工作完成后,通过调用stopSelf()
或stopService()
来停止Service。(在绑定状态下,无需实现此方法。) -
onDestroy()
当Service不再使用且将被销毁时,系统将调用此方法。Service应该实现此方法来清理所有资源,如线程、注册的侦听器、接收器等,这是Service接收的最后一个调用。
五、Service绑定服务
通过第四节我们知道了启动和停止Service的基本方法,不知道你有没有发现,虽然Service是在activity里启动的,但在启动了Service之后,activity与服务基本就没有了什么关系。确实如此,我们在activity里调用了startService
方法之后启动MyService
这个服务。然后MyService
的onCreate
和onStartCommand
方法就会得到执行。之后Service会一直处于运行状态,但具体的运行的什么逻辑,活动就已经控制不了。那就是代表我们无法通过组件对Service进行控制吗?不不不 ,不是的。这时候我们就要用到我们 Service 中继承的另一个方法 onbind 方法。
绑定Service是Service的另一种变形,当Service处于绑定状态时,其代表着客户端-服务器接口中的服务器。当其他组件(如 Activity)绑定到Service时(有时我们可能需要从Activity组件中去调用Service中的方法,此时Activity以绑定的方式挂靠到Service后,我们就可以轻松地方法到Service中的指定方法),组件(如Activity)可以向Service(也就是服务端)发送请求,或者调用Service(服务端)的方法,此时被绑定的Service(服务端)会接收信息并响应,甚至可以通过绑定Service进行执行进程间通信 (即IPC,这个后面再单独分析)。与启动服务不同的是绑定Service的生命周期通常只在为其他应用组件(如Activity)服务时处于活动状态,不会无限期在后台运行,也就是说宿主(如Activity)解除绑定后,绑定Service就会被销毁。
为了实现客户端与服务器的交互,我们一般都会通过下方三种方式进行处理。
1. 扩展 Binder 类
在Service类中进行添加一个Binder
内部类,我们通过前台进行绑定后,当绑定后成功后,客户端收到binder 后,可利用他直接访问Binder
继承类中或Service中可用的公共方法。如果我们的Service只是自有应用的后台工作线程,则优先采用这种方法。前提:Service服务端与客户端相同的进程中运行。
我们这里的目的就是为了使 应用组件 能够与应用的 Service 服务进行交互。并且我们的服务仅供于本地服务的使用,不需要跨进程工作,然后我们就可以实现自有的 binder 类。
流程如下
1、创建Binder
子类,让前端能够通过Binder
类实现对Service
的调用。
2、Service
中的onBinder
方法返回Binder实例 3、在前端中的
onServiceConnected中接收返回的
Binder`实例。
public class MyService extends Service {
private static final String TAG = "myservice";
private LocalBinder mbinder = new LocalBinder();
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "onBind:" );
return mbinder;
}
public class LocalBinder extends Binder{
public MyService getservices(){
return MyService.this;
}
public void start(){
Log.e(TAG, "start:" );
}
public void end(){
Log.e(TAG, "end:" );
}
}
@Override
public void onCreate() {
Log.e(TAG, "onCreate:");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand:");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.e(TAG, "onDestroy:");
super.onDestroy();
}
public String myway(){
Log.e(TAG, "myway:hello world");
return "hello world";
}
@Override
public boolean onUnbind(Intent intent) {
Log.e(TAG, "onUnbind:");
return super.onUnbind(intent);
}
}
conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
MyService.LocalBinder binder = (MyService.LocalBinder) iBinder;
binder.start();
binder.end();
services = binder.getservices();
services.myway();
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
services = null;
Log.e(TAG, "onServiceDisconnected:");
}
};
//绑定服务
Intent intent = new Intent(this, MyService.class);
bindService(intent, conn, Service.BIND_AUTO_CREATE);
//解绑服务
Intent intent1 = new Intent(this, MyService.class);
unbindService(conn);
在上面代码中,我们在前端代码中实现了一个ServiceConnection
接口,该接口有两个方法,onServiceConnected
和onServiceDisconnected
。
onServiceConnected(ComponentName componentName, IBinder iBinder)
当我们进行绑定的时候,onbind()
方法会返回Binder
实例对象。进而我们可以对其进行调用。
onServiceDisconnected(ComponentName componentName)
Android 系统会在与服务的连接意外中断时(例如当服务崩溃或被终止时)调用该方法。注意:当客户端取消绑定时,系统“绝对不会”调用该方法。
通过Log可知,当我们第一次点击绑定Service时,LocalService服务端的
onCreate()
、onBind
方法会依次被调用,此时客户端的ServiceConnection#onServiceConnected()
被调用并返回 LocalBinder
对象,接着调用LocalBinder#getService
方法返回MyService
实例对象,此时客户端便持有了MyService
的实例对象,也就可以任意调用MyService
类中的声明公共方法了。更值得注意的是,我们多次调用bindService
方法绑定LocalService
服务端,而LocalService
的onBind
方法只调用了一次,那就是在第一次调用bindService
时才会回调onBind
方法。
2. 使用 Messenger
这是执行进程间通信 (IPC) 的最简单方法,因为 Messenger 会在单一线程中创建包含所有请求的队列,也就是说Messenger是以串行的方式处理客户端发来的消息,这样我们就不必对服务进行线程安全设计了。
前面我们了解通过扩展Binder
类来进行通信。接下来我们就来介绍一下不同进程之间的通信,我们下面就是采用最简单的方式Messenger
来进行通信,通过此来了解进程之间的通信,这也是最轻量级的方式。过程如下:
1、在service
中创建handler
,然后通过这个handler
创建Messenger
对象。
2、我们在客户端通过绑定 onBinder
函数返回 binder
对象,然后我们在创建出Messenger
对象
创建Messenger对象 两种方式:
Messenger(Binder);
Messenger(Handler);
3、通过Messenger
发送信息 mService.send(msg);
message
对象的创建方式:
Message.obtain(null, MessageService.MSG_SAY_HELLO, 0, 0)
第二个参数为 int 类型的变量以作为信息的区分。
Service
public class MessageService extends Service {
static final int MSG_SAY_HELLO = 1;
private static final String TAG = "MessageService";
class Localhandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SAY_HELLO:
Log.e(TAG, "handleMessage : accepted!");
//信息回馈
Messenger client = msg.replyTo;
Message replyMsg = Message.obtain(null, MessageService.MSG_SAY_HELLO,0,0);
Bundle bundle = new Bundle();
bundle.putString("reply", "ok~,I had receiver message from you! ");
replyMsg.setData(bundle);
try {
client.send(replyMsg);
Log.e(TAG, "handleMessage:" );
} catch (RemoteException e) {
e.printStackTrace();
}
break;
default:
super.handleMessage(msg);
}
}
}
//通过IncomingHandler对象创建一个Messenger对象,该对象是与客户端交互的特殊对象
final Messenger mMessenger = new Messenger(new Localhandler());
/**
* 当绑定Service时,该方法被调用,将通过mMessenger返回一个实现
* IBinder接口的实例对象
*/
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "onBind:");
return mMessenger.getBinder();
}
}
客户端
public class ActivityMessenger extends Activity implements View.OnClickListener {
@BindView(R.id.bindservice)
Button bindservice;
@BindView(R.id.unbindservice)
Button unbindservice;
@BindView(R.id.sendmsg)
Button sendmsg;
/**
* 与服务端交互的Messenger
*/
Messenger mService = null;
/**
* Flag indicating whether we have called bind on the service.
*/
boolean mBound;
private static final String TAG = "MessageService";
private ServiceConnection myConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.e(TAG, "onServiceConnected: ");
mService = new Messenger(iBinder);
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
mService = null;
mBound = false;
}
};
/**
* 用于接收服务器返回的信息
*/
private Messenger mRecevierReplyMsg = new Messenger(new ReceiverReplyMsgHandler());
private class ReceiverReplyMsgHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
//接收服务端回复
case MessageService.MSG_SAY_HELLO:
Log.e(TAG, "receiver message from service:" + msg.getData().getString("reply"));
break;
default:
super.handleMessage(msg);
}
}
}
public void sayHello(View v) {
if (!mBound) return;
// 创建与服务交互的消息实体Message
Message msg = Message.obtain(null, MessageService.MSG_SAY_HELLO, 0, 0);
msg.replyTo = mRecevierReplyMsg;
try {
//发送消息
mService.send(msg);
Log.e(TAG, "sayHello:");
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_messenger);
ButterKnife.bind(this);
initClick();
}
private void initClick() {
// @OnClick(R.id.bindservice)
bindservice.setOnClickListener(this);
unbindservice.setOnClickListener(this);
sendmsg.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.bindservice:
Intent intent = new Intent(this, MessageService.class);
bindService(intent, myConnection, Context.BIND_AUTO_CREATE);
Toast.makeText(this, "我们都好", Toast.LENGTH_SHORT).show();
break;
case R.id.unbindservice:
if (mBound) {
Log.e("zj", "onClick-->unbindService");
unbindService(myConnection);
mBound = false;
}
break;
case R.id.sendmsg:
sayHello(view);
break;
default:
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
还有一点就是我们的目的是为了验证不同进程之间的通信,所以我们这里需要为服务重新设置一个的单独进程。
<service
android:name=".MessageService"
android:enabled="true"
android:exported="true"
android:process=":remote"/>
可能会有一部分小伙伴会想提问,那么如果我想重新从服务端发送信息给客户端那么我应该如何操作。
其实道理也还是一样的,我们只需跟上方一样进行相同的操作就能得到我们想要的结果。我们可以只要在我们发送信息给客户端把我们的客户端的Messenger
对象也发送给Service
就可以了
重点代码摘要:
客户端
Message msg = Message.obtain(null, MessageService.MSG_SAY_HELLO, 0, 0);
msg.replyTo = mRecevierReplyMsg;
服务端
//信息回馈
Messenger client = msg.replyTo;
Message replyMsg = Message.obtain(null, MessageService.MSG_SAY_HELLO, 0, 0);
Bundle bundle = new Bundle();
bundle.putString("reply", "ok~,I had receiver message from you! ");
replyMsg.setData(bundle);
try {
client.send(replyMsg);
Log.e(TAG, "handleMessage:" );
} catch (RemoteException e) {
e.printStackTrace();
}
我们通过客户端进行绑定服务-》发送信息 通过此我们得到如下的log日志。
主线程日志:
09-28 17:51:06.273 MessageService: onServiceConnected:
09-28 17:51:12.790 MessageService: sayHello:
09-28 17:51:12.808 MessageService: receiver message from service:ok~,I had receiver message from you!
remote线程日志:
09-28 17:51:06.264 MessageService: onBind:
09-28 17:51:12.793 MessageService: handleMessage : accepted!
09-28 17:51:12.793 MessageService: handleMessage:
Messenger 进程通信图
3. 使用 AIDL
如果我们想让Service同时处理多个请求,则应该使用 AIDL。 在此情况下,Service必须具备多线程处理能力,并采用线程安全式设计。使用AIDL必须创建一个定义编程接口的 .aidl 文件。Android SDK 工具利用该文件生成一个实现接口并处理 IPC 的抽象类,随后可在Service内对其进行扩展。
绑定的细节注意点
-
多个客户端可同时连接到一个服务。不过,只有在第一个客户端绑定时,系统才会调用服务的
onBind()
方法来检索IBinder
。系统随后无需再次调用onBind()
,便可将同一IBinder
传递至任何其他绑定的客户端。当最后一个客户端取消与服务的绑定时,系统会将服务销毁。 -
通常情况下我们应该在客户端生命周期(如Activity的生命周期)的引入 (bring-up) 和退出 (tear-down) 时刻设置绑定和取消绑定操作,以便控制绑定状态下的
Service
,一般有以下两种情况:
- 如果只需要在
Activity
可见时与Service
交互,则应在onStart()
期间绑定,在onStop()
期间取消绑定。 - 如果希望 Activity 在后台停止运行状态下仍可接收响应,则可在
onCreate()
期间绑定,在onDestroy()
期间取消绑定。需要注意的是,这意味着 Activity 在其整个运行过程中(甚至包括后台运行期间)都需要使用Service
,因此如果Service位于其他进程内,那么当提高该进程的权重时,系统很可能会终止该进程。
- 应用组件(客户端)可通过调用
bindService()
绑定到Service
,Android 系统随后调用服务的onBind()
方法,该方法返回用于与Service交互的IBinder
,而该绑定是异步执行的。
六、关于启动Service与绑定Service之间的问题
-
先绑定
Service
后启动Service
如果当前Service
实例先以绑定状态运行,然后再以启动状态运行,那么绑定服务将会转为启动服务运行,这时如果之前绑定的宿主(Activity)被销毁了,也不会影响服务的运行,Service还是会一直运行下去,指定收到调用停止服务或者内存不足时才会销毁该服务。 -
先启动Service后绑定Service
如果当前Service实例先以启动状态运行,然后再以绑定状态运行,当前启动Service并不会转为绑定Service,但是还是会与宿主绑定,只是即使宿主解除绑定后,Service依然按启动Service的生命周期在后台运行,直到有Context
调用了stopService()
或是Service本身调用了stopSelf()
方法抑或内存不足时才会销毁Service。
以上两种情况显示出启动Service的优先级确实比绑定Service高一些。
最后这里有点需要特殊说明一下的,由于Service在其托管进程的主线程中运行(UI线程),它既不创建自己的线程,也不在单独的进程中运行(除非另行指定)。 这意味着,如果Service将执行任何耗时事件或阻止性操作(例如 MP3 播放或联网)时,则应在Service内创建新线程来完成这项工作,简而言之,耗时操作应该另起线程执行。只有通过使用单独的线程,才可以降低发生“应用无响应”(ANR) 错误的风险,这样应用的主线程才能专注于用户与 Activity 之间的交互, 以达到更好的用户体验。
七、前台服务以及通知发送
Service几乎都是在后台运行的,一直以来他都是默默地做着辛苦的工作。但是Service的系统优先级还是比较低的,当系统出现内存不足的情况时,就有可能会回收正在后台运行的Service。如果你希望可以一直保持运行状态,而不会由于系统内存不足的原因导致被回收,就可以考虑使用前台Service。前台Service和普通Service最大的区别就在于,他会一直有一个正在运行的图标在系统的状态栏显示,下拉状态栏后可以看到更加详细的信息,非常类似于通知的效果。当然有时候你也可能不仅仅是为了防止Service被回收掉才用前台服务,有些项目也有可能有着这样的特殊要求。
不多说先介绍两个api先
startForeground(NOTIFICATION_DOWNLOAD_PROGRESS_ID, notification);
第一个参数为int数值,只要你不要使用两个相同的int就可以 ,第二个参数为弹框对象
stopForeground(true);
只有一个boolean参数 ,关闭弹框的出现。其余我直接上案例代码
客户端
public class ForegroundActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_foreground);
Button btnStart= (Button) findViewById(R.id.startForeground);
Button btnStop= (Button) findViewById(R.id.stopForeground);
final Intent intent = new Intent(this,ForegroundService.class);
btnStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
intent.putExtra("cmd",0);//0,开启前台服务,1,关闭前台服务
startService(intent);
}
});
btnStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
intent.putExtra("cmd",1);//0,开启前台服务,1,关闭前台服务
startService(intent);
}
});
}
}
服务端
public class ForegroundService extends Service {
/**
* id不可设置为0,否则不能设置为前台service
*/
private static final int NOTIFICATION_DOWNLOAD_PROGRESS_ID = 0x0001;
private boolean isRemove=false;//是否需要移除
/**
* Notification
*/
public void createNotification(){
//使用兼容版本
NotificationCompat.Builder builder=new NotificationCompat.Builder(this);
//设置状态栏的通知图标
builder.setSmallIcon(R.mipmap.ic_launcher);
//设置通知栏横条的图标
builder.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher_round));
//禁止用户点击删除按钮删除
builder.setAutoCancel(false);
//禁止滑动删除
builder.setOngoing(true);
//右上角的时间显示
builder.setShowWhen(true);
//设置通知栏的标题内容
builder.setContentTitle("I am Foreground Service!!!");
//创建通知
Notification notification = builder.build();
//设置为前台服务
startForeground(NOTIFICATION_DOWNLOAD_PROGRESS_ID,notification);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
int i=intent.getExtras().getInt("cmd");
if(i==0){
if(!isRemove) {
createNotification();
}
isRemove=true;
}else {
//移除前台服务
if (isRemove) {
stopForeground(true);
}
isRemove=false;
}
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
//移除前台服务
if (isRemove) {
stopForeground(true);
}
isRemove=false;
super.onDestroy();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
八、管理Service的生命周期
九、Android5.0以上的隐式启动问题
显隐存在的意义
如果在同一个应用中,两者都可以用。在不同应用时,只能用隐式启动
- 显示启动
直接上代码一目了然,不解释了。
//显示启动
Intent intent = new Intent(this,ForegroundService.class);
startService(intent);
- 隐式启动
需要设置一个Action
,我们可以把Action
的名字设置成Service
的全路径名字,在这种情况下android:exported
默认为true
。如下
<service
android:name="com.dbjtech.acbxt.waiqin.UploadService"
android:enabled="true" >
<intent-filter android:priority="1000" >
<action android:name="com.dbjtech.myservice" />
</intent-filter>
</service>
final Intent serviceIntent=new Intent(); serviceIntent.setAction("com.android.ForegroundService");
serviceIntent.setPackage(getPackageName());//设置应用的包名
startService(serviceIntent);
十、如何保证服务不会被杀死
- 单纯的介绍两种返回start_sticky
当Service
因内存不足而被系统kill后,一段时间后内存再次空闲时,系统将会尝试重新创建此Service
,一旦创建成功后将回调onStartCommand
方法,但其中的Intent
将是null
,除非有挂起的Intent
,如pendingintent
,这个状态下比较适用于不执行命令、但无限期运行并等待作业的媒体播放器或类似服务。
**
* 返回 START_STICKY或START_REDELIVER_INTENT
* @param intent
* @param flags
* @param startId
* @return
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// return super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
- 提高Service的优先权
<service
android:name="com.dbjtech.acbxt.waiqin.UploadService"
android:enabled="true" >
<intent-filter android:priority="1000" >
<action android:name="com.dbjtech.myservice" />
</intent-filter>
</service>
网友评论