我已经实现了一个Android应用小部件。
点击窗口小部件将使用PendingIntent.getBroadcast(...)
启动广播。
我想在广播接收器的onReceive
内发出网络请求。
(您问我为什么不使用PendingIntent.getService(...)
并启动IntentService
吗?那是很自然的主意,但可悲的是,由于背景限制,如果应用程序不在以下位置,则无法启动该服务前景。您可以看看this post。)
为了证明它是可行的,我已经实现了一个示例BroadcastReceiver:
class WidgetClickBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (context == null || intent == null) return
Log.i("Sira", "onReceive called")
val pendingResult = goAsync()
Observable.just(true).delay(3, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
Log.i("Sira", "Fake completion of network call")
pendingResult.finish()
}
}
}
是的。
但是,我注意到,如果我多次点击窗口小部件,则会创建多个广播并逐个排队,直到调用上一个广播的pendingResult.finish()
。
这可以通过goAsync()
的文档进行解释:
请记住,您在此处所做的工作会阻止进一步的广播,直到完成为止,因此,过度利用这一点可能会适得其反,并导致以后的事件接收得更慢。
所以我想知道是否有一种方法可以防止同一广播已在队列中多次触发?
还是其他任何方法可以防止由于小部件的疯狂点击而导致排队的呼叫?
答案 0 :(得分:1)
编辑2 :小部件可能的解决方案是:
完成操作后,将timestamp
保存到SharedPreferences
(对于每个操作,如果需要的话)。
再次调用onReceive
后,请检查timestamp
中您偏爱的millis
增量,只有在增量足够长的情况下才再次执行操作。
Edit1 :以下答案对 widgets 无效无效,我将其留给寻找“常规”情况的任何人< / p>
我已经尝试了很多事情(包括使用Handler
和Reflection
),最后我想出了以下解决方案:当您收到一条消息时,您不想得到同样,unregister
(该特定操作)和完成操作后的register
。 BroadcastReceiver
在下面,ZonedDateTime
package com.exmplae.testbroadcastreceiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
public class SelfRegisteringBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "SelfRegisteringBR";
public static final String TEST_ACTION1 = "TEST_ACTION1";
public static final String TEST_ACTION2 = "TEST_ACTION2";
private final ArrayList<String> registeredActions = new ArrayList<>();
private final ILogListener logListener;
private final Object registeringLock = new Object();
public static IntentFilter getIntentFilter() {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(TEST_ACTION1);
intentFilter.addAction(TEST_ACTION2);
return intentFilter;
}
public SelfRegisteringBroadcastReceiver(ILogListener logListener) {
this.logListener = logListener;
registeredActions.add(TEST_ACTION1);
registeredActions.add(TEST_ACTION2);
}
private void register(Context context, String action) {
synchronized (registeringLock) {
if (!registeredActions.contains(action)) {
registeredActions.add(action);
context.unregisterReceiver(this);
register(context);
}
}
}
private void register(Context context) {
IntentFilter intentFilter = new IntentFilter();
for (String action : registeredActions) {
intentFilter.addAction(action);
}
context.registerReceiver(this, intentFilter);
}
private void unregister(Context context, String action) {
synchronized (registeringLock) {
if (registeredActions.contains(action)) {
registeredActions.remove(action);
context.unregisterReceiver(this);
register(context);
}
}
}
@Override
public void onReceive(Context context, Intent intent) {
logListener.d(TAG, "onReceive");
if (intent == null) {
logListener.e(TAG, "intent = null");
return;
}
String action = intent.getAction();
if (action == null) {
logListener.e(TAG, "action = null");
return;
}
//noinspection IfCanBeSwitch
if (action.equals(TEST_ACTION1)) {
doAction1(context, TEST_ACTION1);
} else if (action.equals(TEST_ACTION2)) {
doAction2();
} else {
logListener.e(TAG, "Received unknown action: " + action);
}
}
private void doAction1(final Context context, final String actionName) {
logListener.d(TAG, "doAction1 start (and unregister)");
unregister(context, actionName);
Observable.just(true).delay(10, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Boolean>() {
@Override
public void onSubscribe(Disposable d) {
logListener.d(TAG, "doAction1 - onSubscribe");
}
@Override
public void onNext(Boolean aBoolean) {
logListener.d(TAG, "doAction1 - onNext");
}
@Override
public void onError(Throwable e) {
logListener.e(TAG, "doAction1 - onError");
}
@Override
public void onComplete() {
logListener.d(TAG, "doAction1 - onComplete (and register)");
register(context, actionName);
}
});
logListener.d(TAG, "doAction1 end");
}
private void doAction2() {
logListener.d(TAG, "doAction2 start");
Observable.just(true).delay(3, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Boolean>() {
@Override
public void onSubscribe(Disposable d) {
logListener.d(TAG, "doAction2 - onSubscribe");
}
@Override
public void onNext(Boolean aBoolean) {
logListener.d(TAG, "doAction2 - onNext");
}
@Override
public void onError(Throwable e) {
logListener.e(TAG, "doAction2 - onError");
}
@Override
public void onComplete() {
logListener.d(TAG, "doAction2 - onComplete");
}
});
logListener.d(TAG, "doAction2 end");
}
}