2013-03-26 15 views
0

我有一個大問題,我找不到解決方案。需要你的幫助。android後臺服務靜態字段發送同樣的消息兩次

當我嘗試僅使用服務在活動中發送一條消息時,它可以正常工作。 但是,當我嘗試發送2個消息跟隨另一個(這意味着一個接一個),使用相同的publishTopic2和pushMsg2兩次發送消息。

代碼是:

PushService.actionPush(getApplicationContext(),publishTopic1,pushMsg1); 
PushService.actionPush(getApplicationContext(),publishTopic2,pushMsg2); 

1 - 這是從syncronized關鍵字錯誤的使用情況如何? 2-是possibe發送後另外兩個味精無

public class PushService 
     extends Service 
{ 
    // this is the log tag 
    public static final String TAG = "DemoPushService"; 
    public static String IncomingText = ""; 

    private static String PushMesaj = ""; 

    // the IP address, where your MQTT broker is running. 
    private static final String MQTT_HOST = ""; 
    // the port at which the broker is running. 
    private static int MQTT_BROKER_PORT_NUM = 1883; 
    // Let's not use the MQTT persistence. 
    private static MqttClientPersistence MQTT_PERSISTENCE = null; 
    // We don't need to remember any state between the connections, so we use a 
    // clean start. 
    private static boolean MQTT_CLEAN_START = true; 
    // Let's set the internal keep alive for MQTT to 15 mins. I haven't tested 
    // this value much. It could probably be increased. 
    private static short MQTT_KEEP_ALIVE = 60 * 15; 
    // Set quality of services to 0 (at most once delivery), since we don't want 
    // push notifications 
    // arrive more than once. However, this means that some messages might get 
    // lost (delivery is not guaranteed) 
    // private static int[] MQTT_QUALITIES_OF_SERVICE = { 0 } ; 
    private static int MQTT_QUALITY_OF_SERVICE = 2; 
    // The broker should not retain any messages. 
    // private static boolean MQTT_RETAINED_PUBLISH = false; 

    // MQTT client ID, which is given the broker. In this example, I also use 
    // this for the topic header. 
    // You can use this to run push notifications for multiple apps with one 
    // MQTT broker. 
    public static String MQTT_CLIENT_ID = "begining"; 
    public static String SUBSCRIBE_TOPIC = "begining"; 
    private static String PUBLISH_TOPIC = "begining"; 
    // These are the actions for the service (name are descriptive enough) 
    private static final String ACTION_START = MQTT_CLIENT_ID + ".START"; 
    private static final String ACTION_STOP = MQTT_CLIENT_ID + ".STOP"; 
    private static final String ACTION_SUBSCRIBE = MQTT_CLIENT_ID 
      + ".SUBSCRIBE"; 
    private static final String ACTION_PUBLISH = MQTT_CLIENT_ID + ".PUBLISH"; 

    private static final String ACTION_KEEPALIVE = MQTT_CLIENT_ID 
      + ".KEEP_ALIVE"; 
    private static final String ACTION_PUSHMESSAGE = MQTT_CLIENT_ID 
      + ".PUSH_MESSAGE"; 
    private static final String ACTION_PUSHMESSAGE2 = MQTT_CLIENT_ID 
      + ".PUSH_MESSAGE"; 
    private static final String ACTION_RECONNECT = MQTT_CLIENT_ID 
      + ".RECONNECT"; 

    // Connection log for the push service. Good for debugging. 
    private ConnectionLog mLog; 

    // Connectivity manager to determining, when the phone loses connection 
    private ConnectivityManager mConnMan; 
    // Notification manager to displaying arrived push notifications 
    private NotificationManager mNotifMan; 

    // Whether or not the service has been started. 
    private boolean mStarted; 

    // This the application level keep-alive interval, that is used by the 
    // AlarmManager 
    // to keep the connection active, even when the device goes to sleep. 
    private static final long KEEP_ALIVE_INTERVAL = 1000 * 60 * 28; 

    // Retry intervals, when the connection is lost. 
    private static final long INITIAL_RETRY_INTERVAL = 1000 * 10; 
    private static final long MAXIMUM_RETRY_INTERVAL = 1000 * 60 * 30; 

    // Preferences instance 
    private SharedPreferences mPrefs; 
    // We store in the preferences, whether or not the service has been started 
    public static final String PREF_STARTED = "isStarted"; 
    // We also store the deviceID (target) 
    public static final String PREF_DEVICE_ID = "deviceID"; 
    // We store the last retry interval 
    public static final String PREF_RETRY = "retryInterval"; 

    // Notification title 
    public static String NOTIF_TITLE = "Hey !!!"; 
    // Notification id 
    private static final int NOTIF_CONNECTED = 0; 

    // This is the instance of an MQTT connection. 
    private MQTTConnection mConnection; 
    private long mStartTime; 

    private static clsUser yourInfo; 
    public static clsOnlineUsers onlineUsers; 
    private static clsUser myInfo; 

    // Static method to start the service 
    public static void actionStart(Context ctx) 
    { 
     Intent i = new Intent(ctx, PushService.class); 
     i.setAction(ACTION_START); 
     ctx.startService(i); 
    } 

    public static void actionSubscribe(Context ctx) 
    { 
     Intent i = new Intent(ctx, PushService.class); 
     i.setAction(ACTION_SUBSCRIBE); 
     ctx.startService(i); 
    } 

    public static void actionPublish(Context ctx) 
    { 
     Intent i = new Intent(ctx, PushService.class); 
     i.setAction(ACTION_PUBLISH); 
     ctx.startService(i); 
    } 

    // Static method to stop the service 
    public static void actionStop(Context ctx) 
    { 
     Intent i = new Intent(ctx, PushService.class); 
     i.setAction(ACTION_STOP); 
     ctx.startService(i); 
    } 

    // Static method to send a keep alive message 
    public static void actionPing(Context ctx) 
    { 
     Intent i = new Intent(ctx, PushService.class); 
     i.setAction(ACTION_KEEPALIVE); 
     ctx.startService(i); 
    } 

    public static void actionPush(Context ctx, String publishTopic, 
      String pushMsg) 
    { 
     PUBLISH_TOPIC = publishTopic; 
     PushMesaj = pushMsg; 
     Intent i = new Intent(ctx, PushService.class); 
     i.setAction(ACTION_PUSHMESSAGE); 
     ctx.startService(i); 
    } 

    @Override 
    public void onCreate() 
    { 
     super.onCreate(); 

     log("Creating service"); 
     mStartTime = System.currentTimeMillis(); 

     try { 
      mLog = new ConnectionLog(); 
      Log.i(TAG, "Opened log at " + mLog.getPath()); 
     } catch (IOException e) { 
      Log.e(TAG, "Failed to open log", e); 
     } 

     // Get instances of preferences, connectivity manager and notification 
     // manager 
     mPrefs = getSharedPreferences(TAG, MODE_PRIVATE); 
     mConnMan = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE); 
     mNotifMan = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); 

     mPrefs.edit().putLong(PREF_RETRY, INITIAL_RETRY_INTERVAL).commit(); 
     mPrefs.edit().putBoolean(PREF_STARTED, false).commit(); 

     /* 
     * If our process was reaped by the system for any reason we need to 
     * restore our state with merely a call to onCreate. We record the last 
     * "started" value and restore it here if necessary. 
     */ 
     handleCrashedService(); 
    } 

    // This method does any necessary clean-up need in case the server has been 
    // destroyed by the system 
    // and then restarted 
    private void handleCrashedService() 
    { 
     if (wasStarted() == true) { 
      log("Handling crashed service..."); 
      // stop the keep alives 
      // stopKeepAlives(); 

      // Do a clean start 
      start(); 
     } 
    } 

    @Override 
    public void onDestroy() 
    { 
     log("Service destroyed (started=" + mStarted + ")"); 

     // Stop the services, if it has been started 
     if (mStarted == true) { 
      stop(); 
     } 

     try { 
      if (mLog != null) 
       mLog.close(); 
     } catch (IOException e) { 
     } 
    } 

    @Override 
    public synchronized void onStart(Intent intent, int startId) 
    { 
     super.onStart(intent, startId); 
     log("Service started with intent=" + intent); 
     if (intent == null) { 
      start(); 
      return; 
     } 
     // Do an appropriate action based on the intent. 
     if (intent.getAction().equals(ACTION_STOP) == true) { 
      stop(); 
      stopSelf(); 
     } else if (intent.getAction().equals(ACTION_START) == true) { 
      start(); 
     } else if (intent.getAction().equals(ACTION_KEEPALIVE) == true) { 
      keepAlive(); 
     } else if (intent.getAction().equals(ACTION_PUBLISH) == true) { 
      publish(); 
     } else if (intent.getAction().equals(ACTION_SUBSCRIBE) == true) { 
      subscribe(); 
     } else if (intent.getAction().equals(ACTION_PUSHMESSAGE) == true) { 
      sendMessage(); 
     } else if (intent.getAction().equals(ACTION_RECONNECT) == true) { 
      if (isNetworkAvailable()) { 
       reconnectIfNecessary(); 
      } 
     } 
    } 

    private void subscribe() 
    { 
     // TODO Auto-generated method stub 
     try { 
      mConnection.subscribeToTopic(SUBSCRIBE_TOPIC); 
     } catch (MqttException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 

    private void publish() 
    { 

     try { 
      // Send a keep alive, if there is a connection. 
      if (mStarted == true && mConnection != null) { 
       mConnection.sendPushMessage(1); 
      } 
     } catch (MqttException e) { 
      log("MqttException: " 
        + (e.getMessage() != null ? e.getMessage() : "NULL"), e); 

      mConnection.disconnect(); 
      mConnection = null; 
      cancelReconnect(); 
     } 
    } 

    @Override 
    public IBinder onBind(Intent intent) 
    { 
     return null; 
    } 

    // log helper function 
    private void log(String message) 
    { 
     log(message, null); 
    } 

    private void log(String message, Throwable e) 
    { 
     if (e != null) { 
      Log.e(TAG, message, e); 

     } else { 
      Log.i(TAG, message); 
     } 

     if (mLog != null) { 
      try { 
       mLog.println(message); 
      } catch (IOException ex) { 
      } 
     } 
    } 

    // Reads whether or not the service has been started from the preferences 
    private boolean wasStarted() 
    { 
     return mPrefs.getBoolean(PREF_STARTED, false); 
    } 

    // Sets whether or not the services has been started in the preferences. 
    private void setStarted(boolean started) 
    { 
     mPrefs.edit().putBoolean(PREF_STARTED, started).commit(); 
     mStarted = started; 
    } 

    private synchronized void start() 
    { 
     log("Starting service..."); 

     // Do nothing, if the service is already running. 
     if (mStarted == true) { 
      Log.w(TAG, "Attempt to start connection that is already active"); 
      return; 
     } 

     // Establish an MQTT connection 
     connect(); 

     // Register a connectivity listener 
     registerReceiver(mConnectivityChanged, new IntentFilter(
       ConnectivityManager.CONNECTIVITY_ACTION)); 

    } 

    private synchronized void stop() 
    { 
     // Do nothing, if the service is not running. 
     if (mStarted == false) { 
      Log.w(TAG, "Attempt to stop connection not active."); 
      return; 
     } 

     // Save stopped state in the preferences 
     setStarted(false); 

     // Remove the connectivity receiver 
     unregisterReceiver(mConnectivityChanged); 
     // Any existing reconnect timers should be removed, since we explicitly 
     // stopping the service. 
     cancelReconnect(); 

     // Destroy the MQTT connection if there is one 
     if (mConnection != null) { 
      mConnection.disconnect(); 
      mConnection = null; 
     } 
    } 

    private clsUser setUserInfo(String deviceId) 
    { 
     clsUser u = new clsUser(); 

     dbUser du = new dbUser(getApplicationContext(), dbUser.DATABASE_NAME, 
       null, dbUser.DATABASE_VERSION); 

     Cursor c1 = du.Getby(null, null, null, null, null, null, null, null, 
       null, deviceId, null, null, null); 

     u = du.setProperties(c1); 
     c1.close(); 
     du.close(); 
     return u; 

    } 

    // 
    private synchronized void connect() 
    { 
     log("Connecting..."); 

     // Create a new connection only if the device id is not NULL 
     if (MQTT_CLIENT_ID == null) { 
      log("Device ID not found."); 
     } else { 
      try { 
       MQTT_CLIENT_ID = Config.id(getApplication()); 
       myInfo = setUserInfo(MQTT_CLIENT_ID); 
       mConnection = new MQTTConnection(MQTT_HOST, "user/" 
         + MQTT_CLIENT_ID + "/#"); 

      } catch (MqttException e) { 
       // Schedule a reconnect, if we failed to connect 
       log("MqttException: " 
         + (e.getMessage() != null ? e.getMessage() : "NULL")); 
       if (!isNetworkAvailable()) { 
        scheduleReconnect(mStartTime); 
       } 
      } 
      setStarted(true); 
     } 
    } 

    private synchronized void keepAlive() 
    { 
     try { 
      // Send a keep alive, if there is a connection. 
      if (mStarted == true && mConnection != null) { 
       mConnection.sendKeepAlive(); 
      } 
     } catch (MqttException e) { 
      log("MqttException: " 
        + (e.getMessage() != null ? e.getMessage() : "NULL"), e); 

      mConnection.disconnect(); 
      mConnection = null; 
      cancelReconnect(); 
     } 
    } 

    private void sendMessage() 
    { 
     try { 
      // Send a keep alive, if there is a connection. 
      if (mStarted == true && mConnection != null) { 
       mConnection.sendPushMessage(); // this does the job 
      } 
     } catch (MqttException e) { 
      log("MqttException: " 
        + (e.getMessage() != null ? e.getMessage() : "NULL"), e); 

      mConnection.disconnect(); 
      mConnection = null; 
      cancelReconnect(); 
     } 
    } 

    // Schedule application level keep-alives using the AlarmManager 
    private void startKeepAlives() 
    { 
     Intent i = new Intent(); 
     i.setClass(this, PushService.class); 
     i.setAction(ACTION_KEEPALIVE); 
     PendingIntent pi = PendingIntent.getService(this, 0, i, 0); 
     AlarmManager alarmMgr = (AlarmManager) getSystemService(ALARM_SERVICE); 
     alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, 
       System.currentTimeMillis() + KEEP_ALIVE_INTERVAL, 
       KEEP_ALIVE_INTERVAL, pi); 
    } 

    // Remove all scheduled keep alives 
    private void stopKeepAlives() 
    { 
     Intent i = new Intent(); 
     i.setClass(this, PushService.class); 
     i.setAction(ACTION_KEEPALIVE); 
     PendingIntent pi = PendingIntent.getService(this, 0, i, 0); 
     AlarmManager alarmMgr = (AlarmManager) getSystemService(ALARM_SERVICE); 
     alarmMgr.cancel(pi); 
    } 

    // We schedule a reconnect based on the starttime of the service 
    public void scheduleReconnect(long startTime) 
    { 
     // the last keep-alive interval 
     long interval = mPrefs.getLong(PREF_RETRY, INITIAL_RETRY_INTERVAL); 

     // Calculate the elapsed time since the start 
     long now = System.currentTimeMillis(); 
     long elapsed = now - startTime; 

     log(String.valueOf(elapsed)); 

     // Set an appropriate interval based on the elapsed time since start 
     if (elapsed < interval) { 
      interval = Math.min(interval * 4, MAXIMUM_RETRY_INTERVAL); 
     } else { 
      interval = INITIAL_RETRY_INTERVAL; 
     } 

     log("Rescheduling connection in " + interval + "ms."); 

     // Save the new internval 
     mPrefs.edit().putLong(PREF_RETRY, interval).commit(); 

     // Schedule a reconnect using the alarm manager. 
     Intent i = new Intent(); 
     i.setClass(this, PushService.class); 
     i.setAction(ACTION_RECONNECT); 
     PendingIntent pi = PendingIntent.getService(this, 0, i, 0); 
     AlarmManager alarmMgr = (AlarmManager) getSystemService(ALARM_SERVICE); 
     alarmMgr.set(AlarmManager.RTC_WAKEUP, now + interval, pi); 
    } 

    // Remove the scheduled reconnect 
    public void cancelReconnect() 
    { 
     Intent i = new Intent(); 
     i.setClass(this, PushService.class); 
     i.setAction(ACTION_RECONNECT); 
     PendingIntent pi = PendingIntent.getService(this, 0, i, 0); 
     AlarmManager alarmMgr = (AlarmManager) getSystemService(ALARM_SERVICE); 
     alarmMgr.cancel(pi); 
    } 

    private synchronized void reconnectIfNecessary() 
    { 
     if (mStarted == true && mConnection == null) { 
      log("Reconnecting..."); 
      connect(); 
     } 
    } 

    private class MQTTConnection 
      implements MqttCallback 
    { 
     MqttClient mqttClient = null; 
     MqttConnectOptions conOpt; 
     String myDeviceId; 

     // Creates a new connection given the broker address and initial topic 
     public MQTTConnection(String brokerHostName, String initTopic) 
       throws MqttException 
     { 
      // Create connection spec 

     } 

     private void publish(String topicName, int qos, String payload, 
       boolean retained) throws MqttException 
     { 

     } 

     /* 
     * Sends a message to the message broker, requesting that it be 
     * published to the specified topic. 
     */ 
     private void publishToTopic(String topicName, String message) 
       throws MqttException 
     { 

      if ((mqttClient == null) || (mqttClient.isConnected() == false)) { 
       // quick sanity check - don't try and publish if we don't have 
       // a connection 
       log("No connection to public to"); 
      } else { 
       publish(topicName, MQTT_QUALITY_OF_SERVICE, message, false); 
      } 

     } 

     /* 
     * Send a request to the message broker to be sent messages published 
     * with the specified topic name. Wildcards are allowed. 
     */ 
     private void subscribeToTopic(String topicName1) throws MqttException 
     { 

      if ((mqttClient == null) || (mqttClient.isConnected() == false)) { 
       // quick sanity check - don't try and subscribe if we don't have 
       // a connection 
       log("Subscribtion failed : Connection error" + "No connection"); 
      } else { 

       mqttClient.subscribe(topicName1, 0); 
       Log.v(TAG, "Subscribe To : " + topicName1); 

      } 
     } 

     public void sendPushMessage(int sira) throws MqttException 
     { 

      publishToTopic(PUBLISH_TOPIC, PushMesaj); 
     } 
    } 

} 
+0

