在 IntentService 中对意图进行优先级排序
Prioritize intents in IntentService
这是我现在所做的:
我有一个在后台运行并读取用户位置的服务。每次读取有效位置(有一些参数,如距离和时间)时,都会启动 IntentService 将该位置发送到 Web 服务器
使用跟踪服务的应用程序也有一些网络调用,具体取决于用户按下的选项。现在,应用程序只是在异步任务中调用 Web 服务。
一些代码:
位置服务会触发 IntentService,每次收到一个好的位置,就像这样:
Intent intentService = new Intent(LocationLoggerService.this, LocationManagerIntentService.class);
intentService.putExtra(Constants.MESSAGE_LOCATION, readLocation);
startService(intentService);
intentservice 处理意图:
@Override
protected void onHandleIntent(Intent intent) {
LocationInfo location = intent.getExtras().getParcelable(Constants.MESSAGE_LOCATION);
.... //Do the web call and broadcast result to app
}
以下是我需要进行的更改:
IntentService和app不能同时调用web server。由于现在已经实施,这是不可能的,因为它们是独立行动的。我正在考虑通过为所有网络调用创建意图,将所有网络调用从应用程序传递到 IntentService。这行得通吗?如果有位置网络发送,来自应用程序调用的新意图将被放入队列并在当前调用后立即执行?
如果因为网速低,队列中有多个location发送,app调用,需要放在队列前面,不等待所有已有的intent完成,只针对当前一。有没有办法将意图放在队列顶部?
谢谢。
稍后编辑:
这是我所做的更改。
- 创建了自定义意向服务
public abstract class PriorityIntentService extends Service {
private final AtomicInteger intentsCount = new AtomicInteger();
protected void intentFinished() {
intentsCount.decrementAndGet();
}
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
public final boolean sendPriorityMessage(Message msg) {
intentsCount.incrementAndGet();
int priority = msg.arg2;
if (priority == 0) {
return sendMessageAtFrontOfQueue(msg);
} else {
return sendMessage(msg);
}
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent) msg.obj);
if (intentsCount.get() == 0) {
// stopSelf(msg.arg1);
stopSelf();
}
}
}
@Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
if (intent.getExtras().getInt(Constants.MESSAGE_PRIORITY) == 0) {
msg.arg2 = 0;
} else {
msg.arg2 = 1;
}
mServiceHandler.sendPriorityMessage(msg);
// mServiceHandler.sendMessage(msg);
}
}
- 其他服务:
public class LocationManagerIntentService extends PriorityIntentService {
@Override
protected void onHandleIntent(Intent intent) {
intentFinished();
}
}
由于 IntentService
的构建方式,您想要做的事情是不可能的,但是,IntentService
是一个 非常 简单的代码并且是开放的源,因此您只需稍作修改即可创建自己的版本。
原码为here.
在 onCreate()
方法中,您可以看到 Service
在哪里创建一个 HandlerThread
和一个 Handler
来分派所有 onHandleIntent
调用。
所以你所要做的就是:
创建一个单例 HandlerThread
和 Handler
供您的整个应用程序使用。每个网络调用或 CustomIntentService
都应调用此单个 Handler
。那是第 1 部分。您只是强制所有网络调用永远不会同时发生。
现在您已经通过同一个线程和处理程序进行了所有调用,只需调用 Handler.postAtFrontOfQueue 来确定某些执行的优先级即可。
编码愉快。
编辑:
HandlerThread
: 一个未完成的线程。它有一个 "looper" 使线程保持活动状态。 https://developer.android.com/reference/android/os/HandlerThread.html
Handler
: "handle" 到包含 "looper" 的线程。通过这个句柄,任何线程都可以向这个句柄线程发送 messages
或 runnables
。消息将在句柄 handleMessage(Message)
回调上执行,Runnables
将执行 run()
方法。https://developer.android.com/reference/android/os/Handler.html
所有这些 Handler 内容都汇集到 MessageQueue
,每个 looper/thread 都是唯一的。 https://developer.android.com/reference/android/os/MessageQueue.html
新编辑:
它没有执行的原因在这里:
stopSelf(msg.arg1);
一旦所有消息都被执行,这将停止服务,检查the docs:
Stop the service if the most recent time it was started was startId
.
This is the same as calling stopService(Intent)
for this particular
service but allows you to safely avoid stopping if there is a start
request from a client that you haven't yet seen in onStart(Intent,
int)
.
Be careful about ordering of your calls to this function. If you call
this function with the most-recently received ID before you have
called it for previously received IDs, the service will be immediately
stopped anyway. If you may end up processing IDs out of order (such as
by dispatching them on separate threads), then you are responsible for
stopping them in the same order you received them.
所以你必须找到一种不同的方法来检查是否所有消息都已在完成之前执行。可能是 AtomicInt
计算队列中消息的数量,或者是保存 startId
.
的映射
这是我现在所做的:
我有一个在后台运行并读取用户位置的服务。每次读取有效位置(有一些参数,如距离和时间)时,都会启动 IntentService 将该位置发送到 Web 服务器
使用跟踪服务的应用程序也有一些网络调用,具体取决于用户按下的选项。现在,应用程序只是在异步任务中调用 Web 服务。
一些代码: 位置服务会触发 IntentService,每次收到一个好的位置,就像这样:
Intent intentService = new Intent(LocationLoggerService.this, LocationManagerIntentService.class);
intentService.putExtra(Constants.MESSAGE_LOCATION, readLocation);
startService(intentService);
intentservice 处理意图:
@Override
protected void onHandleIntent(Intent intent) {
LocationInfo location = intent.getExtras().getParcelable(Constants.MESSAGE_LOCATION);
.... //Do the web call and broadcast result to app
}
以下是我需要进行的更改:
IntentService和app不能同时调用web server。由于现在已经实施,这是不可能的,因为它们是独立行动的。我正在考虑通过为所有网络调用创建意图,将所有网络调用从应用程序传递到 IntentService。这行得通吗?如果有位置网络发送,来自应用程序调用的新意图将被放入队列并在当前调用后立即执行?
如果因为网速低,队列中有多个location发送,app调用,需要放在队列前面,不等待所有已有的intent完成,只针对当前一。有没有办法将意图放在队列顶部?
谢谢。
稍后编辑:
这是我所做的更改。
- 创建了自定义意向服务
public abstract class PriorityIntentService extends Service { private final AtomicInteger intentsCount = new AtomicInteger(); protected void intentFinished() { intentsCount.decrementAndGet(); } private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); } public final boolean sendPriorityMessage(Message msg) { intentsCount.incrementAndGet(); int priority = msg.arg2; if (priority == 0) { return sendMessageAtFrontOfQueue(msg); } else { return sendMessage(msg); } } @Override public void handleMessage(Message msg) { onHandleIntent((Intent) msg.obj); if (intentsCount.get() == 0) { // stopSelf(msg.arg1); stopSelf(); } } } @Override public void onStart(Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; if (intent.getExtras().getInt(Constants.MESSAGE_PRIORITY) == 0) { msg.arg2 = 0; } else { msg.arg2 = 1; } mServiceHandler.sendPriorityMessage(msg); // mServiceHandler.sendMessage(msg); } }
- 其他服务:
public class LocationManagerIntentService extends PriorityIntentService { @Override protected void onHandleIntent(Intent intent) { intentFinished(); } }
由于 IntentService
的构建方式,您想要做的事情是不可能的,但是,IntentService
是一个 非常 简单的代码并且是开放的源,因此您只需稍作修改即可创建自己的版本。
原码为here.
在 onCreate()
方法中,您可以看到 Service
在哪里创建一个 HandlerThread
和一个 Handler
来分派所有 onHandleIntent
调用。
所以你所要做的就是:
创建一个单例
HandlerThread
和Handler
供您的整个应用程序使用。每个网络调用或CustomIntentService
都应调用此单个Handler
。那是第 1 部分。您只是强制所有网络调用永远不会同时发生。现在您已经通过同一个线程和处理程序进行了所有调用,只需调用 Handler.postAtFrontOfQueue 来确定某些执行的优先级即可。
编码愉快。
编辑:
HandlerThread
: 一个未完成的线程。它有一个 "looper" 使线程保持活动状态。 https://developer.android.com/reference/android/os/HandlerThread.htmlHandler
: "handle" 到包含 "looper" 的线程。通过这个句柄,任何线程都可以向这个句柄线程发送messages
或runnables
。消息将在句柄handleMessage(Message)
回调上执行,Runnables
将执行run()
方法。https://developer.android.com/reference/android/os/Handler.html所有这些 Handler 内容都汇集到
MessageQueue
,每个 looper/thread 都是唯一的。 https://developer.android.com/reference/android/os/MessageQueue.html
新编辑:
它没有执行的原因在这里:
stopSelf(msg.arg1);
一旦所有消息都被执行,这将停止服务,检查the docs:
Stop the service if the most recent time it was started was
startId
. This is the same as callingstopService(Intent)
for this particular service but allows you to safely avoid stopping if there is a start request from a client that you haven't yet seen inonStart(Intent, int)
.Be careful about ordering of your calls to this function. If you call this function with the most-recently received ID before you have called it for previously received IDs, the service will be immediately stopped anyway. If you may end up processing IDs out of order (such as by dispatching them on separate threads), then you are responsible for stopping them in the same order you received them.
所以你必须找到一种不同的方法来检查是否所有消息都已在完成之前执行。可能是 AtomicInt
计算队列中消息的数量,或者是保存 startId
.