当手机状态为待机时,ActivityRecognitionClient requestActivityUpdates() 方法不会触发给定的 PendingIntent
Posted
技术标签:
【中文标题】当手机状态为待机时,ActivityRecognitionClient requestActivityUpdates() 方法不会触发给定的 PendingIntent【英文标题】:ActivityRecognitionClient requestActivityUpdates() method doesn't trigger given PendingIntent when phone state is stand by 【发布时间】:2014-04-12 19:21:41 【问题描述】:我编写了一个应用程序来定期(在后台)记录用户的位置。我使用了 ActivityRecognitionClient。收到活动后,会将其与之前的活动状态进行比较,并根据评估记录(或不记录)。
只要我的手机处于唤醒状态,它就会按预期工作。 (日志消息定期出现在 Eclipse 的 LogCat 视图中)每当屏幕关闭并且设备进入待机状态时,它就会停止接收活动识别调用。另一方面,我也在平板电脑上安装了该应用程序,即使设备进入待机状态,它也会不断更新。 (顺便说一句,我的手机是 General Mobile Discovery)
我已经搜索了 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,因此它在首次安装时开始运行。)
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(此服务连接到 ActivityRecognitionClient 并注册一个 PendingIntend 以通过活动更新调用。当它工作时调用 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() 方法被 Activity Recognition 更新调用)
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);
【问题讨论】:
【参考方案1】:我假设您需要设置一些 Power Wake 锁定以使手机即使在“睡眠”模式下也能处理 GPS 位置。像 WiFi 锁等。当我做类似的事情时,我使用:
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
if (pm!=null)
pmWakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK+PowerManager.ON_AFTER_RELEASE, APP_TAG);
pmWakeLock.acquire();
但那是在 GPS 跟踪活动中。您需要根据需要更改 newWakeLock 的参数。也许您正在使用的服务有一些关于它的代码,所以您只需要先在 Manifest 中声明使用 WakeLock 权限。
【讨论】:
我在某个时候尝试过。这就是清单文件中有 WAKE_LOCK 权限的原因。我认为活动识别应该唤醒手机。引用“通过定期唤醒设备并读取传感器数据的短脉冲来检测活动。它仅使用低功耗传感器以将功耗保持在最低水平。”来自developer.android.com/reference/com/google/android/gms/location/… 看起来像一个 AOS 困境:需要防止电池快速耗尽,但也必须在 bg 中做一些工作(我相信你明白 GPS“吃掉”电池,这就是它在睡眠中禁用的原因) ...因此,也许您需要一项显示地图或其他内容的活动,以便在您想跟踪 GPS 或同意在手机休眠时关闭 GPS 时使用我的代码之类的东西保持手机保持清醒。至少试一试。 好吧,谷歌定位服务应该是 gps 的低功耗替代品。 (它根据网络信息创建一个“融合”位置)这就是我不直接访问 GPS 的原因。 (这个应用程序的以前版本就是这样做的)无论如何,即使用户没有与手机交互,我也需要定期记录用户的位置。所以它需要在后台,因此我需要解决这个睡眠问题。 好吧,如果它是关于“网络”位置而不是 GPS,那么可能 PM 锁定 WiFi 应该可以解决问题 您能详细说明一下吗? WiFi上的PM锁怎么办?以上是关于当手机状态为待机时,ActivityRecognitionClient requestActivityUpdates() 方法不会触发给定的 PendingIntent的主要内容,如果未能解决你的问题,请参考以下文章