Android 定期 GPS 轮询服务,最大限度地延长电池寿命 [英] Android Regular GPS Polling in Service, maximizing battery life

查看:22
本文介绍了Android 定期 GPS 轮询服务,最大限度地延长电池寿命的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个服务,它将每 X 分钟尝试获取设备的 GPS 位置,并在后台运行和记录,即使应用程序未处于焦点状态.

那么,是时候创建一个服务了.

我创建了一个服务,设置了 locationListener,获得了位置管理器和 requestLocationUpdates...世界上一切都很好......基本框架工作.

现在,我不希望 GPS 一直运行,因为这会耗尽电池电量,我希望发生的是服务,启动 GPS,要求更新,然后关闭(至少它对gps 位置),然后 5 或 10 分钟后再次执行此操作..

很简单,在我的监听器的 onLocationChanged() 方法上,我添加了一行 LocationManager (removeUpdates(locationListener))..所以当我的服务请求更新时,它只得到一个,然后关闭.

我决定添加一个 while 循环,它可以有效地注册我的位置侦听器,并休眠 X 分钟.所以从逻辑上讲,它应该注册它想要的信息,然后睡眠.. 一个更新进来,我在 onLocationChange 中获得该更新,它取消注册它对事件的兴趣,关闭 GPS 直到下一次执行循环.

现在,我有 2 个问题 1) 这在逻辑上看起来没问题吗?还是有更优雅的方式?请记住,我希望它记录启动应用程序是否处于焦点状态的信息,老实说,即使启动应用程序被终止,也希望服务继续运行,但这是我尚未完全做出的设计决定.

第二个问题是,我需要把这个 LOOP 放在一个线程中,因为它在 oncreate 中,导致服务最终被杀死,因为它需要很长时间才能从 oncreate 返回,那么最好的方法是什么去做这件事?AsyncTask 是一个选项,但这是一个理论上永远不会完成的任务. Handler 似乎也有点傻,因为没有真正的回调,它只是注册 GPS 更新,而无趣的代码在 LocationListener 中onLocationChange().

一旦实例化,这个线程就不会产生真正的通信,尽管当服务将被某些用户交互关闭时,它需要被告知死亡/结束......

>

那么我应该只使用基本线程吗?使用 AsyncTask 即使它永远不会真正回来?还是使用 Handler 是更好的选择?还是我的模型一开始就完全不合格?

解决方案

我认为拥有管理 GPS 的服务是明智的做法,尤其是当您有多个活动可能需要位置信息时.我在我的应用中采用了这种方法.

首先,我在服务中使用了一个 Ibinder 并使用

从活动中绑定到它

bindService (new Intent(....), mServconn, Context.BIND_AUTO_CREATE);

在 onStart()

unbindService(mServconn); 在每个活动的 onStop() 中

我让服务使用 sendBroadcast()BroadcastReceivers 在活动中注册.位置数据通过广播 Intent 中的 extra 传递.

我在服务中使用了具有 3 个状态的状态机,IDLE、SEEKING 和 GOT_A_FIX_NOW_SLEEPING.睡眠时间通过服务的公共方法中公开的changeGPSParameters"方法传入.另一个参数是所需的准确度,即在您得到比所需准确度更好的修复之前不要广播消息,然后您就可以睡觉了.睡眠意味着关闭 GPS,直到时间过去.

时间由一个 Runnable 管理,一个 Handler 用类似的代码向它发送消息

mHandler.postDelayed(this, mSleepTime);

我觉得这很好用.当没有活动绑定到服务时,onUnbind() 将在服务中运行.在该方法中,您只需要确保停止位置侦听器并使用 mHandler.removeCallbacks

停止计时器

更新

下面是一个简单的 Runnable 示例,您可以通过 main.xml 中的两个按钮启动/停止,其中应该有一个文本视图来显示计时器状态:

import android.app.Activity;导入 android.os.Bundle;导入 android.os.Handler;导入 android.view.View;导入 android.widget.TextView;公共类 TimerLoopActivity 扩展 Activity {私有处理程序 mHandler = 新处理程序();私人 int mSleepTime = 2;//秒私有 int mLoopCount = 0;private Runnable mUpdateTimeTask = new Runnable() {公共无效运行(){//此处为计时器完成时的代码mLoopCount++;setTextBoxMsg("运行 - 计数 = " + mLoopCount);mHandler.removeCallbacks(this);mHandler.postDelayed(this, mSleepTime * 1000);//继续循环}};@覆盖public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);setTextBoxMsg("定时器空闲");}私人无效setTextBoxMsg(字符串字符串){TextView tv = (TextView) findViewById(R.id.textView1);tv.setText(string);}public void myClickHandler(查看目标){开关(target.getId()){案例R.id.startbutton:setTextBoxMsg("启动计时器");开始定时器();休息;案例R.id.stopbutton:setTextBoxMsg("停止计时器");mLoopCount = 0;停止定时器();休息;}}private void stopTimer() { mHandler.removeCallbacks(mUpdateTimeTask);}private void startTimer() { mHandler.postDelayed(mUpdateTimeTask, mSleepTime * 1000);}}

您可以对此进行调整以将其用于您的服务中.

I am attempting to write a service, that will every X minutes attempt to get the GPS location of the device, and run and record in the background even when the app is not in focuse.

So, time to create a service.

I created a service, set up the locationListener, got the location Manager and requestLocationUpdates... all is good with the world.. rudimentary skeleton working.

Now, I don't want the GPS running constantly as this will kill the battery, what I would like to happen is the service, fire up the GPS, ask for an update, then shut down (at least its interest in the gps location) and then 5 or 10 minutes later do this again..

Simple enough, on the onLocationChanged() method of my listener, I add the line LocationManager (removeUpdates(locationListener)).. so when my service asks for an update, it gets only one, and shuts down.

I decide to add a little while loop, that effectively registers my location listener, and sleeps for X minutes. So logically, it should register that it wants information, then sleep.. an update comes in, I get that update in the onLocationChange and it unregisteres its intereste in the event, shutting down the GPS until the next execution of the loop.

Now, I have 2 questions 1) Does this logically seem okay? or is there a more elegant way? Remember I want this to record information whether or not the launching application is in focus, and honestly even if the launching app was killed would like the service to continue running potentially but that's a design decision I haven't fully made yet.

The 2nd question is, I will need to put this LOOP inside a thread since having it in the oncreate, causes the service to eventually be killed because its taking too long to come back from oncreate, so what would be the best way to go about doing this? AsyncTask is an option, but this is a task that is never in theory going to finish.. Handler also seems sort of silly, as there are no real callbacks, its just registering for the GPS updates, and the uninterest code is in the LocationListener onLocationChange().

There is no real communication that would come out of this thread once instantiated, though it would need to be signaled to die/end when the service is going to be shut down by some user interaction to do so...

So should I just just use a base thread? Go with an AsyncTask even though its never really coming back? or is using the Handler the better option? Or is my model just complete bad form out of the gate?

解决方案

I think having a service to manage the GPS is the sensible way to go, especially if you have more than one activity which might want location information. I adopted such an approach in my app.

Firstly I used an Ibinder in the service and bound to it from the activities with

bindService (new Intent(....),   mServconn, Context.BIND_AUTO_CREATE);

in onStart()

and unbindService(mServconn); in onStop() of each activity

I had the service use sendBroadcast() to BroadcastReceivers registered in the activities. The location data is passed via extras in the broadcast intent.

I used a state machine in the service with 3 states, IDLE, SEEKING and GOT_A_FIX_NOW_SLEEPING. The sleep time is passed in through a 'changeGPSParameters' method exposed in a public method of the service. Another parameter is the required accuracy, i.e. don't broadcast a message until you've had a fix better than the the required accuracy, then you can sleep. Sleep means turn off the GPS until the time has elapsed.

The timing is managed by a Runnable and a Handler posts messages to it with code like

mHandler.postDelayed(this, mSleepTime );

I find this works well. When no activities are bound to the service then onUnbind() will run in the service. In that method you just have to make sure that you stop the location listener and stop the timer with mHandler.removeCallbacks

UPDATE

Below is a simple example of a Runnable which you can start/stop by means of two buttons in your main.xml which should have a single textview to show the timer state:

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.TextView;

public class TimerLoopActivity extends Activity {

    private Handler mHandler = new Handler();
    private int mSleepTime  = 2; //seconds
    private int mLoopCount = 0;
    private Runnable mUpdateTimeTask = new Runnable() {
        public void run() {
            // Code here for when timer completes
            mLoopCount++;
            setTextBoxMsg("Running - count = " + mLoopCount);
            mHandler.removeCallbacks(this);
            mHandler.postDelayed(this, mSleepTime * 1000); // keep looping
        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        setTextBoxMsg("Timer Idle");
    }

    private void setTextBoxMsg(String string) {
        TextView tv = (TextView) findViewById(R.id.textView1);
        tv.setText(string);
    }

    public void myClickHandler(View target) {
        switch (target.getId()) {
            case R.id.startbutton:
                setTextBoxMsg("Starting timer");
                startTimer();
                break;
            case R.id.stopbutton:
                setTextBoxMsg("Stopping timer");
                mLoopCount = 0;
                stopTimer();
                break;
        }
    }

    private void stopTimer() { mHandler.removeCallbacks(mUpdateTimeTask); }
    private void startTimer() { mHandler.postDelayed(mUpdateTimeTask, mSleepTime * 1000);}
}

You can adapt this to put it in your service.

这篇关于Android 定期 GPS 轮询服务,最大限度地延长电池寿命的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