Android: content observer's "onChange()" method is called multiple times
Asked Answered
T

4

10

I am using a content observer for content://sms. I am writing all the messages to a text file in SD card. But the onChange() method in the content observer is called multiple times and the same message is written multiple times to the text file. How to avoid this? Also I want to know if having the content observer will slow down the phone.

Twila answered 17/5, 2011 at 5:22 Comment(1)
So did you solved the problem? Im having the same problem. Can you help me how to solve it? Im registerin my observer in a service. And it repeats two, three, some times.Choriamb
S
7

You need to override deliverSelfNotifications() to return true.

class ObserverSms extends ContentObserver {
private Context mContext;

public ObserverSms(Context context, Handler handler) {
    super(handler);
    mContext = context;
}

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

@Override
public void onChange(boolean selfChange) {
    super.onChange(selfChange);
    MyLog.logDebugInConsole(TAG, "Sms Database Changed");
}
}
Sapro answered 7/6, 2011 at 6:32 Comment(1)
It did not change the result, I coded and tested it for history observer and the problem is still there(after doing what u said)Phenetidine
F
1

Vivek, please ensure that you unregister your content observer any time you leave the activity e.g. in onDestroy() method, call unregisterContentObserver(). Hope this help ! (in my case it worked)

Freightage answered 23/5, 2011 at 9:48 Comment(4)
I am not having any activity. Just the content observer runs in the background and records all the sms in a text file. So if I unregister the content observer after I write into the text file, then how can I get to know the next sms recieved or sent without content observer?Twila
If this "background" thing is a service, try to unregister in its onDestroy() function.Freightage
you can also try to pass Application's Context while registering ContentObserver instead of Activity. I have not tested it, but this should work.Freightage
I tried it out and it did not work for me. Why is it marked as the correct answer when it is not?Phenetidine
C
1

Try this to avoid multiple execution of onChange()

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();

    }
Clo answered 25/12, 2013 at 7:50 Comment(1)
Can you explain the code? What behaviour dd you induce to chang?Saloop
T
0

The onChange() event is called once for each column that changes (i.e. "body" or "address") - thus the multiple calls. The easiest way to only process the data once is to store the value of the "_id" column, see if it has changed on the next iteration and then ignore.

cur.getColumnIndex("_id")

See example here: Sms ContentObserver onChange() fires multiple times

Transpire answered 11/9, 2013 at 21:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.