2010-05-05 50 views
46

我正在運行一項Web服務,該服務允許用戶將他們的旅行(類似Google的MyTracks)作爲較大應用程序的一部分進行記錄。問題在於,當用戶開始旅程或結束旅程時,很容易將數據(包括座標和其他項目)傳遞到服務器。作爲一個新手,我不知道如何設置一個後臺服務,每隔(預定)時間段(最少3分鐘,最長1小時)發送位置更新一次,直到用戶標記行程結束,或直到預設的時間量過去了。Android:如何定期向服務器發送位置信息

一旦從手機開始旅行,服務器將以手機的輪詢週期作爲更新間隔的迴應。這部分工作,因爲我可以在手機上顯示響應,並且我的服務器註冊用戶的操作。同樣,在緊急旅程請求時,旅程將在服務器端關閉。

但是,當我嘗試從StartTrack Activity中啓動一個週期性的跟蹤方法時,使用requestLocationUpdates(String provider,long minTime,float minDistance,LocationListener listener)其中minTime是服務器的輪詢週期,它只是沒有工作,我沒有得到任何錯誤。所以這意味着我在這一點上毫無頭緒,以前從未使用過Android。

我在這裏看到很多關於使用後臺服務處理程序,待處理意圖和其他事情做類似的東西,但我真的不明白如何去做。我希望用戶在更新進行時在手機上做其他事情,所以如果你們可以指點我一個教程來展示如何實際編寫後臺服務(也許這些服務可以作爲單獨的類運行?)或其他方式這樣做,那會很棒。

謝謝!

回答

15

您需要創建一個單獨的類,該類是Service類的子類。

Service Documentation

您的主要應用程序應該可以調用startServicestopService啓動後臺進程。也Theres在上下文類其他一些有用的呼叫管理服務:

Context Documentation

+0

萬分感謝。我已經能夠建立服務,啓動和停止它。我現在必須確保系統不會殺死它,並且根據需要調用它。 – Mark 2010-05-06 15:45:02

+2

請記住,操作系統會定期停止(並重新啓動)您認爲合適的服務:http://developer.android.com/reference/android/app/Service.html#ProcessLifecycle – jscharf 2010-05-06 17:47:56

+0

jscharf,我如何確保該服務被保證被定期調用,並且只在那時運行,直到用戶執行特定的操作來停止呼叫爲止?我正在尋找使用警報,並通過文檔瞭解如何使用它們...... – Mark 2010-05-06 18:25:08

71

我最近寫了其中一個,並決定它是不是一個好主意離開後臺服務運行。無論如何,它可能會被操作系統關閉,或者它可能會被操作系統關閉。我所做的是爲引導意圖使用過濾器,然後使用警報管理器設置警報,以便我的應用程序定期重新啓動,然後發送數據。您可以在Android文檔中找到關於服務和鬧鐘管理器的更多信息。

首先,我創建了一個廣播接收器,當互聯網連接打開時我只需啓動我的服務(我只關心是否存在連接 - 您可能還想過濾引導事件)。這次發射接收機必須是短暫的,所以剛開始你的服務:

public class LaunchReceiver extends BroadcastReceiver { 

    public static final String ACTION_PULSE_SERVER_ALARM = 
      "com.proofbydesign.homeboy.ACTION_PULSE_SERVER_ALARM"; 

    @Override 
    public void onReceive(Context context, Intent intent) { 
     AppGlobal.logDebug("OnReceive for " + intent.getAction()); 
     AppGlobal.logDebug(intent.getExtras().toString()); 
     Intent serviceIntent = new Intent(AppGlobal.getContext(), 
       MonitorService.class); 
     AppGlobal.getContext().startService(serviceIntent); 
    } 
} 

在清單中,我有:

<receiver 
    android:name="LaunchReceiver" 
    android:label="@string/app_name" > 
    <intent-filter> 
     <action android:name="android.net.conn.CONNECTIVITY_CHANGE" /> 
    </intent-filter> 
    <intent-filter> 
     <action android:name="com.proofbydesign.homeboy.ACTION_PULSE_SERVER_ALARM" /> 
    </intent-filter> 
</receiver> 

通知我如何有一個過濾器爲我自己報警,這是什麼讓我關閉服務並在服務完成後重新啓動服務。

