Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/199.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 如何阻止同一广播(从PendingEvent)排队? 脚本_Android_Android Widget_Android Pendingintent_Android Broadcast - Fatal编程技术网

Android 如何阻止同一广播(从PendingEvent)排队? 脚本

Android 如何阻止同一广播(从PendingEvent)排队? 脚本,android,android-widget,android-pendingintent,android-broadcast,Android,Android Widget,Android Pendingintent,Android Broadcast,我已经实现了一个Android应用程序小部件 单击小部件将使用pendingent.getBroadcast(…)启动广播 我想在广播接收器的onReceive内执行网络请求 (你问我为什么不使用pendingent.getService(…)并启动IntentService?这是一个自然的想法,但遗憾的是由于背景限制,如果应用程序不在前台,该服务将无法启动。你可以看看。) 问题 为了证明它是有效的,我实现了一个示例BroadcastReceiver: class WidgetClickBroa

我已经实现了一个Android应用程序小部件

单击小部件将使用
pendingent.getBroadcast(…)
启动广播

我想在广播接收器的
onReceive
内执行网络请求

(你问我为什么不使用
pendingent.getService(…)
并启动
IntentService
?这是一个自然的想法,但遗憾的是由于背景限制,如果应用程序不在前台,该服务将无法启动。你可以看看。)

问题 为了证明它是有效的,我实现了一个示例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()
        }
    }

}
是的,很管用

但是,我注意到,如果我多次点击该小部件,将创建多个广播并逐个排队,直到调用前一个的
pendingreult.finish()

这可以通过
goAsync()
的文档来解释:

请记住,您在此处所做的工作将阻止进一步的广播,直到广播完成为止,因此过度利用这一点可能会适得其反,并导致以后的事件接收速度变慢

所以我想知道,如果同一个广播已经在队列中,是否有办法防止它多次发射


或任何其他防止因疯狂点击小部件而导致排队的方法?

编辑2:小部件的一种可能解决方案是:
操作完成后,将
时间戳
保存到
SharedReferences
(对于每个操作,如果需要)。
再次调用
onReceive
后,请检查
时间戳
中您首选的
millis
delta,并仅在delta足够长时再次运行该操作

Edit1:下面的答案不适用于小部件,我将把它留给寻找“常规”案例的任何人

我尝试了很多方法(包括使用
处理程序
反射
),最后我想出了以下解决方案:当您收到不想再次收到的消息时,
取消注册
(该特定操作)并在操作完成时注册。
BroadcastReceiver
位于下方和下方

package com.exmplae.testbroadcastreceiver;
导入android.content.BroadcastReceiver;
导入android.content.Context;
导入android.content.Intent;
导入android.content.IntentFilter;
导入java.util.ArrayList;
导入java.util.concurrent.TimeUnit;
导入io.reactivex.Observable;
导入io.reactivex.Observer;
导入io.reactivex.android.schedulers.AndroidSchedulers;
进口io.reactivex.disposables.Disposable;
导入io.reactivex.schedulers.schedulers;
公共类自注册GBroadCastReceiver扩展广播接收器{
私有静态最终字符串TAG=“SelfRegisteringBR”;
公共静态最终字符串TEST\u ACTION1=“TEST\u ACTION1”;
公共静态最终字符串TEST\u ACTION2=“TEST\u ACTION2”;
私有最终ArrayList registeredActions=新ArrayList();
私人最终iGlistener logListener;
私有最终对象寄存器registeringLock=新对象();
公共静态IntentFilter getIntentFilter(){
IntentFilter IntentFilter=新的IntentFilter();
intentFilter.addAction(测试动作1);
intentFilter.addAction(测试动作2);
返回意向过滤器;
}
公共自注册GBroadcastreceiver(iGlistener logListener){
this.logListener=logListener;
添加(测试操作1);
添加(测试操作2);
}
专用无效寄存器(上下文、字符串操作){
已同步(registeringLock){
如果(!registeredActions.contains(操作)){
添加(操作);
上下文。未注册接收者(本);
语域(上下文);
}
}
}
专用无效寄存器(上下文){
IntentFilter IntentFilter=新的IntentFilter();
for(字符串操作:registeredActions){
intentFilter.addAction(操作);
}
registerReceiver(this,intentFilter);
}
私有void注销(上下文、字符串操作){
已同步(registeringLock){
if(registeredActions.contains(操作)){
删除(操作);
上下文。未注册接收者(本);
语域(上下文);
}
}
}
@凌驾
公共void onReceive(上下文、意图){
logListener.d(标记“onReceive”);
if(intent==null){
logListener.e(标记“intent=null”);
返回;
}
String action=intent.getAction();
if(action==null){
logListener.e(标记“action=null”);
返回;
}
//无检查IfCanBeSwitch
if(动作等于(测试动作1)){
doAction1(上下文、测试和操作1);
}else if(动作等于(测试动作2)){
doAction2();
}否则{
logListener.e(标记“接收到未知操作:”+操作);
}
}
私有void doAction1(最终上下文,最终字符串actionName){
logListener.d(标记“doAction1启动(并注销)”;
取消注册(上下文、actionName);
可观察。刚好(正确)。延迟(10,时间单位。秒)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.订阅(新观察员){
@凌驾
认购的公共无效(一次性d){
logListener.d(标记“doAction1-onSubscribe”);
}
@凌驾
public void onNext(布尔aBoolean){
logListener.d(标记“doAction1-onNext”);
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");
    }

}