Я прочитал много руководств и сообщений здесь на SO относительно использования WakeLock и WifiLock, но до сих пор не нашел решения моей проблемы.
Я пишу приложение, которое при запуске имеет единственный эффект создания и запуска службы (переднего плана). Эта служба запускает два потока, которые являются прослушивателем широковещательной передачи UDP (с использованием java.io) и сервером TCP (с использованием java.nio). В onCreate службы я приобретаю wakelock и wifilock и отпускаю их в onDestroy.
Пока телефон не спит, все работает нормально, но когда дисплей выключается, широковещательный приемник 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>
Я прочитал это и сомневаюсь, что проблема То же самое, но на самом деле это происходит со мной на всех телефонах, которые я пробовал (Galaxy Tab 7.1, Galaxy tag 10, Galaxy SIII, Galaxy Note 3 Neo, Galaxy SIII mini) с версиями Android от 4.0 до 4.4.
Я уже пробовал решение, опубликованное здесь, но все изменилось (опять же ... это немного расстраивает).
Я даже пытался установить для параметра «Сохранять Wi-Fi в режиме ожидания» значение «Всегда» на всех телефонах, которые я пробовал, но все равно ничего.
Я изучил класс WakeFulIntentService, который должен работать, как все говорят, но я не вижу каких-либо существенных отличий в моем коде.
Я очень надеюсь, что кто-то может мне помочь, я действительно застрял в этом с прошлой недели.
РЕДАКТИРОВАТЬ: после ответа вакаслама я проверил устройство с опцией «Оптимизация Wi-Fi» в настройках Wifi-Advaced, и оно действительно работает, как только я отключил эту опцию. Итак, теперь возникает проблема: могу ли я отключить оптимизацию Wi-Fi на устройствах, на которых эта опция не отображается в расширенном меню? как я писал ниже в своем комментарии, похоже, это не связано с выпуском Android, так как у меня есть два устройства (оба Samsung) с 4.4.2, и они не показывают эту опцию.
Новое РЕДАКТИРОВАНИЕ: из отредактированного ответа вакаслама я попытался добавить многоадресную передачу в свою службу, но снова все изменилось. Это уже раздражает, вряд ли есть что-то простое и понятное, что можно сделать с андроидом.
большое спасибо C.