Question

I implemented content observer of history but it is behaving weird.For every change in history its onChange() function runs 3-5 times.

static class BrowserOberser extends ContentObserver {
    public BrowserOberser() {
        super(null);
    }

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

    @Override
    public void onChange(boolean selfChange) {
        super.onChange(selfChange);
        Log.d("History", "onChange: " + selfChange);
    }

}

I also registered my observer using

BrowserOberser observer = new BrowserOberser();
getApplication().getContentResolver().registerContentObserver(Browser.BOOKMARKS_URI, true, observer );

and added required permissions in manifest.

The code works fine but onChange(); runs 3-5 times for each change in history
Can anyone help me out with a solution to this problem?

Was it helpful?

Solution

This is how I finally solved the problem for my case atleast(I wanted to read history when there is change in history)

    @Override
    public void onChange(boolean selfChange) {
        super.onChange(selfChange);
        /**
         * Get SharedPreferneces of the user
         */
        SharedPreferences pref= myContext.getSharedPreferences("com.tpf.sbrowser", 
                Context.MODE_PRIVATE);
        long wherelong = pref.getLong("Date", 0);
        DatabaseManager db=new DatabaseManager(myContext,1);
        String[] proj = new String[] { Browser.BookmarkColumns.TITLE,
                Browser.BookmarkColumns.URL, BookmarkColumns.DATE,};
        String sel = Browser.BookmarkColumns.BOOKMARK + " = 0"; 
        Cursor mCur = myContext.getContentResolver().query(
                Browser.BOOKMARKS_URI, proj, sel, null, null);
        Log.d("onChange", "cursorCount"+mCur.getCount());
        mCur.moveToFirst(); 
        String title = ""; 
        String url = ""; 
        long lastVisitedDate=0;
        DbMessage msg = new DbMessage(lastVisitedDate,url, title);
        /**
         * Start reading the user history and dump into database
         */
        if(mCur.moveToFirst() && mCur.getCount() > 0) { 
              while (mCur.isAfterLast() == false) {
                  title =mCur.getString(0); 
                  url = mCur.getString(1); 
                  lastVisitedDate =mCur.getLong(2); 
                  if ((lastVisitedDate>wherelong) && (!title.equals(url))) {
                      msg.set(lastVisitedDate, url, title);
                      db.InsertWithoutEnd(msg);
                      pref.edit().putBoolean("BrowserHistoryRead", true).commit();
                      pref.edit().putLong("Date", lastVisitedDate).commit();
                      myContext.updateTime(wherelong,lastVisitedDate);
                      wherelong=lastVisitedDate;
                  }
                  mCur.moveToNext(); 
              } 
          }
    }

But still if would be great if someone could tell which iteration of onChange(in the simple code of question) corresponds to exactly which state in page loading. From what I learned, in first iteration title was same as url and in the third iteration the correct page title was present. But during redirection, onChange got called upto 5 times. So can someone confirm which iteration coressponds to which stage?

OTHER TIPS

I think I may find the answer. First I want to say that my English is limited, I hope that you can understand me.

Indeed, onChange(); runs several times for each change in history, at least two times.

Because when user use the browser to browse a website, the system add a history in database, and onChange(); is called. But right now the system don't know the title of the url. After the system got the title of the url, the system updates the database and onChange(); is called second time.

And, if the url is redirecting during the time, every time the system gets a new url, the system will update the database too, so onChange(); is called too. So, I think onChange will be called several times every change. Hope you can understand my English.

The exact way in which history is updated is an implementation detail you probably do not want to be relying on. Rather than trying to guess whether the update is finished or not based on the values of various fields, I would suggest restarting a timer each time onChange(..) is called. If the timer expires, you can be reasonably certain that history has finished updating.

Edit Example of how to use a timer:

static class BrowserOberser extends ContentObserver implements Runnable {
    private Handler h;

    public BrowserOberser() {
        super(null);
        h = new Handler();
    }

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

    @Override
    public void onChange(boolean selfChange) {
        super.onChange(selfChange);
        h.removeCallbacks(this);
        h.postDelayed(this, 500);
    }

    public void run() {
        Log.d("history observer", "change timer elapsed");
    }

}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top