2016-01-23 27 views
1

我对rxjava非常陌生,所以我想在android IntentService中使用它,并且我需要在特定时间段内每秒钟收到一次通知(类似于Android CountDownTimer,我决定用rxjava和我有这个类:Android RxJava与IntentService的时间间隔

public class WorkoutService extends IntentService { 
public static final String BUNDLE_EXTRA_MESSENGER = "messenger"; 
public static final String BUNDLE_EXTRA_NUMBER_ROUNDS = "nr_rounds"; 
public static final String BUNDLE_EXTRA_WORKOUT_DURATION = "workout_duration"; 
public static final String BUNDLE_EXTRA_PAUSE_DURATION = "pause_duration"; 
private static final int NOTIFICATION_ID = 1; 
public static final int UPDATE_PROGRESS = 2; 

/** 
* Target we publish for clients to send messages to IncomingHandler. 
* This is the messenger from the activity 
*/ 
Messenger messenger; 

private NotificationManager notifyManager; 
private NotificationCompat.Builder builder; 
private volatile int maxProgress; 
private int numberOfRounds = 4; 
private int workoutDuration = 7 * 60; //7 minutes 
private int pauseDuration = 90; //1.5 minutes 
private int currentProgress; 

public WorkoutService() { 
    super("WorkoutService"); 
} 

@Override 
protected void onHandleIntent(Intent intent) { 
    Bundle extras = intent.getExtras(); 
    if (extras != null) { 
     messenger = (Messenger) extras.get(BUNDLE_EXTRA_MESSENGER); 
     numberOfRounds = extras.getInt(BUNDLE_EXTRA_NUMBER_ROUNDS, numberOfRounds); 
     workoutDuration = extras.getInt(BUNDLE_EXTRA_WORKOUT_DURATION, workoutDuration); 
     pauseDuration = extras.getInt(BUNDLE_EXTRA_PAUSE_DURATION, pauseDuration); 
    } 
    maxProgress = numberOfRounds * workoutDuration + ((numberOfRounds - 1) * pauseDuration); 
    maxProgress = 10; //TODO: for testing 
    showNotification(maxProgress); 
    Timber.d("maxProgress %d", maxProgress); 
    startWorkout(); 

} 

private void startWorkout() { 
    final Observable<Long> observable = Observable 
      .interval(1, TimeUnit.SECONDS); 
    observable 
      .subscribeOn(Schedulers.io()) 
      .subscribe(new Subscriber<Long>() { 
       @Override 
       public void onCompleted() { 
        Timber.d("onCompleted"); 
        unsubscribe(); 
        stopForeground(true); 
        stopSelf(); 

       } 

       @Override 
       public void onError(Throwable e) { 
        Timber.e("onError"); 
       } 

       @Override 
       public void onNext(Long aLong) { 
        Timber.d("onNext : " + aLong + "S"); 
        updateProgress(); 
        if (aLong == maxProgress) { 
         onCompleted(); 
        } 
       } 
      }); 
} 

private void showNotification(int maxProgress) { 
    Intent notificationIntent = new Intent(this, WorkoutService.class); 
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); 
    notifyManager = 
      (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 
    builder = new NotificationCompat.Builder(this); 
    builder.setContentTitle(getString(R 
      .string.notification_title)) 
      .setContentIntent(pendingIntent) 
      .setSmallIcon(R.mipmap.ic_launcher); 
    startForeground(NOTIFICATION_ID, builder.build()); 
    currentProgress = 0; 
    builder.setProgress(maxProgress, currentProgress, false); 
    notifyManager.notify(NOTIFICATION_ID, builder.build()); 
} 

private void sendMessageToActivity(Message message) { 
    try { 
     if (messenger != null) { 
      messenger.send(message); 
     } 
    } catch (RemoteException e) { 
     Timber.e(e, "Error sending message to activity"); 
    } 
} 

private void updateProgress() { 
    currentProgress++; 
    builder.setProgress(maxProgress, currentProgress, false); 
    notifyManager.notify(NOTIFICATION_ID, builder.build()); 
    Message message = Message.obtain(null, UPDATE_PROGRESS, currentProgress, 0); 
    sendMessageToActivity(message); 
} 

} 

的问题是通知没有被搁置,而应该是,它似乎即使我显式调用stopSelf()在Android文档它说,该服务没有得到停止。当没有工作要完成时,这项服务会自行停止,但是由于我正在调用onCompleted并取消订阅,如果不是这种情况?我怎样才能确保可观察到的停止发射和流程终止?Thks a lot

+1

我可以看到很多的问题。您应该使用'takeWhile'来应用您的布尔条件,* *不*自己调用'onCompleted',并且在完成之后,您*取消订阅,因此不需要调用该方法。另外我不认为你应该手动调用'stopSelf'来使用intent服务,但是我可能是错误的 –

回答

3

问题是,当onHandleIntent返回时,您的意图服务已经死亡。 IntentServices是一种非常特殊的服务,它在后台线程中执行onHandleIntent并被解散。

通过这样做,您泄漏该intentservice类,因为该用户拥有对它的引用。订阅完成后,您正在致电stopSelf一个已死的(泄漏)服务。

此外,在不同的线程中订阅是没有意义的,因为onHandleIntent本身运行在不同的线程中。

我想你应该使用服务(而不是意图)来实现你正在尝试做的事情。

0

感谢fedepolol和David Medenjak,我设法解决了这个问题。 由:

  • 切换到服务,而不是使用takeWhile的布尔条件

这里意图服务

  • 是结果类

    public class WorkoutService extends Service { 
    public static final String BUNDLE_EXTRA_MESSENGER = "messenger"; 
    public static final String BUNDLE_EXTRA_NUMBER_ROUNDS = "nr_rounds"; 
    public static final String BUNDLE_EXTRA_WORKOUT_DURATION = "workout_duration"; 
    public static final String BUNDLE_EXTRA_PAUSE_DURATION = "pause_duration"; 
    private static final int NOTIFICATION_ID = 1; 
    public static final int UPDATE_PROGRESS = 2; 
    
    /** 
    * Target we publish for clients to send messages to IncomingHandler. 
    * This is the messenger from the activity 
    */ 
    Messenger messenger; 
    
    private NotificationManager notifyManager; 
    private NotificationCompat.Builder builder; 
    private volatile int maxProgress; 
    private int numberOfRounds = 4; 
    private int workoutDuration = 7 * 60; //7 minutes 
    private int pauseDuration = 90; //1.5 minutes 
    private int currentProgress; 
    
    @Override 
    public int onStartCommand(Intent intent, int flags, int startId) { 
        Bundle extras = intent.getExtras(); 
        if (extras != null) { 
         messenger = (Messenger) extras.get(BUNDLE_EXTRA_MESSENGER); 
         numberOfRounds = extras.getInt(BUNDLE_EXTRA_NUMBER_ROUNDS, numberOfRounds); 
         workoutDuration = extras.getInt(BUNDLE_EXTRA_WORKOUT_DURATION, workoutDuration); 
         pauseDuration = extras.getInt(BUNDLE_EXTRA_PAUSE_DURATION, pauseDuration); 
        } 
        maxProgress = numberOfRounds * workoutDuration + ((numberOfRounds - 1) * pauseDuration); 
        maxProgress = 10; //TODO: for testing 
        showNotification(maxProgress); 
        Timber.d("maxProgress %d", maxProgress); 
        startWorkout(); 
        return START_STICKY; 
    } 
    
    @Nullable 
    @Override 
    public IBinder onBind(Intent intent) { 
        return null; 
    } 
    
    
    private void startWorkout() { 
        final Observable<Long> observable = Observable 
          .interval(1, TimeUnit.SECONDS) 
          .takeWhile(new Func1<Long, Boolean>() { 
           @Override 
           public Boolean call(Long aLong) { 
            return aLong <= maxProgress; 
           } 
          }); 
        observable.observeOn(AndroidSchedulers.mainThread()) 
          .subscribeOn(Schedulers.io()) 
          .subscribe(new Subscriber<Long>() { 
           @Override 
           public void onCompleted() { 
            Timber.d("onCompleted"); 
            stopForeground(true); 
            stopSelf(); 
    
           } 
    
           @Override 
           public void onError(Throwable e) { 
            Timber.e("onError"); 
           } 
    
           @Override 
           public void onNext(Long aLong) { 
            Timber.d("onNext : " + aLong + "S"); 
            updateProgress(); 
           } 
          }); 
    } 
    
    private void showNotification(int maxProgress) { 
        Intent notificationIntent = new Intent(this, WorkoutService.class); 
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); 
        notifyManager = 
          (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 
        builder = new NotificationCompat.Builder(this); 
        builder.setContentTitle(getString(R 
          .string.notification_title)) 
          .setContentIntent(pendingIntent) 
          .setSmallIcon(R.mipmap.ic_launcher); 
        startForeground(NOTIFICATION_ID, builder.build()); 
        currentProgress = 0; 
        builder.setProgress(maxProgress, currentProgress, false); 
        notifyManager.notify(NOTIFICATION_ID, builder.build()); 
    } 
    
    private void sendMessageToActivity(Message message) { 
        try { 
         if (messenger != null) { 
          messenger.send(message); 
         } 
        } catch (RemoteException e) { 
         Timber.e(e, "Error sending message to activity"); 
        } 
    } 
    
    private void updateProgress() { 
        currentProgress++; 
        builder.setProgress(maxProgress, currentProgress, false); 
        notifyManager.notify(NOTIFICATION_ID, builder.build()); 
        Message message = Message.obtain(null, UPDATE_PROGRESS, currentProgress, 0); 
        sendMessageToActivity(message); 
    } 
    
    } 
    
  • +0

    你应该接受我的回答:) – fedepaol