[英]How to sync Toggle Button State with Foreground Service?
我有一個Foreground Service,我在Activity中使用Toggle Button啟動和停止。 為了跟蹤服務是否正在運行,我使用了存儲在SharedPreference
的變量。
這是流程
當用戶啟用切換按鈕時
startService() start background work
makeForeGround()
bindService() to get update
當用戶禁用切換按鈕時
unbindService() to stop getting updates
stopForeGround()
stopService() stop background work
當用戶離開活動時
unbindService(); To stop getting the update.
But the service is running for background work
當用戶重新進入活動時
if(Service is running)
Show toggle button state as enabled
bindService()
我已經實現了所有這些。
我面臨的唯一問題是:
有時我的服務被OS殺死了。 在這種情況下,我無法更新My SharedPreference
變量。 因此無法將我的切換按鈕與服務同步。
如何通知操作系統已殺死該服務。 (因為在這種情況下沒有調用onDestroy())? 我還經歷了如何檢查Android上是否正在運行某項服務? 但遺憾的是,所提供的解決方案和方法已被棄用。
您應該考慮從不同的方向處理您的問題。
試圖推斷系統何時殺死了您的Service
是一個問題。 應用程序( Services
)在終止時不會得到通知,因此難以檢測到這種情況。 但是,找出Service
何時啟動是微不足道的( onCreate()
)。 這是正確方法的線索。
很明顯,您了解在Activity
和Service
之間交換信息的正確方法是通過綁定。 這是解決方案的另一個關鍵部分。
解
您應該延長Service
的生命周期。 現在,您似乎為了執行長時間運行的任務而創建Service
。 您希望任務啟動時創建Service
,並在任務結束后立即終止。 換句話說, Service
的范圍和“任務”是相同的。
相反,你應該讓“任務”成為Service
的孩子; Service
存在時間應該比“任務”長一些。 特別是,只要Activity
開始, Service
應該可用(如果沒有其他原因,只能將有關“任務”狀態的信息傳達給Activity
)。
每當Activity
啟動時,它應該綁定到Service
,並注冊了一個監聽器Service
。 每當A.)監聽器被新注冊時, Service
調用此監聽器,或者B.)“任務”改變狀態(啟動或停止)。 因此,只要它與Service
綁定, Activity
就會立即通知狀態變化。
當Activity
希望“任務”改變狀態時,它應該通過綁定(或者可能是startService()
調用通知Service
,即使Service
已在運行)。 然后, Service
將啟動/停止后台線程(或者您為完成“任務”而執行的任何操作),並通知任何偵聽器。
如果Service
已運行“任務”一段時間,並且活動突然彈出,則Service
明確知道“任務”存在,並且Activity
將通過監聽器獲取該信息,只要它結合。
當Activity
停止時,它應該通過取消注冊其偵聽器並從Service
解除綁定來清理。
此方法不需要SharedPreferences
,也無需檢測Service
何時停止。 無論何時創建Service
,顯然“任務”沒有運行,因此Service
將始終知道給予Activity
的正確答案。 由於必須在綁定到Activity
之前創建Service
,因此不存在操作順序問題。
我重新設計了。 現在的流程是
輸入活動
bindService()
離開活動
unbindService()
啟用切換
startService()
禁用切換
stopService()
為此,我在服務中使用int變量SERVICE_START_COUNTER
並在onStartCommand()中增加其值。 當Activity綁定到服務時,我會收到SERVICE_START_COUNTER
。 根據計數器值,我可以區分服務是否正在運行
public boolean isServiceRunning(int SERVICE_START_COUNTER)
{
return SERVICE_START_COUNTER == 0 ? false : true;
}
基於這個值,我編寫了一個同步UI的方法。
public void syncUI(boolean isServiceRunning)
{
setToggleState(isServiceRunning);
setAniamtionState(isServiceRunning);
}
1)第一次輸入活動(仍然禁用切換)
onBind() // SERVICE_START_COUNTER = 0
2)首次輸入活動(用戶啟用切換)
onBind() // SERVICE_START_COUNTER = 0
onStartCommand() // SERVICE_START_COUNTER = 1
3)第二次重新進入活動(啟用切換)
onBind() // SERVICE_START_COUNTER = 1
4)服務被OS殺死。 重新進入活動
onBind() // SERVICE_START_COUNTER = 0
由於綁定需要時間(因為onServiceConnected())是異步調用的。 因此,結果可能無法立即獲得。 為此,我首先檢查Splash Activity中的服務狀態,並更新Utility類中的類似計數器。
您的問題是由於您使用Bounded Foreground服務引起的。 請參閱: https : //developer.android.com/guide/components/bound-services
綁定服務通常僅在它服務於另一個應用程序組件時才存在,並且不會無限期地在后台運行。
基本上,您的服務存在取決於是否綁定。
另一種方法是不使用Bind方法,而是使用Context.startService()或Context.startForegroundService()來啟動服務並讓它永遠運行。 像這樣的東西:
Intent intent = new Intent(getApplicationContext(), ForegroundService.class);
intent.setAction(ForegroundService.ACTION_START_FOREGROUND_SERVICE);
startService(intent);
ForegroundService類看起來像這樣:
public class ForegroundService extends Service {
private static final String TAG_FOREGROUND_SERVICE = "FOREGROUND_SERVICE";
public static final String ACTION_START_FOREGROUND_SERVICE = "ACTION_START_FOREGROUND_SERVICE";
public static final String ACTION_STOP_FOREGROUND_SERVICE = "ACTION_STOP_FOREGROUND_SERVICE";
public ForegroundService () {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG_FOREGROUND_SERVICE, "My foreground service onCreate().");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(intent != null)
{
String action = intent.getAction();
switch (action)
{
case ACTION_START_FOREGROUND_SERVICE:
startForegroundService();
break;
case ACTION_STOP_FOREGROUND_SERVICE:
stopForegroundService();
break;
}
}
return super.onStartCommand(intent, flags, startId);
}
private void startForegroundService()
{
// Build the notification.
// ... lot of code ...
Notification notification = builder.build();
// Start foreground service.
startForeground(1, notification);
}
private void stopForegroundService()
{
// Stop foreground service and remove the notification.
stopForeground(true);
// Stop the foreground service.
stopSelf();
}
}
在這種情況下,您不需要同步服務狀態,因為它將盡可能長時間處於活動狀態,並且只有在調用stopSelf()時才會停止。 即使應用程序進入后台,該服務也不會停止。
此外,您可以使用Broadcast result,livedata或EventBus方法在服務和活動之間進行同步/通信。
我希望這個答案有所幫助。 如果這不是你想要的,我道歉。 這只是一個想法。
嘗試覆蓋服務的onTaskRemoved()方法,並在方法中將切換值更新為false。 查看此文檔
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.