2011-09-20 28 views
12

Ho seguito l'implementazione ContentObserver per ricevere e scrivere SMS, ma è chiamato più volte.Perché il ContentObserver viene chiamato più volte?

Codice:

public class SMSObserverActivity extends Activity { 
    protected MyContentObserver observer = null; 

    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState){ 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 
     String url = "content://mms-sms/"; 
     Uri uri = Uri.parse(url); 
     observer = new MyContentObserver(new Handler()); 
     getContentResolver().registerContentObserver(uri, true, observer); 
    } 

    @Override 
    protected void onDestroy(){ 
     super.onDestroy(); 

     getContentResolver().unregisterContentObserver(observer); 
    } 

    class MyContentObserver extends ContentObserver { 
     ContentValues values = new ContentValues(); 
     Handler handler; 

     public MyContentObserver(Handler handler){ 
      super(handler); 
      this.handler = handler; 
     } 

     @Override 
     public boolean deliverSelfNotifications(){ 
      return false; 
     } 


     @Override 
     public void onChange(boolean arg0){ 
      super.onChange(arg0); 

      Log.v("SMS", "Notification on SMS observer"); 
      values.put("status", 5); 
      Message msg = new Message(); 
      msg.obj = "xxxxxxxxxx"; 
      int threadId = 0; 
      handler.sendMessage(msg); 

      Uri uriSMSURI = Uri.parse("content://sms/"); 
      Cursor cur = 
        getContentResolver().query(uriSMSURI, null, null, null, 
          null); 
      cur.moveToNext(); 
      Log.e("sms", cur.getString(4)+" "+cur.getString(11)); 
     } 
    } 
} 

manifesto:

<?xml version="1.0" encoding="utf-8"?> 
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
    package="com.test" 
    android:versionCode="1" 
    android:versionName="1.0"> 
    <uses-sdk android:minSdkVersion="8" /> 
    <uses-permission android:name="android.permission.READ_SMS"></uses-permission> 
    <uses-permission android:name="android.permission.WRITE_SMS"></uses-permission> 

    <application android:icon="@drawable/icon" android:label="@string/app_name"> 
     <activity android:name=".SMSObserverActivity" 
        android:label="@string/app_name"> 
      <intent-filter> 
       <action android:name="android.intent.action.MAIN" /> 
       <category android:name="android.intent.category.LAUNCHER" /> 
      </intent-filter> 
     </activity> 

    </application> 
</manifest> 

Perché si chiama più volte?

MODIFICA:
C'è stata l'idea che il problema sia causato dallo unregisterContentObserver mancante, ma non fa alcuna differenza.

+0

hai mai questo numero? –

+0

Non ancora, non ho ancora il tempo, ma leggi i commenti sulla risposta e provalo con un servizio. Forse lo farai funzionare. ;) – CSchulz

+0

Il problema è lo stesso se eseguito in un servizio che ho paura –

risposta

11

Ciò si verifica perché si sta registrando l'osservatore dei contenuti per l'intero database SMS. Quindi il tuo osservatore di contenuti riceve una notifica ogni volta che viene aggiornata una voce della tabella nel database.

In questo caso quando viene inviato un messaggio, ad esempio circa 7 tabelle, le voci vengono aggiornate in modo che l'osservatore del contenuto venga avvisato 7 volte.

Dato che sono interessato solo se viene inviato un messaggio, mi sono modificato per osservare solo i messaggi in coda e questo significa che il mio osservatore riceve sempre una notifica esattamente tre volte, quindi ho implementato il codice per proteggerlo.

È probabile che ci siano altri problemi come messaggi multi-destinatario o multiparte, ma le basi funzionano finora.

+0

Okay, ho pensato che l'osservatore venga chiamato una sola volta per tutti gli aggiornamenti correlati per oggetto. Penso che ci sia un ID univoco da vedere, quali notifiche appartengono a un aggiornamento, no? – CSchulz

0

Se si desidera avere il vostro osservatore abilitato solo quando l'attività è in stato attivo, vi consiglio di spostare registerContentObserver() e unregisterContentObserver() ai metodi onResume() e onPause() rispettivamente. onDestroy() non può essere chiamato se l'applicazione termina, ma è garantito che sia onPause().

+0

L'osservatore deve essere sempre attivo quando * Attività * è in esecuzione. È solo un test del contenuto osservativo. – CSchulz

+0

L'attività è in esecuzione tra 'onResume()' e 'onPause()', nell'altro tempo è in background o non è visibile. Può anche essere ucciso senza ricevere una chiamata a 'onDestroy()', e quando si ricrea l'applicazione in 'onCreate()', si registrerà un osservatore per la seconda volta. – Malcolm

+0

Perché deve essere registrato due volte? Ho una dichiarazione di annullamento della registrazione. – CSchulz

2

per evitare l'invio di sms multipli da osservatore contenuti provare questo

public class SmsObserver extends ContentObserver { 
    SharedPreferences trackMeData; 
    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; 
     trackMeData = context.getSharedPreferences("LockedSIM", 0); 
     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 { 

         String body = cur.getString(cur.getColumnIndex("body")); 

         if (initialPos != getLastMsgId()) { 

          String receiver = cur.getString(cur.getColumnIndex("address")); 
          Log.i("account", myDeviceId); 
          Log.i("date", day + "-" + month + "-" + year + " " 
           + hour + ":" + minute + ":" + seconde); 
          Log.i("sender", myTelephoneNumber); 
          Log.i("receiver", receiver); 


          // Then, set initialPos to the current position. 
          initialPos = getLastMsgId(); 

          sendsmstoph(receiver, body); 
         } 
        } catch (Exception e) { 
         // Treat exception here 
        } 
       } 
       cur.close(); 
      } 
     }).start(); 

    } 
+0

Chiamata initialPos = getLastMsgId(); dal contructor lancia l'eccezione puntatore nullo –

+0

Ho notato che questo è buono ma non sempre infallibile. Quindi penso che l'uso di SharedPreferences possa risolvere questo problema. Ecco come l'ho fatto: if (! SharedPreferences.getString ("lastMessageTime", "0") .equals (String.valueOf (timeInMillis)) ||! SharedPreferences.getString ("lastMessageNumber", "0") .equals (numero)) – Usman

Problemi correlati