Android GPS 服务唤醒锁

Android Wakelock for GPS Service

我正在开发一个应用程序,它每十分钟获取一次 GPS 位置并将其发送到服务器,为此我使用了计时器、requestLocationUpdates 和 Android 异步 Http 客户端库。位置需要每十分钟最多保存 12 小时。

为了让应用程序保持活动状态,我在服务内的 onCreate 中使用唤醒锁

    PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
    wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "whatever");
    wl.acquire();

和 onDestroy()

    wl.release();

通过 MainActivity 中的按钮启动和停止服务。我的主要问题是,如果用户按下主页按钮并将应用程序移回,我只会获得两次位置(开始时和 10 分钟后,20 分钟后没有位置更新)。好像只要在应用上锁屏就可以了,但是当我锁在主屏幕上几分钟后进程似乎被杀死了。

这是我的 GPS 服务的完整代码:

public class UpdatePositionService extends Service {

    private PowerManager.WakeLock wl;
    private Handler mHandler = new Handler(Looper.getMainLooper());
    private AsyncHttpClient client = new AsyncHttpClient();
    private SharedPreferences preferences;
    public static final String USER_PREFERENCES = "userPreferences";
    private Timer updatingTimer;
    private TimerTask task = new TimerTask() {
        @Override
        public void run() {
            mHandler.post(new Runnable() {
                public void run() {
                    preferences = getSharedPreferences(USER_PREFERENCES, MODE_PRIVATE);
                    final String uid = preferences.getString("userid", "");
                    final String pause = readFromFile("pause.txt");
                    final String userState = readFromFile("user.txt");
                    final String workid = readFromFile("work.txt");
                    final String consid = readFromFile("cons.txt");
                    if (!pause.equals("1") && !userState.equals("0")) {
                        Log.e("mmd:test:123", "dochodzi  " + userState);
                        final LocationManager[] lm = {(LocationManager)
                            getSystemService(Context.LOCATION_SERVICE)};
                        Criteria criteria = new Criteria();
                        criteria.setAccuracy(Criteria.ACCURACY_FINE);
                        criteria.setPowerRequirement(Criteria.POWER_HIGH);
                        _if();
                        lm[0].requestLocationUpdates(LocationManager
                            .GPS_PROVIDER, 6000, 10, new LocationListener() {
                            @Override
                            public void onLocationChanged(Location location) {
                                String updatedPause = readFromFile("pause.txt");

                                _if();
                                lm[0].removeUpdates(this);
                                lm[0] = null;
                                if (!updatedPause.equals("1")) {
                                    RequestParams params = new RequestParams();
                                    params.put("uid", uid);
                                    params.put("lat", location.getLatitude());
                                    params.put("long", location.getLongitude());
                                    params.put("workid", workid);
                                    params.put("type", userState);
                                    params.put("cons", consid);
                                    String url = "http://example.com/api/event/add";
                                    client.post(url, params,
                                      new AsyncHttpResponseHandler() {
                                        @Override
                                        public void onSuccess(int statusCode,
                                        Header[] headers, byte[] responseBody) {
                                            String response = new String(
                                                responseBody);
                                            if (!response.equals("ERROR")) {
                                            } else {
                                            }
                                        }

                                        @Override
                                        public void onFailure(
                                            int statusCode, Header[] headers,
                                            byte[] responseBody,
                                            Throwable error) {}
                                    });
                                }
                            }

                            @Override
                            public void onStatusChanged(String provider, int
                                status, Bundle extras) {}

                            @Override
                            public void onProviderEnabled(String provider) {}

                            @Override
                            public void onProviderDisabled(String provider) {}
                        });
                    }
                }
            });
        }
    };

    private void _if() {
        if (ActivityCompat.checkSelfPermission(UpdatePositionService.this,
            Manifest.permission.ACCESS_FINE_LOCATION) !=
            PackageManager.PERMISSION_GRANTED &&
            ActivityCompat.checkSelfPermission(UpdatePositionService.this,
                Manifest.permission.ACCESS_COARSE_LOCATION) !=
                PackageManager.PERMISSION_GRANTED) {}
    }

