Android 历史内容观察者

Posted

技术标签:

【中文标题】Android 历史内容观察者【英文标题】:Android History Content Observer 【发布时间】:2013-05-14 16:05:02 【问题描述】:

我实现了历史内容观察器,但它的行为很奇怪。对于历史中的每一次更改,它的 onChange() 函数都会运行 3-5 次。

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


我还使用

注册了我的观察者
BrowserOberser observer = new BrowserOberser();
getApplication().getContentResolver().registerContentObserver(Browser.BOOKMARKS_URI, true, observer );

并在清单中添加了所需的权限。

代码运行良好,但 onChange();每次历史变化运行 3-5 次 谁能帮我解决这个问题?

【问题讨论】:

***.com/questions/6026547/… 对我没有帮助。 我观察到的是第一次和第三次运行之间的区别是:在第一次运行中,标题与 url 相同,但在第三次运行中出现了适当的标题。所以这可能是因为页面加载的阶段。但它到底是什么?为什么运行次数不同? 如果您需要更多信息,请发表评论 【参考方案1】:

这就是我最终为我的案例解决问题的方法(我想在历史发生变化时阅读历史)

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

但是,如果有人能分辨出 onChange 的哪个迭代(在问题的简单代码中)与页面加载中的哪个状态完全对应,那就太好了。 据我所知,在第一次迭代中,标题与 url 相同,在第三次迭代中,出现了正确的页面标题。但是在重定向期间,onChange 被调用了 5 次。那么有人可以确认哪个迭代对应哪个阶段吗?

【讨论】:

【参考方案2】:

我想我可能会找到答案。 首先我想说我的英语有限,希望你能理解我。

确实,onChange(); 会针对历史记录的每次更改运行多次,至少两次。

因为当用户使用浏览器浏览网站时,系统会在数据库中添加一个历史记录,并调用onChange();。但是现在系统不知道 url 的标题。系统得到url的标题后,系统更新数据库,第二次调用onChange();

而且,如果在此期间url正在重定向,每次系统得到一个新的url时,系统也会更新数据库,所以onChange();也被称为。 所以,我认为每次更改都会调用 onChange 多次。 希望你能听懂我的英文。

【讨论】:

【参考方案3】:

更新历史的确切方式是您可能不想依赖的实现细节。与其尝试根据各个字段的值来猜测更新是否完成,我建议每次调用onChange(..) 时重新启动一个计时器。如果计时器到期,您可以合理地确定历史记录已完成更新。

编辑如何使用计时器的示例:

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


【讨论】:

嗯,这也是一个不错的方法,我尝试过,但没有奏效。 1) 猜测历史何时完成更新也很棘手。假设用户在页面加载过程中失去了互联网连接,这将导致标题与 url 相同(这是基于我的实际观察)。 2)您打算如何实施? onChange() 将在每次 url 加载时被调用 5 次,所以你不能只是暂停它,因为这不会产生预期的结果。 如果你能告诉我更新历史的确切方式是什么,我将不胜感激(当然赏金也是你的)。 好吧,这种方法很好,但问题 1) 仍然存在。如果用户网络很慢并且站点很重,则可能需要更长的时间。我将延迟时间增加到 5000,有时会重复进入。但我真的很感激这个答案:) 因此赏金 我尝试将延迟时间增加到 20000(假设该页面肯定会在 20 秒内加载,否则我会得到错误的结果),它使浏览器非常慢,并且记录日志的次数也没有非常一致。所以不,这不是理想的解决方案

以上是关于Android 历史内容观察者的主要内容,如果未能解决你的问题,请参考以下文章

Android10_内容提供者_内容观察者_标题栏

Android 在电话簿更新时通知(内容观察者)

设计模式 观察者模式 以Android中TextView文本内容发生变化为背景

设计模式 观察者模式 以Android中TextView文本内容发生变化为背景

在 Android 内容观察器中观察 Audio.Media.EXTERNAL_CONTENT_URI 的变化

Android 手机卫士8--删除通话记录