我有一些代码可以侦听Windows应用程序发送的多播,它在android 7.0及以下版本上运行正常,但在android 8.0上,则可以在5分钟到1小时内随机停止,而不会引发异常。我不确定这是否受Android 8.0中引入的Background Service Limitations影响。但我进行了一些研究,有人说它不应该受到影响,因为它是线程here!但是由于它仍然是后台线程,因此我不确定。
这是我的多播线程代码:
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);
}
}
以下是多播侦听器的代码:
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();
}
}
我使用以下函数在onResume的主要活动上对其进行初始化:
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");
}
}
}
然后我用onDestroy停止线程:
private void stopThreads() {
if (this.multicastListenerThread != null)
this.multicastListenerThread.stopRunning();
if (this.multicastSenderThread != null)
this.multicastSenderThread.interrupt();
}