展会信息港展会大全

Activity四大组件之Service详解(上)
来源:互联网   发布日期:2016-01-13 22:20:28   浏览:2076次  

导读:Service是一种可以在后台执行长时间任务的没有交互界面的应用组件,Service运行在进程中的主线程中,它不能自己建立线程处理长时间的事务,所以需要你手动为你的Service创建独立的线程来避免系统没有响应(ANR)......

Service是一种可以在后台执行长时间任务的没有交互界面的应用组件,Service运行在进程中的主线程中,它不能自己建立线程处理长时间的事务,所以需要你手动为你的Service创建独立的线程来避免系统没有响应(ANR)等问题。

Service生命周期

1.startService

startService()->onCreate()->onStartCommand()->running->onDestory()->shut down

多次调用startService()方法会多次执行Service的onStartCommand()方法,然后只需调用一次stopService()去停止Service。

当Service启动后,独立运行在后台,即使应用组件被Destory了,Service也不会停止,Service应该应该在完成事务后调用stopSelf(),或者在其他应用组件中调用stopService()。

2.bindService

bindService()->onCreate()->onBind()->客户端绑定Service->onUnBind()->onDestory()->shut down

多个应用组件可以绑定同一个Service,当客户端和Service绑定后,调用unbindService()来进行解绑,直到所有调用该Service的客户端都解绑了,系统才会去销毁Service。

这类Service不会独立运行在后台(设置->运行的服务中看到不你的Service),它的生命周期与绑定它的应用组件相关,当应用组件销毁了,Service会调用onDestory。

如果在一个Activity中多次绑定Service,在解绑的时候需要多次调用unbindService(),但此时系统会抛出异常:

java.lang.IllegalArgumentException: Service not registered:

所以按照官方的要求(忘记在哪看到了,找不到了,应该就在官网上有说明),需要在绑定和解绑过程中做一个标志位,当Service已经解绑了,才能再次被绑定。官网的实例代码也是这么做的。

处理多个请求

IntentService

IntentService继承Service,使用工作队列来处理所有请求,一次处理一件。当有多个请求同时发出,可以保证线程的安全性。你所要做的只需要实现onHandleIntent()方法在后台处理从不同的Intent发来的请求。

下面写了一个小实例,发送3个请求,每隔5秒钟打印信息,并且在所有请求完成后销毁Service。

//Client

//start service

Intent intent = new Intent(ServiceStartActivity.this,

HelloIntentService.class);

intent.putExtra("value", "From ServiceStartActivity");

startService(intent);

//stop service

Intent intent = new Intent(ServiceStartActivity.this,

HelloIntentService.class);

stopService(intent);

//Service

public class HelloIntentService extends IntentService {

@Override

protected void onHandleIntent(Intent intent) {

logger.i("onHandleIntent " + intent.getStringExtra("value"));

long endTime = System.currentTimeMillis() + 5 * 1000;

while (System.currentTimeMillis() < endTime) {

synchronized (this) {

try {

wait(endTime - System.currentTimeMillis());

} catch (Exception e) {

logger.e(e.getMessage());

}

}

}

}

}

Service

如果你还是想让Service来执行多线程任务,那么你需要继承Service处理每一个intent。

官网上的例子还是一次只能执行一个请求,请求都在一个线程中等待上一个请求结束,我修改了下,让请求可以同时进行,所有请求处理结束后,销毁Service。

//Client

//start service

Intent intent = new Intent(ServiceStartActivity.this,HelloService.class);

startService(intent);

//stop service

Intent intent = new Intent(ServiceStartActivity.this,HelloService.class);

stopService(intent);

//Service

//用来处理接受的请求

public class HelloService extends Service {

private final class ServiceHandler extends Handler {

public ServiceHandler(Looper looper) {

super(looper);

}

@Override

public void handleMessage(Message msg) {

logger.i("handleMessage1");

long endTime = System.currentTimeMillis() + 5 * 1000;

while (System.currentTimeMillis() < endTime) {

synchronized (this) {

try {

wait(endTime - System.currentTimeMillis());

} catch (InterruptedException e) {

// TODO Auto-generated catch block

logger.e(e.getMessage());

}

}

}

logger.i("stopSelf " + msg.arg1);

stopSelf(msg.arg1);

// stopSelfResult(msg.arg1);

}

}

@Override

public int onStartCommand(Intent intent, int flags, int startId) {

logger.i("onStartCommand " + startId);

//为每一次的请求分配线程

HandlerThread thread = new HandlerThread("ServiceStartArguments",

Process.THREAD_PRIORITY_BACKGROUND);

thread.start();

Looper looper = thread.getLooper();

Handler handler = new ServiceHandler(looper);

Message msg1 = handler.obtainMessage();

msg1.arg1 = startId;

handler.sendMessage(msg1);

return START_STICKY;

}

}

