当前位置: 首页 > 面试题库 >

wifi断开并不会重新连接时,应用程序,服务和mqtt崩溃

尹俊贤
2023-03-14
问题内容

我正在制作一个带有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将无法正常工作,我也不知道这是否也是一个问题):

    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客户端将不会重新连接。

  1. 您可以BroadcastReceiver在您的Service#onCreate()方法中仅使用a 来侦听WIFI_STATE_CHANGED_ACTION操作,如下所示。

  2. 此外,你必须使用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();
}

}
  1. 必须声明org.eclipse.paho.android.service.MqttService,并Your Service Class在您的清单文件:



我希望这可以帮助你。
最好的祝愿



 类似资料:
  • 问题内容: 我正在制作一个带有mqtt客户端和后台服务的应用程序,当我收到某些mqtt消息时会发出通知。 我使用Paho库和服务作为客户端,只要我连接到wifi并打开代理,一切都可以正常运行。 我不希望通过Internet访问代理,所以当没有wifi可用时,客户端将断开连接,问题是当wifi重新连接时,mqtt客户端将不会重新连接。 我已经尝试了很多事情,但是最新的测试是让处理程序检查是否有互联网

  • 断开mqtt连接,前提是必须已经通过Iot_id,Iot_pwd建立过一次mqtt连接。 请求方式: "|4|1|4|\r" 返回值: "|4|1|4|1|\r" 断开成功 "|4|1|4|2|\r" 断开失败 Arduino样例: softSerial.print("|4|1|4|\r");

  • 启动mysql服务: sudo service mysql start 停止mysql服务: sudo service mysql stop 要连接到服务器,我们通常需要提供MySQL的用户名来触发mysql,很可能,还需要密码。如果你的服务器运行在一个其他的机器上,你还需要指定主机名。联系管理员来找到连接参数(例如主机名,用户名和密码),当你知道了正确的参数后,你可以像下面那样连接: she

  • 重新连接上一次连接的wifi。 请求方式: "|2|3|\r" 返回值: "|2|1|\r" wifi连接状态:wifi断开连接 "|2|2|\r" wifi连接状态:正在连接wifi "|2|3|ip|\r" wifi连接状态:wifi连接成功,返回OBLOQ的ip地址 "|2|4|\r" wifi连接状态:wifi连接失败,检查SSID和PWD是否输入正确 Arduino样例: softSer

  • 重新建立mqtt连接,前提是必须已经通过Iot_id,Iot_pwd建立过一次mqtt连接。 请求方式: "|4|1|5|\r" 返回值: "|4|1|1|1|\r" mqtt连接状态:连接成功 "|4|1|1|2|reason|\r" mqtt连接状态:连接失败,字符串reason表示失败的原因 Arduino样例: softSerial.print("|4|1|5|\r");

  • 问题内容: 关于它有几个问题,但我总是读同一本书:“如果系统需要资源,该服务将被杀死”或“您无法构建永远运行的服务,因为它在后台运行的次数越多,越容易受到影响。被系统杀死”等等。 我面临的问题是:我的服务运行正常,并且可以预期,如果我运行我的应用程序,然后退出它,我的服务仍在运行,但是当我杀死我的应用程序时(通过转到“最近的应用程序”并对其进行扫描)离开)服务停止。在这一刻,如果我转到设置>>应用