1

我的一个应用程序有一个小问题。它使用 aBroadCastReceiver来检测呼叫何时完成,然后执行一些次要的内务处理任务。这些必须延迟几秒钟,以允许用户查看一些数据并确保通话记录已更新。我目前正在handler.postDelayed()为此目的使用:

public class CallEndReceiver extends BroadcastReceiver {

@Override
public void onReceive(final Context context, final Intent intent) {
    if (DebugFlags.LOG_OUTGOING)
        Log.v("CallState changed "
                + intent.getStringExtra(TelephonyManager.EXTRA_STATE));
    if (intent.getStringExtra(TelephonyManager.EXTRA_STATE)
            .equalsIgnoreCase(TelephonyManager.EXTRA_STATE_IDLE)) {
        SharedPreferences prefs = Utils.getPreferences(context);
        if (prefs.getBoolean("auto_cancel_notification", true)) {
            if (DebugFlags.LOG_OUTGOING)
                Log.v("Posting Handler to remove Notification ");
            final Handler mHandler = new Handler();
             final Runnable mCancelNotification = new Runnable() {
                   public void run() {
                        NotificationManager notificationMgr = (NotificationManager) context
                        .getSystemService(Service.NOTIFICATION_SERVICE);
                notificationMgr.cancel(12443);
                if (DebugFlags.LOG_OUTGOING)
                    Log.v("Removing Notification ");
                   }
                };
                mHandler.postDelayed(mCancelNotification, 4000);


        }
        final Handler updateHandler = new Handler();
         final Runnable mUpdate = new Runnable() {
               public void run() {
        if (DebugFlags.LOG_OUTGOING)
            Log.v("Starting updateService");
        Intent newBackgroundService = new Intent(context,
                CallLogUpdateService.class);
        context.startService(newBackgroundService);
               }
               };
               updateHandler.postDelayed(mUpdate, 5000);

        if (DebugFlags.TRACE_OUTGOING)
            Debug.stopMethodTracing();
        try
        {
        // Stopping old Service
        Intent backgroundService = new Intent(context,
                NetworkCheckService.class);
        context.stopService(backgroundService);
        context.unregisterReceiver(this);
        }
        catch(Exception e)
        {
            Log.e("Fehler beim Entfernen des Receivers", e);
        }
    }

}

}

现在我有一个问题,这个设置在大约 90% 的时间里都有效。在大约 10% 的情况下,通知不会被删除。我怀疑,线程在消息队列处理消息/可运行之前死亡。

我现在正在考虑替代方案postDelayed(),我的选择之一显然是 AlarmManager。但是,我不确定性能影响(或它使用的资源)。

也许有更好的方法来确保在线程死亡之前处理完所有消息,或者有另一种方法来延迟这两位代码的执行。

谢谢

4

4 回答 4

4

我目前正在为此目的使用 handler.postDelayed() :

这不是一个好主意,假设它BroadcastReceiver是由清单中的过滤器触发的。

现在我有一个问题,这个设置在大约 90% 的时间里都有效。在大约 10% 的情况下,通知不会被删除。我怀疑,线程在消息队列处理消息/可运行之前死亡。

更准确地说,该过程被终止,并带走了所有东西。

我现在正在考虑 postDelayed() 的替代方案,我的选择之一显然是 AlarmManager。但是,我不确定性能影响(或它使用的资源)。

它没有那么坏。另一种可能性是在一个IntentService- 通过调用触发startService()- 并让它在其后台线程上休眠几秒钟来完成您的延迟工作。

于 2011-03-31T19:53:56.103 回答
3

让我们尝试一种新的方法来做到这一点。使用 RxJava。如果您想同时运行数百个这样的延迟任务,顺序地,加上异步任务,链接同步链异步调用等,那么原型设计和管理大量线程要简单得多。

首先,设置订阅者。记住newonSubscriber应该只执行一次以避免内存泄漏。

// Set up a subscriber once
private Subscuber<Long> delaySubscriber = new Subscuber<Long> () {
    @Override
    public void onCompleted() {
        //Wrap up things as onCompleted is called once onNext() is over
    }
    @Override
    public void onError(Throwable e) {
        //Keep an eye open for this. If onCompleted is not called, it means onError has been called. Make sure to override this method
    }
    @Override
    public void onNext(Long aLong) {
        // aLong will be from 0 to 1000
        // Yuor code logic goes here

        // If you want to run this code just once, just add a counter and call onComplete when the counter runs the first time

    }
} 

下面的代码片段只会1在订阅者的 onNext() 中发出。请注意,这是在 RxJava 库创建和管理的计算线程池上完成的。

//Now when you want to start running your piece of cade, define an Observable interval that'll emit every second
private Observable<Long> runThisAfterDelay = Observable.just(1).delay(1000, TimeUnit.MILLISECONDS, Schedulers.computation());
// Subscribe to begin the emissions.
runThisAfterDelay.subscribe(delaySubscriber);

如果你想每隔一秒运行一次代码,那么你可以这样做:

private Observable<Long> runThisOnInterval = Observable.interval(1000, TimeUnit.MILLISECONDS, Schedulers.computation());
于 2017-02-25T09:00:49.143 回答
1

除了第一个答案之外,您可能还需要考虑 API 文档对该onReceive方法的说明:

[...] 该函数通常在其进程的主线程中调用,因此您不应该在其中执行长时间运行的操作[...]

所以看起来一般来说,开始等待一段时间的东西并不是一个好主意onReceive(即使在你的情况下它小于 10 秒的限制)。

我对 BroadcastReceiver 有类似的时间问题。即使我onReceive被调用的正是我所期望的,我也无法处理我的结果。似乎BroadastReceiver正在运行的线程在我的结果处理完成之前就被杀死了。我的解决方案是启动一个新线程来执行所有处理。

于 2012-03-26T10:12:23.973 回答
1

AlarmManager 似乎在 10 秒之类的短时间内不能很好地工作,并且根据用户报告,该行为在很大程度上取决于固件。

最后我决定使用HandlerRunnable为我服务。

创建时Handler,请务必在 Service 类中创建它,而不是在 BroadcastReceiver 中,因为在最后一种情况下,您将获得Can't create Handler inside thread that has not called Looper.prepare()

public class NLService extends NotificationListenerService {
    private NLServiceReceiver nlservicereciver;
    Handler delayUpdateHandler = new Handler();
    private Runnable runBroadcastUpdate;

    public void triggerViewUpdate() {
        /* Accumulate view updates for faster, resource saving operation.
        Delay the update by some milliseconds.
        And if there was pending update, remove it and plan new update.
         */
        if (runBroadcastUpdate != null) {
            delayUpdateHandler.removeCallbacks(runBroadcastUpdate);
        }
        runBroadcastUpdate = new Runnable() {
            public void run() {
                // Do the work here; execution is delayed
            }
        };
        delayUpdateHandler.postDelayed(runBroadcastUpdate, 300);
    }

    class NLServiceReceiver extends BroadcastReceiver{
        @Override
        public void onReceive(Context context, Intent intent) {
            triggerViewUpdate();
        }
    }

}
于 2016-07-14T09:19:44.720 回答