簡體   English   中英

如何將Toggle Button State與Foreground Service同步?

[英]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() )。 這是正確方法的線索。

很明顯,您了解在ActivityService之間交換信息的正確方法是通過綁定。 這是解決方案的另一個關鍵部分。

您應該延長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);
}

不同情況下SERVICE_START_COUNTER值?

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM