1

the app I'm currently working on has to react on changes in the calendar or event database, therefore the Observer below gets registered with the URI:

content://com.android.calendar (for older Devices: content://calendar)

The "problem" is that the Observer gets (sometimes) called several times, when respective data gets changed. If I register two separate ContentResolver, one for .../calendars and one for .../events they still get often called multiple times. What I try to achieve with the following code is to buffer those multiple calls, as the ContentResolver itself calls a service, that would run a lot of code. So the service should only get called once for many ContentObserver calls in a short period of time.

public class Observer extends ContentObserver{

private Context con;

public Observer(Handler handler, Context con) {
    super(handler);
    this.con = con;
}

@Override
public void onChange(boolean selfChange) {
    Log.i("TS", "Änderung an den Kalendern");

    //Gets released after the first Change, waits and checks SharedPrefs in order to buffer multiple Calls in a short period of time!
    //Changes get handled in the Service
    Thread buffer = new Thread(){

        @Override
        public void run() {
            int check = 1, last = 0;

            do{
                try {
                    sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                last = check;
                check = getCurrent();
            } while(last != check);

            releaseIntent();
        }

    };

    SharedPreferences prefs = con.getSharedPreferences(con.getPackageName(), Context.MODE_PRIVATE);
    Editor edit = prefs.edit();

    int first = prefs.getInt(Constants.FIRST_ON_CHANGE, 1);

    if(first == 1)
        buffer.run();

    first++;

    edit.putInt(Constants.FIRST_ON_CHANGE, first);
    edit.commit();

}

//returns the current control-integer from SharedPrefs (for Thread)
private int getCurrent(){
    SharedPreferences prefs = con.getSharedPreferences(con.getPackageName(), Context.MODE_PRIVATE);
    return prefs.getInt(Constants.FIRST_ON_CHANGE, 1);      
}

//releases ContentChanged-Intent for Service, resets SharedPrefs
private void releaseIntent(){
    con.getSharedPreferences(con.getPackageName(), Context.MODE_PRIVATE).edit().putInt(Constants.FIRST_ON_CHANGE, 1).commit();


    AlarmManager alm = (AlarmManager) con.getSystemService(Context.ALARM_SERVICE);
    alm.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), new PendingIntentCreator(con).createContentChangedIntent());
    }
}

My idea to solve that problem, was to generate a thread if a saved value ("int first" from SharedPreferences) equals 1. If the observer would get called another time while that thread sleeps, the value would get raised and the thread would sleep again...

Unfortunately the Thread blocks other incoming calls, so that its loop never gets extended. The Logs in my original code, showed me that the SharedPreferences get changed after the Thread is done!

  • Does anybody have a solution for me? (I'm new to threading...)
  • Should I implement another service for this buffering work?
  • General: Is it ok to transfer Context into a ContentObserver?

Thanks in advance! ;)

4

1 回答 1

1

我发现了我犯的错误:

而不是调用buffer.run(),我必须通过buffer.start()实际启动线程,因为调用 .run() 只是执行运行方法的实现......

换句话说,实例化线程的客户端代码不应该在新实例化的线程上调用 run() 方法。因为在线程对象上调用 run() 方法会立即执行run() 方法违背了多线程编程的目的,就并发运行的线程的执行顺序而言,多线程编程本质上是不确定的。

http://www.coderanch.com/t/234040/threads/java/Difference-run-start-method-Thread

于 2013-05-12T08:54:09.537 回答