我是rxjava的新手,所以我想在Android IntentService中使用它,我需要在一段时间内每秒通知一次(类似于Android CountDownTimer。我已决定尝试使用rxjava并且我有这个类:
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并且取消订阅应该不是这样吗?如何确保可观察的停止发射并且流程终止?好多了
答案 0 :(得分:4)
问题是,当onHandleIntent返回时,您的意图服务已经死亡。 IntentServices是一种非常特殊的服务,它在后台线程中执行onHandleIntent并被解雇。
通过执行此操作,您正在泄漏该intentservice类,因为订阅者拥有对它的引用。订阅完成后,您将在死(泄露)服务上调用stopSelf。
此外,由于onHandleIntent本身在不同的线程中运行,所以在另一个线程中订阅是没有意义的。
我认为您应该使用服务(而非目标服务)来实现您的目标。
答案 1 :(得分:0)
感谢fedepaol和David Medenjak,我设法解决了这个问题。 由:
这是结果类
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);
}
}