2011-03-31 88 views
0

我在其中一个应用程序中遇到小问题。它使用BroadCastReceiver来检测呼叫何时结束,然后执行一些小型内务处理任务。这些必须延迟几秒钟,以允许用户查看一些数据并确保通话记录已更新。我目前使用handler.postDelayed()为了这个目的:handler.postDelayed与AlarmManager vs

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

我目前使用handler.postDelayed()用于此目的:

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

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

更确切地说,这个过程终止了,把所有的东西都拿走了。

我现在想着替代postDelayed(),我的选择之一显然是AlarmManager。但是,我不确定性能影响(或其使用的资源)。

这并不坏。另一种可能性是在IntentService中通过致电startService()触发延迟工作 - 让它在其后台线程上睡几秒钟。

+0

好了,就像我想 - 我只是不想浪费资源。我想我会和AlarmManager一起使用,并为这两项任务使用一个接收器。谢谢! – alibi 2011-03-31 21:15:32

+0

好吧,实施它(比我想象的要容易),完美无瑕。再次感谢你! – alibi 2011-03-31 21:56:58

0

除了the first answer,你可能要考虑一下API文档说的onReceive方法:

[...]该功能通常被称为其进程的主线程,左右的时间内你不应该在它 [...]

所以看起来一般是不启动某些等待中onReceive一对夫妇的时间(一个好主意执行长时间运行的操作,即使在您的情况不及10秒的限制)。

我有一个类似的timinig与BroadcastReceiver的问题。即使我的onReceive被调用的时候,我仍然无法得到我的结果。看起来线程BroadastReceiver正在运行,在我的结果处理完成之前被杀死。我的solutuion是启动一个新线程来执行所有处理。

0

AlarmManager似乎不能在短时间内工作得很好,例如10秒钟,根据用户报告,这种行为在很大程度上取决于固件。

最后我决定在我的服务中使用HandlerRunnable

在创建Handler,务必因为在后一种情况下创建它的服务类中,而不是广播接收器里面,你会得到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(); 
     } 
    } 

} 
2

让我们尝试这样做的一个新途径。使用RxJava。如果想要同时运行数百个这样的延迟任务,按顺序加上异步任务,链接同步链接的异步调用等,原型和更容易管理大量线程就简单多了。

首先,设置订阅服务器。切记newSubscriber应该只做一次以避免内存泄漏。

// 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());