onStartCommand()的返回值用来描述,系统将如何处理被kill的Service。

START_NOT_STICKY

如果系统在onStartCommand()返回之后杀掉Service,不会重建Service,除非一个intent被传递给Service。可以避免你在必须要的时候运行你的Service。

START_STICKY

如果系统在onStartCommand()返回之后杀掉Service,重建Service并调用onStartCommand(),但不会传递最后一次Intent,换句话说,onStartCommand()所接受到的Intent是null值,除非有一个intent启动了Service。

START_REDELIVER_INTENT

如果系统在onStartCommand()返回之后杀掉Service,重建Service并调用onStartCommand(),并传递最后一次Intent给Service。

运行一个Foreground Service

一个Foreground Service即便在内存较低的情况下也不会被系统kill掉。Foreground Service提供了一个通知在状态栏,这个通知在 ongoing 栏中,意思是通知不会消失除非Service停止或者从Foreground移除。调用startForeground()启动foreground service,从前台移除Service,调用stopForeground()方法,这个方法不会让Service停止,如果停止了Service,那么通知也会从状态栏移除。看下实例代码。

//Client

//start service

Intent intent = new Intent(ServiceStartActivity.this,LocalService.class);

intent.putExtra("value", "1234");

startService(intent);

//stop service

Intent intent = new Intent(ServiceStartActivity.this,LocalService.class);

stopService(intent);

//Service

public class LocalService extends Service {

private NotificationManager mNm;

private static final Class[] mStartForegroundSignature = new Class[] {

int.class, Notification.class };

private static final Class[] mStopForegroundSignature = new Class[] { boolean.class };

private Method mStartForeground;

private Method mStopForeground;

private Object[] mStartForegroundArgs = new Object[2];

private Object[] mStopForegroundArgs = new Object[1];

//开启Foreground Service,为了兼容早期版本,2.0之前的版本调用setForeground()方法

void startForegroundCompat(int id, Notification notification) {

if (mStartForeground != null) {

mStartForegroundArgs[0] = Integer.valueOf(id);

mStartForegroundArgs[1] = notification;

try {

mStartForeground.invoke(this, mStartForegroundArgs);

} catch (InvocationTargetException e) {

logger.e(e.getMessage());

} catch (IllegalAccessException e) {

logger.e(e.getMessage());

}

return;

}

setForeground(true);

mNm.notify(id, notification);

}

//移除Foreground Service

void stopForegroundCompat(int id) {

if (mStopForeground != null) {

mStopForegroundArgs[0] = Boolean.TRUE;

try {

mStopForeground.invoke(this, mStopForegroundArgs);

} catch (InvocationTargetException e) {

logger.e(e.getMessage());

} catch (IllegalAccessException e) {

logger.e(e.getMessage());

}

return;

}

mNm.cancel(id);

setForeground(false);

}

@Override

public void onCreate() {

super.onCreate();

logger.w("onCreate threadID" + Thread.currentThread().getId());

mNm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

try {

mStartForeground = getClass().getMethod("startForeground",

mStartForegroundSignature);

mStopForeground = getClass().getMethod("stopForeground",

mStopForegroundSignature);

} catch (NoSuchMethodException e) {

mStartForeground = mStopForeground = null;

}

showBroadCast();

}

private void showBroadCast() {

Notification notification = new Notification(R.drawable.btn_star,

"afasdf", System.currentTimeMillis());

Intent intent = new Intent(this, ServiceStartActivity.class);

PendingIntent pi = PendingIntent.getBroadcast(this, 123, intent, 0);

notification.setLatestEventInfo(this, "AAA", "BBB", pi);

startForegroundCompat(R.string.dialog_alert_title, notification);

}

}

需要注意的是在android2.0之后引入 startForeground()和 stopForeground()方法,如果你的程序想在android2.0之前运行Foreground Service,你必须使用之前的方法 setForeground() 。

赞助本站

人工智能实验室

相关热词: Service

AiLab云推荐
推荐内容
展开

热门栏目HotCates

Copyright © 2010-2024 AiLab Team. 人工智能实验室 版权所有    关于我们 | 联系我们 | 广告服务 | 公司动态 | 免责声明 | 隐私条款 | 工作机会 | 展会港