我更正了網址 – 2013-03-26 16:03:49

+0

onStart已棄用。改用onStartCommand。 – 2013-03-26 16:07:23

+0

@DoctororDrive有關'onStart()'的註釋與問題無關,是嗎?我的意思是,用'onStartCommand()'代替它不會解決OP的問題。 – 2013-03-26 16:11:32

回答

1

當你調用actionPush(),它執行以下操作:

PUBLISH_TOPIC = publishTopic; 
    PushMesaj = pushMsg; 

從而節省了在private static變量的參數,然後調用startService。如果你這樣做了兩次,你將用第二組參數覆蓋private static變量。

您需要了解對startService()的呼叫不同步。它不會立即啓動服務並在方法返回之前調用onStart()。該服務將開始,並且撥打onStart()將在稍後發生(時間不在您的控制範圍之內)。

您希望將這些參數放入您用於啓動服務的Intent中,並從IntentonStart()中檢索參數。您無法可靠地使用static變量來執行此操作。

編輯:添加代碼細節

變化actionPush()這樣:

static final String EXTRA_TOPIC = "EXTRA_TOPIC"; 
static final String EXTRA_MESSAGE = "EXTRA_MESSAGE"; 

public static void actionPush(Context ctx, String publishTopic, 
     String pushMsg) 
{ 
    Intent i = new Intent(ctx, PushService.class); 
    i.setAction(ACTION_PUSHMESSAGE); 
    i.putExtra(EXTRA_TOPIC, publishTopic); 
    i.putExtra(EXTRA_MESSAGE, pushMsg); 
    ctx.startService(i); 
} 

onStart()你可以得到的參數了Intent這樣的:

String topic = intent.getStringExtra(EXTRA_TOPIC); 
String message = intent.getStringExtra(EXTRA_MESSAGE); 

我我不會爲你重寫整個程序。你現在必須弄清楚如何處理參數。也許你現在可以將它們存儲在private static變量中,但是我對你的程序不夠了解,無法確定它是否可行。更好的解決方案是通過你定義的各種方法傳遞參數,直到他們使用它們的方法。

+0

那我該怎麼辦?如何更改代碼以解決我的問題? – 2013-03-26 20:07:41

+0

哇,非常感謝你,我測試了你的建議,它的工作原理,所以問題是傳遞變量的意圖,我總是使用傳遞參數意圖與putExtra,但在服務,它並沒有出現在我的腦海裏。作爲經典編程。 – 2013-03-27 01:08:09