    @Override
    public void onCreate() {
        super.onCreate();
        updatingTimer = new Timer();
        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
        wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager
            .ACQUIRE_CAUSES_WAKEUP, "whatever");
        wl.acquire();
    }

    @Override
    public void onDestroy() {
        updatingTimer.cancel();
        mHandler.removeCallbacksAndMessages(null);
        wl.release();
        super.onDestroy();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        int time = 1000 * 60 * 10; // 10 mins
        updatingTimer.scheduleAtFixedRate(task, 3000, time);
        return START_NOT_STICKY;
    }

    @Override
    public IBinder onBind(Intent arg0) {
        return null;
    }

    private String readFromFile(String filename) {
        String ret = "";
        try {
            InputStream inputStream = openFileInput(filename);
            if (inputStream != null) {
                InputStreamReader inputStreamReader = new InputStreamReader
                    (inputStream);
                BufferedReader bufferedReader = new BufferedReader
                    (inputStreamReader);
                String receiveString = "";
                StringBuilder stringBuilder = new StringBuilder();
                while ((receiveString = bufferedReader.readLine()) != null) {
                    stringBuilder.append(receiveString);
                }
                inputStream.close();
                ret = stringBuilder.toString();
            }
        } catch (FileNotFoundException e) {
            Log.e("login activity", "File not found: " + e.toString());
        } catch (IOException e) {
            Log.e("login activity", "Can not read file: " + e.toString());
        }
        return ret;
    }
}

扩展@CommonsWare 。为此设置服务是个坏主意——而且也不像您所看到的那样工作。 Android 杀了它,派对结束了。要执行任何周期性任务,您必须使用警报管理器设置警报。要做到这一点,请注册一个警报 - 在某些设置为在启动时接收的接收器中更好 - 因为在重新启动时,所有警报都会再见:

private void setupAlarm(Context context, boolean setup) {
    am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    pi = PendingIntent.getBroadcast(context, NOT_USED, yourIntent,
                                    PendingIntent.FLAG_UPDATE_CURRENT);
    if (setup) { // setup the alarms
        try {
            am.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                SystemClock.elapsedRealtime() + SOME_DELAY, THE_INTERVAL_BETWEEN_ALARMS, pi);
        } catch (InstantiationException e) {
            // should not happen
            throw new RuntimeException(UNABLE_TO_SET_ALARMS, e);
        } catch (IllegalAccessException e) {
            // should not happen
            throw new RuntimeException(UNABLE_TO_SET_ALARMS, e);
        }
    } else { // teardown the alarms
        // send message to the monitors that the party is over
        Intent i = new Intent(YOUR_ABORTING_ACTION, Uri.EMPTY, context, YOUR_SERVICE_CLASS);
        WakefulIntentService.sendWakefulWork(context, i);
        // cancel the alarms
        am.cancel(pi);
    }
    d("alarms " + (setup ? "enabled" : "disabled"));
}

然后在注册接收来自 AlarmManager 的广播的接收器的 onReceive 中(它们为您保留永远不会失败的唤醒锁)委托给 WakefulIntentService

@Override
final public void onReceive(Context context, Intent intent) {
    final String action = intent.getAction();
    if (ac_setup_alarm.equals(action) || ac_cancel_alarm.equals(action)) {
        monitoringIntent = new Intent(context, this.getClass());
        monitoringIntent.setAction(ac_monitor.toString());
        final boolean enable = ac_setup_alarm.equals(action);
        setupAlarm(context, enable);
    } else if (ac_monitor.equals(action)) {
        // monitoring - got broadcast from ALARM
        WakefulIntentService.sendWakefulWork(context, YOUR_SERVICE_CLASS);
    } else if (ac_reschedule_alarm.equals(action)) {
        monitoringIntent = new Intent(context, this.getClass());
        monitoringIntent.setAction(ac_monitor.toString());
        rescheduleAlarm(context);
    } else {
        w("Received bogus intent : " + intent);
    }
}

或者,要使用唤醒意图服务,您可以使用 WakefulBroadcastReceiver - but you have to write the service. The (my) code is here - 有效!