我編寫了一個應用程序來定期(在後臺)記錄用戶的位置。我使用了ActivityRecognitionClient。當收到活動時,它將與之前的活動狀態進行比較,並根據評估記錄(或不記錄)。ActivityRecognitionClient requestActivityUpdates()方法不會在電話狀態爲空時觸發給定的PendingIntent
只要我的手機保持清醒狀態,它就可以按預期工作。 (日誌消息定期出現在eclipse上的LogCat視圖中)每當屏幕熄滅且設備進入待機狀態時,它將停止接收活動識別呼叫。另一方面,我也在平板電腦上安裝了應用程序,即使設備進入待機狀態,它也會持續更新。 (我的手機是通用移動發現btw)
我一直在尋找網絡(包括stackoverflow問題)3天,一直沒能找到任何適合我的東西。我想感謝所有幫助...謝謝...
以下是我的應用程序相關的代碼:
AndroidManifest.xml中(有些權限是即使不需要存在,他們很可能是從失敗的試驗,以解決剩菜問題)
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.o3n.android.familywathcer"
android:installLocation="internalOnly"
android:versionCode="2"
android:versionName="1.0.1" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="19" />
<uses-feature
android:glEsVersion="0x00020000"
android:required="true"/>
<permission android:name="org.o3n.android.familywathcer.permission.MAPS_RECEIVE" android:protectionLevel="signature"/>
<uses-permission android:name="org.o3n.android.familywathcer.permission.MAPS_RECEIVE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION"/>
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<meta-data
android:name="com.google.android.maps.v2.API_KEY"
android:value="***maps api key *****"/>
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
<activity
android:name="org.o3n.android.familywathcer.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:label="Settings" android:name=".SettingsActivity">
<intent-filter>
<action android:name="org.o3n.android.familywatcher.SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<service android:enabled="true" android:name=".FamilyWatcherService" />
<service android:name=".ActivityRecognitionService" />
<receiver android:name=".StartFamilyWatcherServiceAtBootReceiver"
android:enabled="true"
android:exported="true"
android:label="StartFamilyWatcherServiceAtBootReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
StartFamilyWatcherServiceAtBootReceiver.java(此接收器開始在設備啓動的FamilyWatcherService.java,還應用MainActivity.java類調用FamilyWatcherService所以它開始此服務連接到ActivityRecognitionClient並註冊PendingIntend第一次安裝時正在競選。)
public class StartFamilyWatcherServiceAtBootReceiver extends BroadcastReceiver {
private static final String TAG = "o3nWatcherLog";
@Override
public void onReceive(Context context, Intent intent) {
//Toast.makeText(context, "StartFamilyWatcherServiceAtBootReceiver called", Toast.LENGTH_SHORT).show();
Log.d(TAG, "StartFamilyWatcherServiceAtBootReceiver onRecieve");
SettingsRetriever.getInstance(context);
Intent serviceIntent = new Intent(context, FamilyWatcherService.class);
context.startService(serviceIntent);
}
}
FamilyWatcherService.java(與活動更新調用。當它工作ActivityRecognitionService.onHandleIntend()方法被調用)
public class FamilyWatcherService extends Service implements ConnectionCallbacks, OnConnectionFailedListener {
private int period;
private static ActivityRecognitionClient arclient;
private static PendingIntent pIntent;
private static AlarmManager alarmManager;
private static PendingIntent alarmPI;
private static final String TAG = "o3nWatcherLog";
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
Log.d(TAG, "FamilyWatcherService onCreate");
period = SettingsRetriever.getInstance().getPeriod() * 60 * 1000;
}
@Override
public void onDestroy() {
Log.d(TAG, "FamilyWatcherService onDestroy");
if(arclient!=null){
arclient.removeActivityUpdates(pIntent);
arclient.disconnect();
}
}
@Override
public void onStart(Intent intent, int startid) {
Log.d(TAG, "FamilyWatcherService onStart");
processStart();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "FamilyWatcherService onStartCommand");
processStart();
return Service.START_STICKY;
}
public void processStart() {
int result = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getApplicationContext());
if (result != ConnectionResult.SUCCESS) {
Log.d("o3nWatcherLog", "Google Play service is not available (status=" + result + ")");
}
else{
arclient = new ActivityRecognitionClient(getApplicationContext(), this, this);
arclient.connect();
}
}
@Override
public void onConnectionFailed(ConnectionResult arg0) {
Log.d("o3nWatcherLog","Google activity recognition services connection failed");
}
@Override
public void onConnected(Bundle arg0) {
Log.d("o3nWatcherLog", "FamilyWathcerService onConnected method called...");
Intent intent = new Intent(this, ActivityRecognitionService.class);
pIntent = PendingIntent.getService(getApplicationContext(), 0, intent,PendingIntent.FLAG_UPDATE_CURRENT);
arclient.requestActivityUpdates(period, pIntent);
}
@Override
public void onDisconnected() {
Log.d("o3nWatcherLog", "Google activity recognition services disconnected");
}
}
ActivityRecognitionService.java(此服務的onHandleIntent()方法是通過行爲識別更新稱呼)
package org.o3n.android.familywathcer;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import org.json.JSONException;
import org.json.JSONObject;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks;
import com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener;
import com.google.android.gms.location.ActivityRecognitionResult;
import com.google.android.gms.location.DetectedActivity;
import com.google.android.gms.location.LocationClient;
import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.os.Bundle;
import android.util.Log;
public class ActivityRecognitionService extends IntentService implements ConnectionCallbacks, OnConnectionFailedListener {
private String TAG = "o3nWatcherLog";
private Context context;
private static int activityEvaluation = 0;
//TODO MAKE THESE PREFERENCES
private static final int MIN_RECORD_DISTANCE = 750;
private static final int MIN_RECORD_INTERVAL = 10 * 1000 * 60;
private static final int MIN_POST_INTERVAL = 2 * 1000 * 60;
//END MAKE THESE PREFERENCES
private LocationClient locationClient;
private static Location lastRecordedLocation;
private static int previousActivityCode = DetectedActivity.UNKNOWN;
private int activityCode = -1000;
private int activityConfidence = -1000;
public ActivityRecognitionService() {
super("My Activity Recognition Service");
}
@Override
protected void onHandleIntent(Intent intent) {
if(ActivityRecognitionResult.hasResult(intent)){
ActivityRecognitionResult result = ActivityRecognitionResult.extractResult(intent);
Log.i(TAG, getType(result.getMostProbableActivity().getType()) +"t" + result.getMostProbableActivity().getConfidence());
this.context = getApplicationContext();
Log.d("o3nWatcherLog", "ActivityRecognitionService onHandleIntent called...");
activityConfidence = result.getMostProbableActivity().getConfidence();
activityCode = result.getMostProbableActivity().getType();
Log.d("o3nWatcherLog", " ACTIVITY CODE : " + activityCode + " ACTIVITY CONFIDENCE : " + activityConfidence);
// Evaluate the avtivity recognition result
evaluateActivityResult();
// Get current location
// check Google Play service APK is available and up to date.
final int googlePlayServiceAvailable = GooglePlayServicesUtil.isGooglePlayServicesAvailable(context);
if (googlePlayServiceAvailable != ConnectionResult.SUCCESS) {
Log.d("o3nWatcherLog", "Google Play service is not available (status=" + result + ")");
}
else {
locationClient = new LocationClient(context, this, this);
locationClient.connect();
}
}
}
// This method is only used in a log line to have readable status in logs
private String getType(int type){
if(type == DetectedActivity.UNKNOWN)
return "UNKNOWN";
else if(type == DetectedActivity.IN_VEHICLE)
return "IN_VEHICLE";
else if(type == DetectedActivity.ON_BICYCLE)
return "ON_BICYCLE";
else if(type == DetectedActivity.ON_FOOT)
return "ON_FOOT";
else if(type == DetectedActivity.STILL)
return "STILL";
else if(type == DetectedActivity.TILTING)
return "TILTING";
else
return "";
}
private void evaluateActivityResult() {
// (Based on previousActivityCode and current activityCode
// assign a value to activityEvaluation)
// compare activityCode to previousActivityCode
activityEvaluation = ...;
previousActivityCode = activityCode;
}
private void actOnEvaluation(Location loc) {
// Based on activityEvaluation decide to post or not
if (activityEvaluation ....)
prepareTheLocationJsonAndRecord(loc);
}
private void prepareTheLocationJsonAndRecord(Location loc) {
// Record the location
}
@Override
public void onConnectionFailed(ConnectionResult arg0) {
//Toast.makeText(context, "Google location services connection failed", Toast.LENGTH_LONG).show();
Log.d("o3nWatcherLog","Google location services connection failed");
}
@Override
public void onDisconnected() {
//Toast.makeText(context, "Google location services disconnected", Toast.LENGTH_LONG).show();
Log.d("o3nWatcherLog", "Google location services disconnected");
}
@Override
public void onConnected(Bundle arg0) {
//Toast.makeText(context, "Google location services connected", Toast.LENGTH_LONG).show();
Log.d("o3nWatcherLog", "Google location services connected");
Location loc = locationClient.getLastLocation();
Log.d("o3nWatcherLog", "location= " + loc.toString());
if (loc!=null)
actOnEvaluation(loc);
}
}
我在某個時候試過。這就是爲什麼在清單文件中有WAKE_LOCK權限。我認爲活動的認可應該會喚醒電話。引用「通過定期喚醒設備並讀取短的突發傳感器數據來檢測活動,它只使用低功率傳感器,以便將功耗保持在最低水平。」來自http://developer.android.com/reference/com/google/android/gms/location/ActivityRecognitionClient.html – umutozkan
看起來像一個AOS的困境:需要防止快速的電池耗盡,但也必須做一些工作在BG(我你確定你明白GPS會「吃」電池,這就是爲什麼它在睡眠中被禁用)......所以,也許你需要一個顯示地圖或somethig的活動,以便當你想跟蹤GPS時保持手機與我的代碼類似的狀態,或者在電話睡眠時同意GPS關機。至少試一試。 – Stan
好的谷歌位置服務應該是一個低功耗的GPS替代品。(它從網絡信息創建一個「融合」的位置)這就是爲什麼我不直接訪問GPS。 (此應用的以前版本就是這樣做的)無論如何,即使用戶沒有與手機進行交互,我也需要定期記錄用戶的位置。所以它需要在後臺,因此我需要解決這個睡眠問題。 – umutozkan