5

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?

Donald Duck
  • 8,409
  • 22
  • 75
  • 99
Aditya
  • 5,509
  • 4
  • 31
  • 51
  • 4
    http://stackoverflow.com/questions/6026547/android-content-observers-onchange-method-is-called-multiple-times was of no help to me. – Aditya May 20 '13 at 08:32
  • 3
    What I observed was that the difference between the first and third run was: In first run title is same as url but in third run the appropriate title is present. So it is maybe because of the stages the pages are loaded in. But what exactly is it? And why the number of runs differ? – Aditya May 23 '13 at 10:05
  • please leave a comment if you need more information – Aditya May 23 '13 at 12:39

3 Answers3

2

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?

Aditya
  • 5,509
  • 4
  • 31
  • 51
1

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.

Robert
  • 5,278
  • 43
  • 65
  • 115
0

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");
    }

}
j__m
  • 9,392
  • 1
  • 32
  • 56
  • 1
    Well that is a nice approach too and I tried it, but it did not work. 1) Guessing when the history has finished updating can be tricky too. Suppose user loses internet connection during page loading, that will cause the title to be same as the url (thats based on my actual observation). 2) How do you propose to implement it? `onChange()` will be called 5 times for every url load, so you cant just pause it as that wont give the desired result. – Aditya May 30 '13 at 05:14
  • And if you can tell me what is the exact way in which history is updated, I would be grateful (ofcourse the bounty is yours too then). – Aditya May 30 '13 at 05:17
  • 1
    Well this approach is good but still the problem 1) stays. If the user net is very slow and site is very heavy, it could take longer. I increased the delay time to 5000 and sometimes got repeated entry. But I really appreciate the answer :) and hence the bounty – Aditya May 30 '13 at 08:30
  • 5
    I tried increasing time delay to 20000(assuimg that page will surely load in 20sec, otherwise I will get incorrect results), it made browser EXTREMELY slow and the number of times the log was recorded was also not very consistent. So no this is not the ideal solution – Aditya May 30 '13 at 09:06