当手机状态为待机时,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的主要内容,如果未能解决你的问题,请参考以下文章

Vivo y51开机时一直提示正在优化怎么办?

MailChimp Api v1.3 如何将订阅者设置为待处理

根据运输方式更改 Woocommerce 订单状态

使用状态机时如何在向导中配置动态表单字段

重启手机后报警通知数据消失

如果在设计有限状态机时,未使用状态的下一个状态设置为初始状态,这种方法称为最小状态( )接近?