我的顯示器業務的頂部看起來像:

public class MonitorService extends Service { 

    private LoggerLoadTask mTask; 
    private String mPulseUrl; 
    private HomeBoySettings settings; 
    private DataFile dataFile; 
    private AlarmManager alarms; 
    private PendingIntent alarmIntent; 
    private ConnectivityManager cnnxManager; 

    @Override 
    public void onCreate() { 
     super.onCreate(); 
     cnnxManager = (ConnectivityManager) 
       getSystemService(Context.CONNECTIVITY_SERVICE); 
     alarms = (AlarmManager) getSystemService(Context.ALARM_SERVICE); 
     Intent intentOnAlarm = new Intent(
       LaunchReceiver.ACTION_PULSE_SERVER_ALARM); 
     alarmIntent = PendingIntent.getBroadcast(this, 0, intentOnAlarm, 0); 
    } 

    @Override 
    public void onStart(Intent intent, int startId) { 
     super.onStart(intent, startId); 
     // reload our data 
     if (mPulseUrl == null) { 
      mPulseUrl = getString(R.string.urlPulse); 
     } 
     AppGlobal.logDebug("Monitor service OnStart."); 
     executeLogger(); 
    } 

executeLogger啓動一個的AsyncTask,這也許是我過分謹慎(這只是我的第三個Android應用程序)。該的AsyncTask抓住GPS數據,將其發送到互聯網,並最終設置一個報警:

private void executeLogger() { 
    if (mTask != null 
     && mTask.getStatus() != LoggerLoadTask.Status.FINISHED) { 
     return; 
    } 
    mTask = (LoggerLoadTask) new LoggerLoadTask().execute(); 
} 

private class LoggerLoadTask extends AsyncTask<Void, Void, Void> { 

    // TODO: create two base service urls, one for debugging and one for live. 
    @Override 
    protected Void doInBackground(Void... arg0) { 
     try { 
      // if we have no data connection, no point in proceeding. 
      NetworkInfo ni = cnnxManager.getActiveNetworkInfo(); 
      if (ni == null || !ni.isAvailable() || !ni.isConnected()) { 
       AppGlobal 
         .logWarning("No usable network. Skipping pulse action."); 
       return null; 
      } 
      ///grab and log data 
     } catch (Exception e) { 
      AppGlobal.logError(
        "Unknown error in background pulse task. Error: '%s'.", 
        e, e.getMessage()); 
     } finally { 
      // always set the next wakeup alarm. 
      int interval; 
      if (settings == null 
       || settings.getPulseIntervalSeconds() == -1) { 
       interval = Integer 
         .parseInt(getString(R.string.pulseIntervalSeconds)); 
      } else { 
       interval = settings.getPulseIntervalSeconds(); 
      } 
      long timeToAlarm = SystemClock.elapsedRealtime() + interval 
       * 1000; 
      alarms.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, timeToAlarm, 
        alarmIntent); 
     } 
     return null; 
    } 
} 

我注意到,我沒有設置報警後調用stopSelf(),所以我的服務將坐在那裏什麼都不做,除非由操作系統關閉。由於我是這個應用程序的唯一用戶,這對公共應用程序無關緊要,所以您的想法是爲下一個時間間隔設置鬧鐘,然後stopSelf關閉。

更新查看@juozas關於使用'alarms.setRepeating()'的評論。

+0

羅布,謝謝。我現在正在搜索文檔以查看如何使用意圖過濾器以及如何設置鬧鐘以定期調用服務,而不是一直運行。 – Mark 2010-05-06 16:09:05

+0

馬克,我發佈了我的代碼 - 希望它有幫助。 – 2010-05-09 10:35:45

+0

再次感謝羅伯。 – Mark 2010-05-19 18:32:56

2

我同意Rob Kent,另外我認爲可能會在您的BroadcastReceiver中擴展WakefulBroadcastReceiver並使用它的靜態方法startWakefulService(android.content.Context context,android.content.Intent intent),因爲它會保證您的服務不會被OS關閉。

public class YourReceiver extends WakefulBroadcastReceiver { 
    @Override 
    public void onReceive(Context context, Intent intent) { 

     Intent service = new Intent(context, YourService.class); 
     startWakefulService(context, service); 
    } 
} 

Official documentation

相關問題