1

私が現在取り組んでいるアプリは、カレンダーまたはイベント データベースの変更に対応する必要があるため、以下のオブザーバーは URI に登録されます。

content://com.android.calendar (古いデバイスの場合: content://calendar)

「問題」は、それぞれのデータが変更されたときに、Observer が (時々) 数回呼び出されることです。.../calendars 用と .../events 用の 2 つの個別の ContentResolver を登録すると、複数回呼び出されることがよくあります。次のコードで達成しようとしているのは、ContentResolver 自体が多くのコードを実行するサービスを呼び出すため、これらの複数の呼び出しをバッファリングすることです。そのため、このサービスは、短期間に多数の ContentObserver 呼び出しに対して 1 回だけ呼び出される必要があります。

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

その問題を解決するための私の考えは、保存された値 (SharedPreferences からの "int first") が 1 に等しい場合にスレッドを生成することでした。そのスレッドがスリープしている間にオブザーバーが別の時間に呼び出されると、値が発生し、スレッドがスリープします。また...

残念ながら、スレッドは他の着信呼び出しをブロックするため、ループが拡張されることはありません。私の元のコードのログは、スレッドが完了した後に SharedPreferences が変更されることを示しました!

  • 誰かが私に解決策を持っていますか? (私はスレッド化が初めてです...)
  • このバッファリング作業のために別のサービスを実装する必要がありますか?
  • 一般: Context を ContentObserver に転送してもよろしいですか?

前もって感謝します!;)

4

1 に答える 1

1

私が犯した間違いを見つけました:

buffer.run()を呼び出す代わりに、 buffer.start()で実際にスレッドを開始する必要がありました。.run()を呼び出すと run-method の実装が実行されるだけだからです...

つまり、スレッドをインスタンス化するクライアント コードは、新しくインスタンス化されたスレッドに run() メソッドを呼び出すべきではありません。スレッド オブジェクトで run() メソッドを呼び出すと、スレッド オブジェクトのステップがすぐに実行されるからです。 run() メソッドは、同時に実行されるスレッドの実行順序に関して本質的に非決定論的な性質を持つマルチスレッド プログラミングの目的そのものを無効にします。

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

于 2013-05-12T08:54:09.537 に答える