2017-08-16 3 views
1

Mon application de MainActivity onCreate(), démarre un service qui se connecte au serveur et s'abonne aux rubriques. De plus, lorsque j'ajoute une nouvelle connexion, mon service redémarre (en utilisant stop/startService). Je stocke les données de connexion (ip, port, etc.) dans la base de données SQL et le regroupe dans le service une fois qu'il démarre. Le problème est (je pense) que lorsque l'un des paramètres de connexion est incorrect le service attend le timeout et bloque une activité ... Si je règle token.waitForCompletion(500); ça va beaucoup plus vite mais je ne peux pas deviner cette valeur ...Pourquoi le service MQTT bloque-t-il l'activité?

Y at-il moyen de résoudre mon problème?

@Override 
public void onCreate() { 

    Datapool(); 
    IntentFilter intentf = new IntentFilter(); 
    intentf.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 
    registerReceiver(mqttBroadcastReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); 
    mConnMan = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE); 
    deviceId = String.format(DEVICE_ID_FORMAT, Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID)); 

} 

MQTTBroadcastReceiver mqttBroadcastReceiver = new MQTTBroadcastReceiver(); 

class MQTTBroadcastReceiver extends BroadcastReceiver { 
    @Override 
    public void onReceive(Context context, Intent intent) { 
     Connect(); 
    } 

}; 

IMqttToken token; 
int i = 0; 
private HashMap<String, Boolean> _hashMap = new HashMap<>(); 
private void Connect(){ 
    for (ServiceDataModel connectionData : dataModels) { 

     Log.d(TAG, "doConnect() " + connectionData.getCONNECTION_NAME()); 
     _hashMap.put(connectionData.getCONNECTION_NAME(), false); 
     MqttConnectOptions options = new MqttConnectOptions(); 
     options.setCleanSession(true); 
     i++; 
     try { 
      mqttClient = new MqttAsyncClient("tcp://" + connectionData.getSERVER_IP() + ":" + connectionData.getSERVER_PORT(), deviceId + i , new MemoryPersistence()); 
      token = mqttClient.connect(); 
      token.waitForCompletion(2500); 
      if (mqttClient.isConnected()) { 
        mqttClient.setCallback(new MqttEventCallback()); 
        token = mqttClient.subscribe(connectionData.getTOPIC(), Integer.parseInt(connectionData.getQOS())); 
        token.waitForCompletion(2500); 
        _hashMap.put(connectionData.getCONNECTION_NAME(), true); 
      } 
     }catch (Exception ex){ 
      Log.d(TAG, ex.toString() + connectionData.toString()); 
     } 
    } 
    sendMessageToActivity(_hashMap); 
} 

Répondre

1

En appelant token.waitForCompletion(2500) vous essayez de synchroniser d'abord la connexion et l'abonnement - qui bloque le thread principal. Ne pas appliquer ces hacks, mais utiliser les rappels de connexion asynchrone (mCallback et mConnectionCallback ci-dessous) à la place. Et après la connexion réussit, utilisez la fonction de rappel d'abonnement asynchrone (mSubscribeCallback ci-dessous):

private final MqttCallbackExtended mCallback = new MqttCallbackExtended() { 
    @Override 
    public void connectComplete(boolean reconnect, String brokerAddress) { 
      mqttClient.subscribe(connectionData.getTOPIC(), Integer.parseInt(connectionData.getQOS()), null, mSubscribeCallback); 
    } 

    @Override 
    public void connectionLost(Throwable ex) { 
    } 

    @Override 
    public void deliveryComplete(IMqttDeliveryToken deliveryToken) { 
    } 

    @Override 
    public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception { 
    } 
}; 

private final IMqttActionListener mConnectionCallback = new IMqttActionListener() { 
    @Override 
    public void onSuccess(IMqttToken asyncActionToken) { 
     // do nothing, this case is handled in mCallback.connectComplete() 
    } 

    @Override 
    public void onFailure(IMqttToken asyncActionToken, Throwable exception) { 
    } 
}; 

private final IMqttActionListener mSubscribeCallback = new IMqttActionListener() { 
    @Override 
    public void onSuccess(IMqttToken subscribeToken) { 
      _hashMap.put(connectionData.getCONNECTION_NAME(), true); 
    } 

    @Override 
    public void onFailure(IMqttToken subscribeToken, Throwable ex) { 
    } 

}; 

try { 
    MqttConnectOptions connectOptions = new MqttConnectOptions(); 
    connectOptions.setCleanSession(true); 
    connectOptions.setAutomaticReconnect(false); 
    connectOptions.setUserName(USERNAME); 
    connectOptions.setPassword(PASSWORD.toCharArray()); 

    mqttClient = new MqttAsyncClient("tcp://" + connectionData.getSERVER_IP() + ":" + connectionData.getSERVER_PORT(), deviceId + i , new MemoryPersistence()); 
    mqttClient.setCallback(mCallback); 
    mqttClient.connect(connectOptions, null, mConnectionCallback); 

} catch (Exception ex) { 
    Log.d(TAG, ex.toString() + connectionData.toString()); 
} 

donc réorganiser votre application un peu et il ne sera pas bloquer.

Considérez également l'utilisation de LocalBroadcastManager pour pouvoir communiquer entre SQLite, MQTT et l'activité.