ContentObserver onChange () is repeated several times

I am trying to query data from CallLog and insert into DB. To do this, I created COntentObserver as an inner class in the service and inside the onChange () method, I call my method, which goes to the specified URI and requests the data that has been changed.

But, say, I got a call, so the observer was informed. So my method goes to the call log content provider, query and insert, but it inserts two, three times the same register.

Here is the code for my service.

public class RatedCallsService extends Service private Handler handler = new Handler(); private SQLiteDatabase db; private OpenHelper helper; private String theDate; private String theMonth_; private String theYear_; private String theDay_; public static boolean servReg = false; class RatedCallsContentObserver extends ContentObserver { public RatedCallsContentObserver(Handler h) { super(h); //helper = new OpenHelper(getApplicationContext()); //db = helper.getWritableDatabase(); } @Override public boolean deliverSelfNotifications() { return true; } @Override public void onChange(boolean selfChange) { super.onChange(selfChange); Log.i(LOG_TAG, "Inside on Change. selfChange " + selfChange); searchInsert(); } } @Override public IBinder onBind(Intent arg0) { return null; } @Override public void onCreate() { servReg = true; db = DataHandlerDB.createDB(this); registerContentObserver(); } @Override public void onDestroy() { super.onDestroy(); db.close(); this.getApplicationContext().getContentResolver().unregisterContentObserver(new RatedCallsContentObserver(handler)); } private void searchInsert() { Cursor cursor = getContentResolver().query( android.provider.CallLog.Calls.CONTENT_URI, null, null, null, android.provider.CallLog.Calls.DATE + " DESC "); if (cursor.moveToFirst()) { int numberColumnId = cursor .getColumnIndex(android.provider.CallLog.Calls.NUMBER); int durationId = cursor .getColumnIndex(android.provider.CallLog.Calls.DURATION); int contactNameId = cursor .getColumnIndex(android.provider.CallLog.Calls.CACHED_NAME); int numTypeId = cursor .getColumnIndex(android.provider.CallLog.Calls.CACHED_NUMBER_TYPE); int callTypeId = cursor .getColumnIndex(android.provider.CallLog.Calls.TYPE); Date dt = new Date(); int hours = dt.getHours(); int minutes = dt.getMinutes(); int seconds = dt.getSeconds(); String currTime = hours + ":" + minutes + ":" + seconds; SimpleDateFormat dateFormat = new SimpleDateFormat("M/d/yyyy"); Date date = new Date(); cursor.moveToFirst(); String contactNumber = cursor.getString(numberColumnId); String contactName = (null == cursor.getString(contactNameId) ? "" : cursor.getString(contactNameId)); String duration = cursor.getString(durationId); String numType = cursor.getString(numTypeId); String callType = cursor.getString(callTypeId); seconds = Integer.parseInt(duration); theDate = dateFormat.format(date); if (theDate.length() == 9) { theMonth_ = theDate.substring(0, 1); theDay_ = theDate.substring(2, 4); theYear_ = theDate.substring(5, 9); } else if (theDate.length() == 10) { theMonth_ = theDate.substring(0, 2); theDay_ = theDate.substring(3, 4); theYear_ = theDate.substring(6, 10); } else if (theDate.length() == 8) { theMonth_ = theDate.substring(0, 1); theDay_ = theDate.substring(2, 3); theYear_ = theDate.substring(4, 8); } ContentValues values = new ContentValues(); ContentValues values2 = new ContentValues(); values.put("contact_id", 1); values.put("contact_name", contactName); values.put("number_type", numType); values.put("contact_number", contactNumber); values.put("duration", Utilities.convertTime(seconds)); values.put("date", dateFormat.format(date)); values.put("current_time", currTime); values.put("cont", 1); values.put("type", callType); values2.put("month", Utilities.monthName(Integer.parseInt(theMonth_))); values2.put("duration", Utilities.convertTime(seconds)); values2.put("year", theYear_); values2.put("month_num", Integer.parseInt(theMonth_)); if (!db.isOpen()) { db = getApplicationContext() .openOrCreateDatabase( "/data/data/com.project.myapp/databases/myDb.db", SQLiteDatabase.OPEN_READWRITE, null); } if (duration != "") { if (Integer.parseInt(duration) != 0) { String existingMonthDuration = DataHandlerDB .selectMonthsDuration(theMonth_, theYear_, this); Integer newMonthDuration; if (existingMonthDuration != "") { newMonthDuration = Integer .parseInt(existingMonthDuration) + Integer.parseInt(duration); values2.put("duration", Utilities.convertTime(newMonthDuration)); db.update(DataHandlerDB.TABLE_NAME_3, values2, "year = ?", new String[] { theYear_ }); } else { db.insert(DataHandlerDB.TABLE_NAME_3, null, values2); } db.insert(DataHandlerDB.TABLE_NAME_2, null, values); } } cursor.close(); } } public void registerContentObserver() { this.getApplicationContext() .getContentResolver() .registerContentObserver( android.provider.CallLog.Calls.CONTENT_URI, false, new RatedCallsContentObserver(handler)); } } 

I have tried everything. unregistration of an observer, etc., but nothing.

+4
source share
2 answers

I have selected a call timestamp from android.provider.CallLog.Calls.DATE and before inserting I check if there is a timestamp like this if I do not insert, if I do not insert data. These values ​​are unique, so they will never be alike.

+2
source

This happens to me when I subscribe to his SMS content provider. I think this is the way that Android handles messages and calls that make this behavior, I get a call 2 times every time I send an SMS, so I assume the message is sent to the outgoing message table? first, and then moved to the submitted table. Perhaps something similar happens with the call provider? Perhaps this call is placed in a temporary table inside the provider, and then, as soon as you receive or miss it, this call goes to the correct table (received / missed). What I do, I check the message identifier every time the calling observer calls me, and I save the identifier of the previous message, so I can check. If the observer is tempered due to the same identifier that I just processed.

Does the value of selfChange change?

Hint. Do not rely on this provider to control all your calls. As soon as the android decides to terminate your application, you will notice that your provider will no longer receive calls. Try planning to bind the content observer each time using the AlarmManager.

+1
source

All Articles