2012-02-02 14 views
6

Sé que esta pregunta se ha hecho varias veces, pero nadie ha podido encontrar una respuesta que funcione de acuerdo con lo que he visto.Sms ContentObserver onChange() se dispara varias veces

Estoy trabajando en una aplicación para interceptar mensajes de texto y, dependiendo del # de envío, aparece una alerta personalizada. Lo tengo funcionando muy bien con un receptor de difusión, sin embargo, si el usuario tiene GoSms instalado, el método onReceive() nunca se llama, ya que goSms aborta antes de que llegue a mi aplicación.

Para evitar esto, estoy tratando de un observador de contenido en content://sms/ Funciona bien, sin embargo, el onChange() se llama dos veces, con exactamente los mismos parámetros. He tratado de verificar las marcas de tiempo, pero son las mismas, como es el tipo y todos los demás parámetros que he establecido.

Por lo que he visto, este es un problema común, pero no uno que he visto respondido en ninguna parte.

@Override 
public void onChange(boolean selfChange) { 
    super.onChange(selfChange); 
    querySMS(); 
} 

protected void querySMS() { 
    Cursor cur = getContentResolver().query(u, null, null, null, null); 
    cur.moveToNext(); // this will make it point to the first record, which is the last SMS sent 
    String type = cur.getString(cur.getColumnIndex("type")); 
    String body = cur.getString(cur.getColumnIndex("body")); //content of sms 
    String add = cur.getString(cur.getColumnIndex("address")); //phone num 
    if (type.equals("1")) { 
     if (add.equals(Test.SENDER)) {    
      String[] bodys = body.split(" ", 7); 
      if (bodys[0].equals("test")) { 
       test = true; 
      } 
      cat = bodys[1]; 
      level = bodys[2]; 
      urgency = bodys[3]; 
      certainty = bodys[4]; 
      carrier = bodys[5]; 
      message = bodys[6]; 
      final Intent intent = new Intent(context, AlertActivity.class); 
      Bundle b = new Bundle(); 
      b.putString("title", cat); 
      b.putString("certainty", certainty); 
      b.putString("urgency", urgency); 
      b.putString("level", level); 
      b.putString("message", message); 
      b.putBoolean("test", test); 
      intent.putExtras(b); 
      intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
      intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 
      TelephonyManager manager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE); 
      carrierName = manager.getNetworkOperatorName(); 
      if (carrierName.replaceAll(" ", "").equals(carrier)) { 

       context.startActivity(intent); 
      } else { 
       //testing 
       Toast.makeText(context, carrierName.replaceAll(" ", ""), Toast.LENGTH_LONG).show(); 
      } 
     } 
    } 
} 

Debido a la onChange() ser despedido dos veces, Im que consigue dos alertas también. No puedo, por la vida de mi, encontrar una forma de evitar esto.

+1

enlaces a las otras respuestas (incompletas) serían útiles – KevinDTimm

Respuesta

4

Si los dos son idénticos:
tienda de cada mensaje recv'd
lo comparan con los mensajes anteriores recv'd
si no lo encuentra, el proceso
si se encuentra, se descarta el mensaje

La vida de los mensajes almacenados deben ser infinitesimales, un pequeño búfer circular de 5 mensajes debería estar bien.

+0

el mensaje solo se recibió una vez. no viene dos veces tbh, ni siquiera sé de qué se está disparando el segundo 'onChange'. – r2DoesInc

+2

Ah. Junté tu idea con http://stackoverflow.com/questions/7012703/android-detect-sms-outgoing-incorrect-count y lo conseguí funcionando. Creo que entendí mal lo que querías decir la primera vez que lo leí. Creé una 'lista_múltiple 'estática y la utilicé para verificar. \t \t \t 'if (! Ids.contains (id)) {ids.add (id); context.startActivity (intent);}' – r2DoesInc

3

Puede guardar el id del último mensaje y compararlo con el id del mensaje que se devuelve por cur en onChange. entonces puede simplemente ignorar el mensaje si los id son los mismos.

// might contain mistakes, but you'll get the idea: 
protected void querySMS() { 
    Cursor cur = getContentResolver().query(u, null, null, null, null); 
    cur.moveToNext(); 
    if (lastId == cur.getLong(cur.getColumnIndex("_id"))) 
     return; 
    lastId = cur.getLong(cur.getColumnIndex("_id")); 
    ... //continue as it was 
} 

Sin embargo - GO SMS sólo impide que otros de aplicación desde que recibe la difusión si el usuario selecciona esta opción (Ajustes recibir - Desactivar otra notificación de mensajes) - por lo que si el usuario no desea que otras aplicaciones molestarlo - I piensa que es una buena idea no hacerlo.

+0

La aplicación en la que trabajo no es una que deba ignorarse, nunca. Está preinstalado en dispositivos y tiene prioridad total sobre cualquier otra cosa que se esté ejecutando actualmente en el teléfono. Hice algo similar a esto, si miras los comentarios de la respuesta a continuación, puedes ver. – r2DoesInc

+1

entiendes que el fragmento que has publicado debería ir realmente, muy lejos antes de poder usarse en la aplicación preinstitucional, ¿no? – Vladimir

+0

oh sí, por supuesto. Acabo de comenzar el proyecto. tiene un largo camino por recorrer – r2DoesInc

4

aquí es mi código, que funciona bien para mí

public class SmsObserver extends ContentObserver { 
    private Context context; 
    private static int initialPos; 
    private static final String TAG = "SMSContentObserver"; 
    private static final Uri uriSMS = Uri.parse("content://sms/sent"); 

    public SmsObserver(Handler handler, Context ctx) { 
     super(handler); 
     context = ctx; 
     initialPos = getLastMsgId(); 

    } 

    @Override 
    public void onChange(boolean selfChange) { 
     super.onChange(selfChange); 
     queryLastSentSMS(); 
    } 

    public int getLastMsgId() { 

     Cursor cur = context.getContentResolver().query(uriSMS, null, null, null, null); 
     cur.moveToFirst(); 
     int lastMsgId = cur.getInt(cur.getColumnIndex("_id")); 
     Log.i(TAG, "Last sent message id: " + String.valueOf(lastMsgId)); 
     return lastMsgId; 
    } 

    protected void queryLastSentSMS() { 

     new Thread(new Runnable() { 

      @Override 
      public void run() { 
       Cursor cur = 
        context.getContentResolver().query(uriSMS, null, null, null, null); 

       if (cur.moveToNext()) { 


        try { 
         if (initialPos != getLastMsgId()) { 
          // Here you get the last sms. Do what you want. 
          String receiver = cur.getString(cur.getColumnIndex("address")); 
          System.out.println(" Receiver Ph no :"+receiver); 


          // Then, set initialPos to the current position. 
          initialPos = getLastMsgId(); 
         } 
        } catch (Exception e) { 
         // Treat exception here 
        } 
       } 
       cur.close(); 
      } 
     }).start(); 

    } 

}//End of class SmsObserver 
0

sólo tiene que utilizar SharedPreference remarcar la última información de SMS (como: id\type ...). si es el mismo, lo haré return.

Cuestiones relacionadas