简体   繁体   English

适用于GPS服务的Android Wakelock

[英]Android Wakelock for GPS Service

I'm developing an app which gets GPS Location every ten minutes and sends it to a server, in order to do that I use a Timer, requestLocationUpdates and Android Asynchronous Http Client library. 我正在开发一个每十分钟获取一次GPS位置并将其发送到服务器的应用程序,为此,我使用了Timer,requestLocationUpdates和Android异步Http客户端库。 The positions need to be saved for up to 12 hours every ten minutes. 每十分钟最多需要保存12个小时的职位。

To keep an app alive, I use wakelock in onCreate inside Service 为了保持应用程序的生命力,我在Service内部的onCreate中使用了唤醒锁

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

and onDestroy() 和onDestroy()

    wl.release();

The service is started and stopped by buttons in MainActivity. 该服务通过MainActivity中的按钮启动和停止。 My main problem is that I only get the position twice (on start and after 10mins, no position update after 20mins) if user presses Home Button and moves the app to back. 我的主要问题是,如果用户按下主屏幕按钮并将应用程序移回原位,我只会获得两次位置(在开始时和10分钟后,在20分钟后没有位置更新)。 It seems to be okay as long as I lock the screen on the app, but the process seems to be killed after few minutes when I lock on Home Screen. 只要锁定应用程序上的屏幕似乎还可以,但是锁定主屏幕后几分钟,该过程似乎被终止。

Here is the whole code of my GPS Service: 这是我的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;
    }
}

To expand @CommonsWare comment . 扩展@CommonsWare 评论 Setting up a service for this is a bad idea - and also does not work as you have seen. 为此设置服务不是一个好主意-而且也无法正常工作。 Android kills it and the party is over. Android杀死了它,聚会结束了。 To do any periodic task you have to setup an alarm using the alarm manager. 要执行任何定期任务,您必须使用警报管理器设置警报。 To do this register an alarm - better in some receiver that is setup to receive on boot - cause when rebooting all your alarms go bye bye: 为此,请注册一个警报-在某些设置为在启动时接收的接收器中更好-在重新启动所有警报时会再见:

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"));
}

Then in the onReceive of the receivers registered to receive the broadcast from the AlarmManager (they hold wakelocks for you that never fail) delegate to a WakefulIntentService 然后在注册为从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);
    }
}

Alternatively to use a wakeful intent service you can use a WakefulBroadcastReceiver - but you have to write the service. 另外,要使用唤醒意图服务,可以使用WakefulBroadcastReceiver-但必须编写服务。 The (my) code is here - works! (我的)代码在这里 -有效!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM