我有问题,经过一些搜索,我没有找到任何积极的解决方案。 经过研究,我认为我的问题没有实施,但这个问题可能是我的最后一次机会。
我需要获得什么?
有获得关于移动网络力量信号的信息的应用程序。我是这样做的
PhoneStateListener
。当然它工作得很好但是当我的设备进入睡眠模式时,监听器不起作用:
https://code.google.com/p/android/issues/detail?id=10931 https://code.google.com/p/android/issues/detail?id=7592
WakeLock
仅在设备因超时关闭时才解决问题。如果我按下硬电源按钮,我的设备也会进入睡眠模式。我们无法覆盖电源按钮操作。
我的目标是在我的设备启用时始终获得强度信号。什么模式无关紧要。它应该一直收集数据。
问题:
有什么想法吗?怎么实现呢?有没有办法做到这一点,或者可能有一些黑客?欢迎所有解决方案。如果您有一些有用的经验,请分享一下。
感谢所有人的帮助!!!我希望,这个主题将获得有关此问题的完整信息。
答案 0 :(得分:9)
警报管理器是可行的方法 - 棘手的部分是在警报管理器接收器返回后保持电话唤醒。所以
设置闹钟(注意你还应该注册一个“On Boot completed”接收器,以便在重新启动后设置闹钟 - 你的闹钟在重启后无法生存):
Intent monitoringIntent = new Intent(context, YourReceiver.class);
monitoringIntent.setAction("your action");
PendingIntent pi = PendingIntent.getBroadcast(context, NOT_USED,
monitoringIntent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am = (AlarmManager)
context.getSystemService(Context.ALARM_SERVICE);
// here is the alarm set up
am.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + INITIAL_DELAY,
INTERVAL_BETWEEN_ALARMS, pi);
接收它 - 接收方在其onReceive()
中保留一个永不失败的WakeLock:
public abstract class YourReceiver extends BroadcastReceiver {
@Override
final public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if ("your action".equals(action)) {
// monitoring - got broadcast from ALARM
try {
d("SS : " + new Signal().getSignalStrength(context));
} catch (InterruptedException e) {
e.printStackTrace();
}
// Actu8ally the lines above will ANR
// I did it with WakefulIntentService :
// WakefulIntentService.sendWakefulWork(
// context, YourWakefulService.class);
// Will be posting it asap
} else {
w("Received bogus intent : " + intent);
return;
}
}
}
如果你很幸运(yourRetrieveSignal()足够快),这将有效,否则你的接收器中需要一个(Wakeful)IntentService模式。
WakefulIntentService将处理唤醒锁(如果你想避免依赖看看here) - 编辑:请记住,你不能在意图服务中定义监听器 - 请参阅{{ 3}}
如果接收者ANR在你身上,你必须尝试WakefulIntentService模式。在任何一种情况下,您都可以使用here:
事实证明这是最困难的部分:
class Signal {
static volatile CountDownLatch latch; //volatile is an overkill quite probably
static int asu;
private final static String TAG = Signal.class.getName();
int getSignalStrength(Context ctx) throws InterruptedException {
Intent i = new Intent(TAG + ".SIGNAL_ACTION", Uri.EMPTY, ctx,
SignalListenerService.class);
latch = new CountDownLatch(1);
asu = -1;
ctx.startService(i);
Log.d(TAG, "I wait");
latch.await();
ctx.stopService(i);
return asu;
}
}
其中:
public class SignalListenerService extends Service {
private TelephonyManager Tel;
private SignalListener listener;
private final static String TAG = SignalListenerService.class.getName();
private static class SignalListener extends PhoneStateListener {
private volatile CountDownLatch latch;
private SignalListener(CountDownLatch la) {
Log.w(this.getClass().getName(), "CSTOR");
this.latch = la;
}
@Override
public void onSignalStrengthChanged(int asu) {
Signal.asu = asu;
latch.countDown();
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.w(TAG, "Received : " + intent.getAction());
Tel = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
listener = new SignalListener(Signal.latch);
@SuppressWarnings("deprecation")
final int listenSs = PhoneStateListener.LISTEN_SIGNAL_STRENGTH;
Tel.listen(listener, listenSs);
return START_STICKY;
}
@Override
public void onDestroy() {
Log.w(TAG, "onDestroy");
Tel.listen(listener, PhoneStateListener.LISTEN_NONE);
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
这是有效的代码(但不是优雅的顶峰 - 欢迎评论/更正)。不要忘记在清单中注册您的服务并获得权限
编辑2013.07.23:我没有使用onReceive
- 如果您使用它,它将是ANR - 如果您在onReceive
中使用WakefulIntentService并且在那里,那么这是有用的代码致电SignalListenerService
。
答案 1 :(得分:1)
根据我对PhoneStateListener的理解,当应用程序CPU处于睡眠模式时,您无法执行此操作。你可以保持设备清醒,这会破坏电池寿命。或者,您可以使用警报(请参阅AlarmManager)按时间间隔唤醒设备,以便您可以收集数据(仍会影响电池寿命)。
答案 2 :(得分:1)
CommonsWare的位置轮询示例非常适合唤醒手机并再次入睡。我认为这可能会有所帮助:https://github.com/commonsguy/cwac-locpoll
答案 3 :(得分:0)
android问题10931的一个可能的解决方法是将android.intent.action.SCREEN_ON
意图发送到'手机'屏幕关闭后的过程。
创建并注册BroadcastReceiver
以在屏幕关闭时收听通知
start(Context context) {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
context.registerReceiver(mScreenReceiver, filter);
}
final BroadcastReceiver mScreenReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) {
Log.v(LOGTAG, "Screen is off. Running workaround");
new Thread(mReportScreenIsOnRunnable).start();
}
}
};
仅将SCREEN_ON
意图发送到手机流程。
public final Runnable mReportScreenIsOnRunnable = new Runnable() {
@Override
public void run() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
Runtime.getRuntime().exec(new String[] { "su", "-c",
"am broadcast -a android.intent.action.SCREEN_ON com.android.phone" });
} catch (IOException e) {
e.printStackTrace();
}
}
};
收到此意图后,电话流程将恢复发送小区位置 更新。
需要root权限。
这个解决方案有点hacky,危险,并不适用于所有手机。它可以导致更高的功耗,但不会比你保持屏幕开启更多。