2017-06-29 87 views
2

我的問題可能是服務的誤解和我對它們的使用,或者與其他應用程序的位置衝突。當我開始一個特定的活動時,我開始了兩個後臺服務 - 定位跟蹤以提供距離,以及已經過的計時器,這兩個服務都通過BroadcastReceiver傳遞給活動。我開始通過Intent對象與Long每個服務從我小學Activity導致崩潰的後臺服務

if (!Utils.isServiceRunning(this, TrackService.class)) { 
    Intent i = new Intent(this, TrackService.class); 
    i.putExtra("SUB_ID", submissionID); 
    startService(i); 
} 

而且我用下面的代碼來檢測,如果該服務已在運行:

public static boolean isServiceRunning(Activity activity, Class<?> serviceClass) { 
    ActivityManager manager = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE); 
    for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { 
     if (serviceClass.getName().equals(service.service.getClassName())) { 
      return true; 
     } 
    } 
    return false; 
} 

onStartCommand的例子如下:

@Override 
public int onStartCommand(Intent intent, int flags, int startId) { 
    submissionID = intent.getLongExtra("SUB_ID", 0L); 
    // I then use this submissionID to get other data 

    super.onStartCommand(intent, flags, startId); 
    return START_STICKY; 
} 

在某些設備上,這似乎完美工作 - 服務(S)工作ks在後臺,允許我在應用程序中使用其他活動&也可以進出應用程序,當我下次打開我的特定活動時,距離和時間會更新並更正。

但是,我收到很多崩潰報告,並且用戶的傳聞證據表明它在甩掉我的應用程序以使用相機之後(我尚未確定在使用其他應用程序時是否發生了崩潰應用程序,或者當他們重新進入我的應用程序):

Fatal Exception: java.lang.RuntimeException: Unable to start service [email protected] with null: java.lang.NullPointerException: Attempt to invoke virtual method 'long android.content.Intent.getLongExtra(java.lang.String, long)' on a null object reference 
    at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3149) 
    at android.app.ActivityThread.access$2500(ActivityThread.java:165) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1515) 
    at android.os.Handler.dispatchMessage(Handler.java:102) 
    at android.os.Looper.loop(Looper.java:135) 
    at android.app.ActivityThread.main(ActivityThread.java:5669) 
    at java.lang.reflect.Method.invoke(Method.java) 
    at java.lang.reflect.Method.invoke(Method.java:372) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:960) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755) 
Caused by java.lang.NullPointerException: Attempt to invoke virtual method 'long android.content.Intent.getLongExtra(java.lang.String, long)' on a null object reference 
    at edu.cornell.birds.ebird.services.TrackService.onStartCommand(TrackService.java:102) 
    at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3112) 
    at android.app.ActivityThread.access$2500(ActivityThread.java:165) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1515) 
    at android.os.Handler.dispatchMessage(Handler.java:102) 
    at android.os.Looper.loop(Looper.java:135) 
    at android.app.ActivityThread.main(ActivityThread.java:5669) 
    at java.lang.reflect.Method.invoke(Method.java) 
    at java.lang.reflect.Method.invoke(Method.java:372) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:960) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755) 

在我看來,由於某種原因該服務被停止和重新啓動不能從目的訪問數據時(我的理解一個空指針錯誤是什麼)。這是因爲我返回START_STICKY它在重新啓動時返回空數據?

有誰知道服務應該停止的任何原因嗎?我怎樣才能防止這種情況發生?

我無法重新使用我自己的設備(Moto G4,Android 7.0),它的工作原理與我所希望的一樣。

+0

你的'TrackService'類中有一個NullPointer在行號** 102 ** – SripadRaj

+0

可能重複[什麼是NullPointerException,我該如何解決它?](https://stackoverflow.com/questions/218384)/what-is-a-nullpointerexception-and-how-do-i-fix-it) – SripadRaj

+0

我的主要問題是「爲什麼服務應該停止」,這導致了NullPointer(我知道它是什麼)。 – iaindownie

回答

1

Android可以(並且會)在任何時候停止您的Service。由於您已經從onStartCommand()返回START_STICKY,因此Android在重新啓動Service後應該會被終止。在這種情況下,在重新啓動後,您將在onStartCommand()中收到空值Intent。如果想要,Android無法阻止您的Service

您需要定期將任何有用的數據保存在持久性存儲(SharedPreferences,文件,數據庫等)中,以便在重新啓動後進行恢復。

+0

簡潔的解釋,謝謝。 – iaindownie

0

對於這個問題快速解決方法是:

返回START_REDELIVER_INTENT在onStartCommand()回調在服務,而不是START_STICKY使整個意圖在重新啓動發送。

您可以用if條件類似這樣的包裝內onStartCommand代碼:

if (null == intent || null == intent.getAction()) { 


     return START_STICKY; 
}else{ 
    //ur code goes in 

    return START_STICKY; 
} 

之所以有這樣的空指針異常將是: 「如果沒有任何未決的START命令被傳送到服務,它將被調用一個空意圖對象,所以你必須小心檢查這一點。「

+0

謝謝。將使用START_REDELIVER_INTENT不會將位置跟蹤和已用時間重新設置爲起點嗎?如果發生這種情況,那麼數據將無用,因爲我需要繼續這些數據。我更關心試圖阻止它重新啓動,爲什麼它重新啓動。 – iaindownie

+0

它重新開始呼籲你這樣做,通過調用START_STICKY –

+0

好,道歉不超清,重新措詞:爲什麼服務停止? – iaindownie

1

Android中的任何內容都可能隨時被殺死,例如系統資源很少。所以你的代碼應該隨時準備好。而在後臺服務的處理方式會在O. 這給予了很大的變化,我想你可以閱讀Android documentation

「如果該服務尚未運行,它將被實例化,並開始(創建一個進程,如果需要的話);如果它正在運行,那麼它仍然在運行。每次調用此方法都會導致相應調用目標服務的onStartCommand(Intent,int,int)方法,其意圖在此處給出。「

所以不要將所有責任保留給調用者,但把它移動到被調用的地方,每當你需要傳遞一些信息時啓動該服務,然後讓該服務知道它是否被實例化並運行,以處理該情況。

// caller, no if-check here (no responsibility) 
startService(new Intent(this, TrackService.class).putExtra("SUB_ID", submissionID)); 

再在另一面,被調用的服務:

@Override 
    public int onStartCommand(Intent intent, int flags, int startId) { 
    if (intent == null) { 
     // do nothing and return 
     return START_STICKY; 
    } 

    // here your intent is not null, use it 
    submissionID = intent.getLongExtra("SUB_ID", 0L); 
    // if you got the most recent data already, do nothing 
    // else, retrieve data using the passed id 

    return START_STICKY; 

最後但並非最不重要,請注意,您無需致電super.onStartCommand(intent,flags,startId);,看看它的實現。 請記住責任倒置,因爲這是一種更一般的方法,您可以使用相當多的編碼Android,而不僅僅是在此示例中。希望能幫助到你!

0

您是否在清單文件的意向操作中註冊了您的廣播接收器?或dynamically

+0

動態。只有服務在清單中註冊。 – iaindownie

+1

然後檢查您是否在* OnResume *和* OnPause *上註冊和取消註冊接收器,並且檢查[Alessio's]的答案[https://stackoverflow.com/users/4469112/alessio] –