I have code that listens to multicast send by a windows app it works perfectly fine from android 7.0 and below but on android 8.0 it works then randomly stop from 5 mins to 1 hr without throwing an exception. I am not sure if this is affected by Background Service Limitations that was introduced on Android 8.0. but I did some research and some said that it should be not affected since it is a thread here! but since it is still a background thread I am not sure.
Here my code for the Multicast Thread :
public class MulticastThread extends Thread {
final AtomicBoolean running = new AtomicBoolean(true);
final Activity mActivity;
final String multicastIP;
final int multicastPort;
final Handler handler;
protected MulticastSocket multicastSocket;
private InetAddress inetAddress;
private NetworkInterface networkInterface;
public MulticastThread(String threadName, Activity mActivity, String multicastIP, int multicastPort, Handler handler) {
super(threadName);
this.mActivity = mActivity;
this.multicastIP = multicastIP;
this.multicastPort = multicastPort;
this.handler = handler;
}
@Override
public void run() {
try {
WifiManager wifiManager = (WifiManager) mActivity.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
int wifiIPInt = wifiInfo.getIpAddress();
byte[] wifiIPByte = new byte[]{
(byte) (wifiIPInt & 0xff),
(byte) (wifiIPInt >> 8 & 0xff),
(byte) (wifiIPInt >> 16 & 0xff),
(byte) (wifiIPInt >> 24 & 0xff)};
this.inetAddress = InetAddress.getByAddress(wifiIPByte);
this.networkInterface = NetworkInterface.getByInetAddress(inetAddress);
this.multicastSocket = new MulticastSocket(multicastPort);
multicastSocket.setNetworkInterface(networkInterface);
multicastSocket.joinGroup(InetAddress.getByName(multicastIP));
multicastSocket.setSoTimeout(100);
multicastSocket.setTimeToLive(2);
} catch (BindException e) {
handler.post(new Runnable() {
@Override
public void run() {
if(mActivity instanceof CameraActivity){
((CameraActivity) mActivity).stopListening();
}
}
});
String error = "Error: Cannot bind Address or Port.";
if (multicastPort < 1024)
error += "\nTry binding to a port larger than 1024.";
outputErrorToConsole(error);
Log.d("ETO>>>",e+"");
} catch (IOException e) {
handler.post(new Runnable() {
@Override
public void run() {
if(mActivity instanceof CameraActivity){
((CameraActivity) mActivity).stopListening();
}
}
});
String error = "Error: Cannot bind Address or Port.\n"
+ "An error occurred: " + e.getMessage();
outputErrorToConsole(error);
Log.d(">>>",e+"");
}catch (Throwable e )
{
Log.d(">>>",e+"");
}
}
String getLocalIP() {
return this.inetAddress.getHostAddress();
}
void outputErrorToConsole(final String errorMessage) {
handler.post(new Runnable() {
@Override
public void run() {
if(mActivity instanceof CameraActivity){
((CameraActivity) mActivity).showError(errorMessage);
}
}
});
}
public void stopRunning() {
this.running.set(false);
}
}
Here the code for the Multicast Listener:
public class MulticastListenerThread extends MulticastThread {
private DatagramPacket packet;
private long newSeqNum;
private long lastSeqNum;
AppSettings appSettings;
public MulticastListenerThread(Activity activity, String multicastIP, int multicastPort) {
super("MulticastListenerThread", activity, multicastIP, multicastPort, new Handler());
}
@Override
public void run() {
super.run();
appSettings = AppSettings.getAppSettingsFromSharedPreference(mActivity);
newSeqNum = 0;
lastSeqNum = 0;
this.packet = new DatagramPacket(new byte[65536], 65536);
while (running.get()) {
packet.setData(new byte[65536]);
try {
if (multicastSocket != null)
multicastSocket.receive(packet);
else
break;
} catch (IOException ignored) {
continue;
}
final String data = new String(packet.getData()).trim();
Log.i("Multicast", data);
this.handler.post(new Runnable() {
@Override
public void run() {
if (mActivity instanceof CameraActivity) {
// ((CameraActivity) mActivity).log(consoleMessage);
String actionMessage = "";
long timer=0;
if (data.contains("seq")) {
if(data.contains(",")) {
String[] result = data.split(",");
String data2 = result[0];
timer = Long.parseLong(result[1]);
newSeqNum = Long.valueOf(data2.substring(data2.lastIndexOf("_") + 1));
String messageWithSubSeq = data2.substring(0, (data2.lastIndexOf("_seq_")));
actionMessage = messageWithSubSeq.substring(0, (messageWithSubSeq.lastIndexOf("_")));
}else {
// long l = Long.parseLong(str);
newSeqNum = Long.valueOf(data.substring(data.lastIndexOf("_") + 1));
String messageWithSubSeq = data.substring(0, (data.lastIndexOf("_seq_")));
actionMessage = messageWithSubSeq.substring(0, (messageWithSubSeq.lastIndexOf("_")));
}
}else if(data.contains("synctime"))
{
appSettings = AppSettings.getAppSettingsFromSharedPreference(mActivity);
appSettings.setCheckaudit(true);
appSettings.save(mActivity);
((CameraActivity) mActivity).onSynctime();
}else if(data.contains("processtime"))
{
appSettings = AppSettings.getAppSettingsFromSharedPreference(mActivity);
appSettings.setUpload(false);
appSettings.save(mActivity);
((CameraActivity) mActivity).onCancelUpload();
}
Log.d("Received! " , ""+data);
}
}
});
}
if (multicastSocket != null)
this.multicastSocket.close();
}
}
I Initialize it on the main activity with onResume using this function:
public void startListening() {
appSettings = AppSettings.getAppSettingsFromSharedPreference(this);
if (!isListening) {
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
if (connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI).isConnected()) {
setWifiLockAcquired(true);
this.multicastListenerThread = new MulticastListenerThread(this, Constants.INET_ADDRESS,
Constants.MULTISOCKET_PORT);
multicastListenerThread.start();
Log.d(">>>>>",multicastListenerThread.getPriority()+"");
isListening = true;
} else {
showError("Connect to Network");
}
}
}
Then I stop the threads with onDestroy:
private void stopThreads() {
if (this.multicastListenerThread != null)
this.multicastListenerThread.stopRunning();
if (this.multicastSenderThread != null)
this.multicastSenderThread.interrupt();
}