唤醒锁和 wifilock 不工作
Wakelock and wifilock not working
我已经在 SO 上阅读了大量关于使用 WakeLock 和 WifiLock 的教程和帖子,但仍然没有解决我的问题。
我正在编写一个应用程序,当您启动它时,它的唯一作用是创建和启动(前台)服务。此服务 运行 两个线程,即 UDP 广播侦听器(使用 java.io)和 TCP 服务器(使用 java.nio)。在服务的 onCreate 中,我获取了一个唤醒锁和一个 wifilock,并在 onDestroy 中释放它们。
只要 phone 处于唤醒状态,一切正常,但是当显示器关闭时,UDP 广播接收器停止接收广播消息,并且在我再次打开显示器之前不会收到任何消息。实际上,这些锁根本不起作用,放置它们也没有区别……我哪里错了?我确定我在某个地方做了一些愚蠢的事情,但我自己找不到。
这是一些代码:
这就是 Activity 的作用:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
onlyStartService = true;
}@Override
protected void onStart() {
super.onStart();
Intent bIntent = new Intent(this, FatLinkService.class);
getApplicationContext().startService(bIntent);
getApplicationContext().bindService(bIntent, flConnection, BIND_AUTO_CREATE);
}
// service connection to bind idle service
private ServiceConnection flConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder binder) {
linkService.MyLinkBinder flBinder = (LinkService.MylinkBinder) binder;
flServiceInstance = flBinder.getService();
if (onlyStartService) {
condLog("Service bound and finishing activity...");
finish();
}
}
public void onServiceDisconnected(ComponentName className) {
flServiceInstance = null;
}
};
@Override
protected void onStop() {
super.onStop();
if (fatFinish) {
Intent bIntent = new Intent(this, FatLinkService.class);
flServiceInstance.stopServices();
flServiceInstance.stopForeground(true);
flServiceInstance.stopService(bIntent);
condLog("Service stop and unbound");
flServiceInstance = null;
}
getApplicationContext().unbindService(flConnection);
}
服务是这样的:
public class LinkService extends Service {
InetAddress iaIpAddr, iaNetMask, iaBroadcast;
private final IBinder mBinder = new MyLinkBinder();
private linklistenBroadcast flBroadServer = null;
private linkTCPServer flTCPServer = null;
private linkUDPClient flBroadClient = null;
List<String> tokens = new ArrayList<String>();
private PowerManager.WakeLock wakeLock;
private WifiManager.WifiLock wifiLock;
public class MylLinkBinder extends Binder {
lLinkService getService() { return LinkService.this; }
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public void onCreate() {
super.onCreate();
getLocks();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
instantiateServices();
// notifies presence to other fat devices
condLog("Service notifying fat presence...");
flBroadClient = new LinkUDPClient();
flBroadClient.startSending(LinkProtocolConstants.BRCMD_PRESENCE + String.valueOf(LinkProtocolConstants.tcpPort), iaBroadcast, LinkProtocolConstants.brPort);
return START_STICKY;
}
public void getLocks() {
// acquire a WakeLock to keep the CPU running
condLog("Acquiring power lock");
WifiManager wm = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
wifiLock = wm.createWifiLock(WifiManager.WIFI_MODE_FULL , "MyWifiLock");
wifiLock.acquire();
PowerManager pm = (PowerManager) getApplicationContext().getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock");
wakeLock.acquire();
}
public void stopServices() {
if (flTCPServer != null)
flTCPServer.stopServer();
if (flBroadServer != null)
flBroadServer.stopSelf();
}
private void instantiateServices() {
populateAddresses(); // just obtain iaIpAddr
if (flTCPServer == null) {
condLog("Instantiating TCP server");
flTCPServer = new LinkTCPServer(iaIpAddr, FatLinkProtocolConstants.tcpPort);
flTCPServer.execute();
}
if (flBroadServer == null) {
condLog("Instantiating UDP broadcast server");
Intent notifyIntent = new Intent(this, LinkMain.class); // this is the main Activity class
notifyIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
notifyIntent.setAction("FROM_NOTIFICATION");
PendingIntent notifyPIntent = PendingIntent.getActivity(this, 0, notifyIntent, 0);
Notification fixNotification = new Notification.Builder(getApplicationContext())
.setContentTitle("Link")
.setSmallIcon(R.mipmap.imgLink)
.setContentIntent(notifyPIntent)
.build();
startForeground(1234, fixNotification);
flBroadServer = new LinklistenBroadcast();
flBroadServer.start();
}
}
private final class LinklistenBroadcast extends Thread {
private boolean bStopSelf = false;
DatagramSocket socket;
public void stopSelf() {
bStopSelf = true;
socket.close();
}
@Override
public void run() {
condLog( "Listening broadcast thread started");
bStopSelf = false;
try {
//Keep a socket open to listen to all the UDP trafic that is destinated for this port
socket = new DatagramSocket(null);
socket.setReuseAddress(true);
socket.setSoTimeout(LinkGeneric.BR_SOTIMEOUT_MILS);
socket.setBroadcast(true);
socket.bind(new InetSocketAddress(InetAddress.getByName("0.0.0.0"), FatLinkProtocolConstants.brPort));
while (true) {
condLog("Ready to receive broadcast packets...");
//Receive a packet
byte[] recvBuf = new byte[1500];
DatagramPacket packet = new DatagramPacket(recvBuf, recvBuf.length);
try {
socket.receive(packet);
} catch (InterruptedIOException sException) {
condLog(sockExcept.toString());
break;
} catch (SocketException sockExcept) {
condLog(sockExcept.toString());
}
if (bStopSelf) {
condLog("Broadcast server stopped...");
break;
}
int len = packet.getLength();
String datarecvd = new String(packet.getData()).trim();
//datarecvd = datarecvd.substring(0, len);
//Packet received
String message = new String(packet.getData()).trim();
condLog("<<< broadcast packet received from: " + packet.getAddress().getHostAddress() + " on port: " + packet.getPort() + ", message: " + message);
if (packet.getAddress().equals(iaIpAddr)) {
condLog("Ooops, it's me! discarding packet...");
continue;
}
else
condLog("<<< Packet received; data size: " + len + " bytes, data: " + datarecvd);
//See if the packet holds the right command (message)
// protocol decode
// here do some tuff
} catch (IOException ex) {
condLog(ex.toString());
}
if (socket.isBound()) {
condLog( "Closing socket");
socket.close();
}
condLog( "UDP server thread end.");
flTCPServer = null;
flBroadServer = null;
}
public boolean isThreadRunning() {
return !bStopSelf;
};
}
// Utility functions
public boolean checkBroadcastConnection (DatagramSocket socket, int timeOutcycles) {
int tries = 0;
while (!socket.isConnected()) {
tries++;
if (tries >= timeOutcycles)
return false;
}
return true;
}
@Override
public void onDestroy() {
super.onDestroy();
if (wakeLock != null) {
if (wakeLock.isHeld()) {
wakeLock.release();
}
}
if (wifiLock != null) {
if (wifiLock.isHeld()) {
wifiLock.release();
}
}
}
}
最后,这是清单:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="xxxxxx.ink" >
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<application
android:allowBackup="true"
android:icon="@mipmap/imgLinkmascotte"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".LinkMain"
android:label="@string/app_name"
android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".LinkService" />
</application>
</manifest>
我已阅读 this,但我怀疑问题是否相同,但在我尝试过的所有 phone 上它实际上都发生在我身上(galaxy Tab 7.1, galaxy tag 10, Galaxy SIII, Galaxy Note 3 Neo, Galaxy SIII mini) android 从 4.0 到 4.4.
我已经尝试过发布 here 的解决方案,但一切都变了(再次......有点令人沮丧)。
我什至尝试在所有 phone 中将 "Keep wifi option in standby" 设置为 "Always",但仍然没有。
我研究了 WakeFulIntentService class,它应该像每个人所说的那样工作,但我看不出我的代码有任何显着差异。
我真的希望有人能帮助我,我从上周开始就一直坚持这个问题。
编辑:根据 waqaslam 的回答,我检查了一个在 Wifi-Advaced 设置中有 "Wifi optimisation" 选项的设备,当我取消该选项时它实际上可以正常工作。所以,现在,问题变成了:我可以在高级菜单中没有显示该选项的设备中禁用 Wifi 优化吗?正如我在下面的评论中所写,这似乎与 android 版本无关,因为我有两台设备(均为三星)4.4.2,但它们没有显示该选项。
新编辑:从编辑过的 waqaslam 答案中,我尝试将多播锁添加到我的服务中,但又发生了任何变化。这越来越烦人了,android 几乎没有什么简单明了的事情可以做。
非常感谢
C.
我认为问题不在于 WakeLocks,而在于 Wi-Fi 设置。
在较新版本的 android 中,设置 -> Wi-Fi[=39= 中有一个附加设置] -> Advanced 称为 Wi-Fi optimization
,它(如果打开)会在显示时禁用所有低优先级通信(如收听 UDP 广播)关闭。
禁用该选项应该允许您的设备即使在显示器关闭时也能收听 UDP 广播。
您也可以使用WifiManager.MulticastLock
获取WiFi锁,在屏幕关闭时收听这些特殊广播。
WifiManager wifi = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);
MulticastLock lock = wifi.createMulticastLock("lockWiFiMulticast");
lock.setReferenceCounted(false);
lock.acquire();
完成锁定后,调用:
lock.release();
此外,不要忘记将以下权限添加到您的清单中:
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
更多信息,您可以阅读this。
写这只是为了将 post 标记为已回答。我终于意识到没有解决方案,或者至少没有解决方案在 "all" 具有 "all" android 发行版(或至少来自 JB)的手机上运行良好。
我已经解决了我的个人问题,只是重新审视了我的应用程序的概念,考虑到:
- 即使在空闲模式下发送 UDP 广播也始终有效
- TCP 服务器不受 WiFi 优化的影响。
感谢大家的帮助和建议
C.
可能的原因是 this .
Starting from Android 6.0 (API level 23), Android introduces two
power-saving features that extend battery life for users by managing
how apps behave when a device is not connected to a power source. Doze
reduces battery consumption by deferring background CPU and network
activity for apps when the device is unused for long periods of time.
App Standby defers background network activity for apps with which the
user has not recently interacted
我已经在 SO 上阅读了大量关于使用 WakeLock 和 WifiLock 的教程和帖子,但仍然没有解决我的问题。
我正在编写一个应用程序,当您启动它时,它的唯一作用是创建和启动(前台)服务。此服务 运行 两个线程,即 UDP 广播侦听器(使用 java.io)和 TCP 服务器(使用 java.nio)。在服务的 onCreate 中,我获取了一个唤醒锁和一个 wifilock,并在 onDestroy 中释放它们。
只要 phone 处于唤醒状态,一切正常,但是当显示器关闭时,UDP 广播接收器停止接收广播消息,并且在我再次打开显示器之前不会收到任何消息。实际上,这些锁根本不起作用,放置它们也没有区别……我哪里错了?我确定我在某个地方做了一些愚蠢的事情,但我自己找不到。
这是一些代码:
这就是 Activity 的作用:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
onlyStartService = true;
}@Override
protected void onStart() {
super.onStart();
Intent bIntent = new Intent(this, FatLinkService.class);
getApplicationContext().startService(bIntent);
getApplicationContext().bindService(bIntent, flConnection, BIND_AUTO_CREATE);
}
// service connection to bind idle service
private ServiceConnection flConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder binder) {
linkService.MyLinkBinder flBinder = (LinkService.MylinkBinder) binder;
flServiceInstance = flBinder.getService();
if (onlyStartService) {
condLog("Service bound and finishing activity...");
finish();
}
}
public void onServiceDisconnected(ComponentName className) {
flServiceInstance = null;
}
};
@Override
protected void onStop() {
super.onStop();
if (fatFinish) {
Intent bIntent = new Intent(this, FatLinkService.class);
flServiceInstance.stopServices();
flServiceInstance.stopForeground(true);
flServiceInstance.stopService(bIntent);
condLog("Service stop and unbound");
flServiceInstance = null;
}
getApplicationContext().unbindService(flConnection);
}
服务是这样的:
public class LinkService extends Service {
InetAddress iaIpAddr, iaNetMask, iaBroadcast;
private final IBinder mBinder = new MyLinkBinder();
private linklistenBroadcast flBroadServer = null;
private linkTCPServer flTCPServer = null;
private linkUDPClient flBroadClient = null;
List<String> tokens = new ArrayList<String>();
private PowerManager.WakeLock wakeLock;
private WifiManager.WifiLock wifiLock;
public class MylLinkBinder extends Binder {
lLinkService getService() { return LinkService.this; }
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public void onCreate() {
super.onCreate();
getLocks();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
instantiateServices();
// notifies presence to other fat devices
condLog("Service notifying fat presence...");
flBroadClient = new LinkUDPClient();
flBroadClient.startSending(LinkProtocolConstants.BRCMD_PRESENCE + String.valueOf(LinkProtocolConstants.tcpPort), iaBroadcast, LinkProtocolConstants.brPort);
return START_STICKY;
}
public void getLocks() {
// acquire a WakeLock to keep the CPU running
condLog("Acquiring power lock");
WifiManager wm = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
wifiLock = wm.createWifiLock(WifiManager.WIFI_MODE_FULL , "MyWifiLock");
wifiLock.acquire();
PowerManager pm = (PowerManager) getApplicationContext().getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock");
wakeLock.acquire();
}
public void stopServices() {
if (flTCPServer != null)
flTCPServer.stopServer();
if (flBroadServer != null)
flBroadServer.stopSelf();
}
private void instantiateServices() {
populateAddresses(); // just obtain iaIpAddr
if (flTCPServer == null) {
condLog("Instantiating TCP server");
flTCPServer = new LinkTCPServer(iaIpAddr, FatLinkProtocolConstants.tcpPort);
flTCPServer.execute();
}
if (flBroadServer == null) {
condLog("Instantiating UDP broadcast server");
Intent notifyIntent = new Intent(this, LinkMain.class); // this is the main Activity class
notifyIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
notifyIntent.setAction("FROM_NOTIFICATION");
PendingIntent notifyPIntent = PendingIntent.getActivity(this, 0, notifyIntent, 0);
Notification fixNotification = new Notification.Builder(getApplicationContext())
.setContentTitle("Link")
.setSmallIcon(R.mipmap.imgLink)
.setContentIntent(notifyPIntent)
.build();
startForeground(1234, fixNotification);
flBroadServer = new LinklistenBroadcast();
flBroadServer.start();
}
}
private final class LinklistenBroadcast extends Thread {
private boolean bStopSelf = false;
DatagramSocket socket;
public void stopSelf() {
bStopSelf = true;
socket.close();
}
@Override
public void run() {
condLog( "Listening broadcast thread started");
bStopSelf = false;
try {
//Keep a socket open to listen to all the UDP trafic that is destinated for this port
socket = new DatagramSocket(null);
socket.setReuseAddress(true);
socket.setSoTimeout(LinkGeneric.BR_SOTIMEOUT_MILS);
socket.setBroadcast(true);
socket.bind(new InetSocketAddress(InetAddress.getByName("0.0.0.0"), FatLinkProtocolConstants.brPort));
while (true) {
condLog("Ready to receive broadcast packets...");
//Receive a packet
byte[] recvBuf = new byte[1500];
DatagramPacket packet = new DatagramPacket(recvBuf, recvBuf.length);
try {
socket.receive(packet);
} catch (InterruptedIOException sException) {
condLog(sockExcept.toString());
break;
} catch (SocketException sockExcept) {
condLog(sockExcept.toString());
}
if (bStopSelf) {
condLog("Broadcast server stopped...");
break;
}
int len = packet.getLength();
String datarecvd = new String(packet.getData()).trim();
//datarecvd = datarecvd.substring(0, len);
//Packet received
String message = new String(packet.getData()).trim();
condLog("<<< broadcast packet received from: " + packet.getAddress().getHostAddress() + " on port: " + packet.getPort() + ", message: " + message);
if (packet.getAddress().equals(iaIpAddr)) {
condLog("Ooops, it's me! discarding packet...");
continue;
}
else
condLog("<<< Packet received; data size: " + len + " bytes, data: " + datarecvd);
//See if the packet holds the right command (message)
// protocol decode
// here do some tuff
} catch (IOException ex) {
condLog(ex.toString());
}
if (socket.isBound()) {
condLog( "Closing socket");
socket.close();
}
condLog( "UDP server thread end.");
flTCPServer = null;
flBroadServer = null;
}
public boolean isThreadRunning() {
return !bStopSelf;
};
}
// Utility functions
public boolean checkBroadcastConnection (DatagramSocket socket, int timeOutcycles) {
int tries = 0;
while (!socket.isConnected()) {
tries++;
if (tries >= timeOutcycles)
return false;
}
return true;
}
@Override
public void onDestroy() {
super.onDestroy();
if (wakeLock != null) {
if (wakeLock.isHeld()) {
wakeLock.release();
}
}
if (wifiLock != null) {
if (wifiLock.isHeld()) {
wifiLock.release();
}
}
}
}
最后,这是清单:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="xxxxxx.ink" >
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<application
android:allowBackup="true"
android:icon="@mipmap/imgLinkmascotte"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".LinkMain"
android:label="@string/app_name"
android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".LinkService" />
</application>
</manifest>
我已阅读 this,但我怀疑问题是否相同,但在我尝试过的所有 phone 上它实际上都发生在我身上(galaxy Tab 7.1, galaxy tag 10, Galaxy SIII, Galaxy Note 3 Neo, Galaxy SIII mini) android 从 4.0 到 4.4.
我已经尝试过发布 here 的解决方案,但一切都变了(再次......有点令人沮丧)。
我什至尝试在所有 phone 中将 "Keep wifi option in standby" 设置为 "Always",但仍然没有。
我研究了 WakeFulIntentService class,它应该像每个人所说的那样工作,但我看不出我的代码有任何显着差异。
我真的希望有人能帮助我,我从上周开始就一直坚持这个问题。
编辑:根据 waqaslam 的回答,我检查了一个在 Wifi-Advaced 设置中有 "Wifi optimisation" 选项的设备,当我取消该选项时它实际上可以正常工作。所以,现在,问题变成了:我可以在高级菜单中没有显示该选项的设备中禁用 Wifi 优化吗?正如我在下面的评论中所写,这似乎与 android 版本无关,因为我有两台设备(均为三星)4.4.2,但它们没有显示该选项。
新编辑:从编辑过的 waqaslam 答案中,我尝试将多播锁添加到我的服务中,但又发生了任何变化。这越来越烦人了,android 几乎没有什么简单明了的事情可以做。
非常感谢 C.
我认为问题不在于 WakeLocks,而在于 Wi-Fi 设置。
在较新版本的 android 中,设置 -> Wi-Fi[=39= 中有一个附加设置] -> Advanced 称为 Wi-Fi optimization
,它(如果打开)会在显示时禁用所有低优先级通信(如收听 UDP 广播)关闭。
禁用该选项应该允许您的设备即使在显示器关闭时也能收听 UDP 广播。
您也可以使用WifiManager.MulticastLock
获取WiFi锁,在屏幕关闭时收听这些特殊广播。
WifiManager wifi = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);
MulticastLock lock = wifi.createMulticastLock("lockWiFiMulticast");
lock.setReferenceCounted(false);
lock.acquire();
完成锁定后,调用:
lock.release();
此外,不要忘记将以下权限添加到您的清单中:
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
更多信息,您可以阅读this。
写这只是为了将 post 标记为已回答。我终于意识到没有解决方案,或者至少没有解决方案在 "all" 具有 "all" android 发行版(或至少来自 JB)的手机上运行良好。
我已经解决了我的个人问题,只是重新审视了我的应用程序的概念,考虑到: - 即使在空闲模式下发送 UDP 广播也始终有效 - TCP 服务器不受 WiFi 优化的影响。
感谢大家的帮助和建议 C.
可能的原因是 this .
Starting from Android 6.0 (API level 23), Android introduces two power-saving features that extend battery life for users by managing how apps behave when a device is not connected to a power source. Doze reduces battery consumption by deferring background CPU and network activity for apps when the device is unused for long periods of time. App Standby defers background network activity for apps with which the user has not recently interacted