以下是我现在所做的事情:
我有一个在后台运行并读取用户位置的服务。每次读取有效位置(有一些参数,如距离和时间),IntentService就会启动将该位置发送到Web服务器
使用跟踪服务的应用也会进行一些网络通话,具体取决于用户按哪些选项。现在,该应用程序只是在asynctask中调用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和应用程序不能同时调用Web服务器。由于现在实施,这是不可能的,因为它们独立行动。我想通过为所有这些调用创建意图,将所有Web调用从应用程序传递到IntentService。这会有用吗?如果有一个位置网络发送,应用程序调用的新意图将被放入队列并在当前通话后立即执行?
如果由于网络速度较低而在队列中发送多个位置,则需要将应用程序调用放在队列前面,而不是等待所有现有意图完成,仅针对当前目标。有没有办法将意图置于队列之上?
谢谢。
稍后编辑:
以下是我所做的更改。
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(); } }
答案 0 :(得分:1)
由于构建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
:包含“looper”的线程的“句柄”。通过此句柄,任何线程都可以将messages
或runnables
发送到此句柄线程。消息将在句柄handleMessage(Message)
回调上执行,Runnables
将执行run()
方法。https://developer.android.com/reference/android/os/Handler.html
所有这些Handler的东西都被汇集到MessageQueue
,这对每个循环器/线程都是唯一的。 https://developer.android.com/reference/android/os/MessageQueue.html
新修改:
它没有执行的原因在于:
stopSelf(msg.arg1);
一旦所有正在执行的消息都停止服务,请检查the docs:
如果服务的最近开始时间是
startId
,请停止服务。 这与为此特定调用stopService(Intent)
相同 服务,但如果有一个开始,你可以安全地避免停止 来自客户的请求,您尚未在onStart(Intent, int)
中看到。请注意对此功能的调用顺序。如果你打电话 此函数具有最近收到的ID,然后才能使用 将其称为先前收到的ID,该服务将立即生效 无论如何都停了。如果您最终可能无序处理ID(例如 通过在不同的线程上调度它们,然后你负责 按照收到它们的顺序停止它们。
因此,在完成之前,您必须找到另一种检查所有消息是否已执行的方法。可能是AtomicInt
计算队列中的邮件数量,或者是用来保存startId
的地图。