我正在制作一个带有mqtt客户端和后台服务的应用程序,当我收到某些mqtt消息时会发出通知。
我使用Paho库和服务作为客户端,只要我连接到wifi并打开代理,一切都可以正常运行。
我不希望通过Internet访问代理,所以当没有wifi可用时,客户端将断开连接,问题是当wifi重新连接时,mqtt客户端将不会重新连接。
我已经尝试了很多事情,但是最新的测试是让处理程序检查是否有互联网以及是否通过wifi,如果是的话,我再次启动mqtt服务器。
我在清单中具有以下权限:
android.permission.INTERNET" android:name="android.permission.ACCESS_NETWORK_STATE" android.permission.WAKE_LOCK"
当我运行模拟器并断开wifi连接时,整个应用以及服务均崩溃,并出现以下错误
这是我正在使用的处理程序:
handler.postDelayed(new Runnable(){ public void run(){ if (isWifiConnected()) { startMqtt(); } handler.postDelayed(this, delay); } }, delay);
这是isWifiConnected(如果没有Context context = this;在应用程序中添加我,context.getSystemService将无法正常工作,我也不知道这是否也是一个问题):
Context context = this;
private boolean isWifiConnected() { boolean isWifi; ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); boolean isConnected = activeNetwork != null && activeNetwork.isConnectedOrConnecting(); return isWifi = activeNetwork.getType() == ConnectivityManager.TYPE_WIFI; } D/AlarmPingSender: Unregister alarmreceiver to MqttServicephone W/Mqtt: Failed to connect to: tcp://192.168.1.39:1883Unable to connect to server (32103) - java.net.ConnectException: failed to connect to /192.168.1.39 (port 1883) from /:: (port 0) after 30000ms: connect failed: ENETUNREACH (Network is unreachable) I/chatty: uid=10085(com.iteda.nome) identical 85 lines W/Mqtt: Failed to connect to: tcp://192.168.1.39:1883Unable to connect to server (32103) - java.net.ConnectException: failed to connect to /192.168.1.39 (port 1883) from /:: (port 0) after 30000ms: connect failed: ENETUNREACH (Network is unreachable) W/Mqtt: Failed to connect to: tcp://192.168.1.39:1883Unable to connect to server (32103) - java.net.ConnectException: failed to connect to /192.168.1.39 (port 1883) from /:: (port 0) after 30000ms: connect failed: ENETUNREACH (Network is unreachable) I/chatty: uid=10085(com.iteda.nome) identical 4 lines W/Mqtt: Failed to connect to: tcp://192.168.1.39:1883Unable to connect to server (32103) - java.net.ConnectException: failed to connect to /192.168.1.39 (port 1883) from /:: (port 0) after 30000ms: connect failed: ENETUNREACH (Network is unreachable) W/Mqtt: Failed to connect to: tcp://192.168.1.39:1883Unable to connect to server (32103) - java.net.ConnectException: failed to connect to /192.168.1.39 (port 1883) from /:: (port 0) after 30000ms: connect failed: ENETUNREACH (Network is unreachable) I/chatty: uid=10085(com.iteda.nome) identical 36 lines W/Mqtt: Failed to connect to: tcp://192.168.1.39:1883Unable to connect to server (32103) - java.net.ConnectException: failed to connect to /192.168.1.39 (port 1883) from /:: (port 0) after 30000ms: connect failed: ENETUNREACH (Network is unreachable) W/Mqtt: Failed to connect to: tcp://192.168.1.39:1883Unable to connect to server (32103) - java.net.ConnectException: failed to connect to /192.168.1.39 (port 1883) from /:: (port 0) after 30000ms: connect failed: ENETUNREACH (Network is unreachable) I/chatty: uid=10085(com.iteda.nome) identical 17 lines W/Mqtt: Failed to connect to: tcp://192.168.1.39:1883Unable to connect to server (32103) - java.net.ConnectException: failed to connect to /192.168.1.39 (port 1883) from /:: (port 0) after 30000ms: connect failed: ENETUNREACH (Network is unreachable) I/MqttConnection: Requesting Automatic reconnect using New Java AC D/AndroidRuntime: Shutting down VM E/AndroidRuntime: FATAL EXCEPTION: main Process: com.iteda.nome, PID: 7394 java.lang.RuntimeException: Error receiving broadcast Intent { act=android.net.conn.CONNECTIVITY_CHANGE flg=0x4200010 (has extras) } in org.eclipse.paho.android.service.MqttService$NetworkConnectionIntentReceiver@5224905 at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$getRunnable$0(LoadedApk.java:1401) at android.app.-$$Lambda$LoadedApk$ReceiverDispatcher$Args$_BumDX2UKsnxLVrE6UJsJZkotuA.run(Unknown Source:2) at android.os.Handler.handleCallback(Handler.java:873) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:193) at android.app.ActivityThread.main(ActivityThread.java:6669) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858) Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void java.util.Timer.cancel()' on a null object reference at org.eclipse.paho.client.mqttv3.MqttAsyncClient.stopReconnectCycle(MqttAsyncClient.java:1120) at org.eclipse.paho.client.mqttv3.MqttAsyncClient.reconnect(MqttAsyncClient.java:1057) at org.eclipse.paho.android.service.MqttConnection.reconnect(MqttConnection.java:1049) at org.eclipse.paho.android.service.MqttService.reconnect(MqttService.java:342) at org.eclipse.paho.android.service.MqttService$NetworkConnectionIntentReceiver.onReceive(MqttService.java:827) at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$getRunnable$0(LoadedApk.java:1391) at android.app.-$$Lambda$LoadedApk$ReceiverDispatcher$Args$_BumDX2UKsnxLVrE6UJsJZkotuA.run(Unknown Source:2) at android.os.Handler.handleCallback(Handler.java:873) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:193) at android.app.ActivityThread.main(ActivityThread.java:6669) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858) I/Process: Sending signal. PID: 7394 SIG: 9 Application terminated.
我知道您可能需要更多信息,所以与其说我用错误的代码轰炸,不如告诉我您需要了解我做错的事情:)
错误代码似乎给出了答案,但是由于我是android和java的新手。我不知道如何更改方法以使其正确。
你说:
问题是,当wifi重新连接时,mqtt客户端将不会重新连接。
您可以BroadcastReceiver在您的Service#onCreate()方法中仅使用a 来侦听WIFI_STATE_CHANGED_ACTION操作,如下所示。
BroadcastReceiver
Service#onCreate()
WIFI_STATE_CHANGED_ACTION
此外,你必须使用return START_STICKY你的Service#onStartCommand(),这样应用程序被关闭后,在服务类将被运行。
return START_STICKY
Service#onStartCommand()
服务等级:
public class MQTTService extends Service { private MqttAndroidClient clientPhone; @Override public void onCreate() { super.onCreate(); registerReceiver(); new Thread(() -> init()).start(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { //do something return START_STICKY; } @Override public IBinder onBind(Intent intent) { return null; } private void registerReceiver(){ m_ScreenOffReceiver = new BroadcastReceiver(){ @Override public void onReceive(final Context context, Intent intent){ //Log.d(TAG,"onReceive of Wifi_State_Change called"); if(intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN); if(wifiState != WifiManager.WIFI_STATE_ENABLED) return; final WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE); new Handler().postDelayed(() -> { WifiInfo wifiInfo = wifiManager.getConnectionInfo(); String ssid = wifiInfo.getSSID(); //Toast.makeText(context, "active wifi:"+ssid, Toast.LENGTH_SHORT).show(); //You can connect to the your mqtt broker again: connectMQTT(); }, 10000); } } }; IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); registerReceiver(m_ScreenOffReceiver, intentFilter); } private void init() { clientPhone = new MqttAndroidClient(this, "tcp://IP:PORT", "Your-CLIENT-ID"); //clientPhone = new MqttAndroidClient(this, "ssl://IP:PORT", "Your-CLIENT-ID"); clientPhone.setCallback(new MqttCallback() { @Override public void connectionLost(Throwable cause) { //do something - for example reconnnect again } @Override public void messageArrived(String topic, MqttMessage message) throws Exception { //you can do everything with the received message from broker here } @Override public void deliveryComplete(IMqttDeliveryToken token) { //do something } }); } private MqttConnectOptions getOptions(){ if(clientPhone.getServerURI().contains("ssl")) { //set ssl config.for example: //options.setSocketFactory(clientPhone.getSSLSocketFactory(YOUR_KEYSTORE_FILE, "YOUR_KEYSTORE_PASSWORD")); //... } options.setKeepAliveInterval(...); options.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1_1); options.setAutomaticReconnect(true); options.setCleanSession(...); //options.setWill(...); options.setUserName(...)); options.setPassword(...); return options; } private void connectMQTT() { try { //getOptions is a method that returns your MqttConnectOptions object IMqttToken token = clientPhone.connect(getOptions()); token.setActionCallback(new IMqttActionListener() { @Override public void onSuccess(IMqttToken asyncActionToken) { //do something } @SuppressWarnings("ThrowableResultOfMethodCallIgnored") @Override public void onFailure(IMqttToken asyncActionToken, Throwable exception) { //do something } }); } catch (MqttException e) { //do something e.printStackTrace(); } } @Override public void onDestroy() { if(clientPhone!=null) { /*unregisterResources is needed,otherwise receive this error: has leaked ServiceConnection org.eclipse.paho.android.service.MqttAndroidClient*/ try { clientPhone.unregisterResources(); clientPhone.close(); clientPhone.disconnect(); } catch (Exception e) { e.printStackTrace(); } } unregisterReceiver(m_ScreenOffReceiver); m_ScreenOffReceiver = null; ... super.onDestroy(); } }
必须声明org.eclipse.paho.android.service.MqttService,并Your Service Class在您的清单文件:
org.eclipse.paho.android.service.MqttService
Your Service Class
我希望这可以帮助你。 最好的祝愿