2

いくつかのタスクを実行するスレッドを開始するために、broadcastreceiverを介して定期的に呼び出される非スティッキーサービスがあります。スレッドの実行中、進行中の通知には、進行状況情報と、ステータスページを表示するためのボタンが表示されます。

このステータスページには、現在処理されているアイテムのリストが表示されます。このリストは、スレッドとこのアクティビティの両方で使用される静的ArrayListです。ステータスアクティビティが開始されると、nullチェックがあります。

if(Global.statusItems == null)
{
    Global.statusItems = new ArrayList<StatusPageItem>();
}

スレッドはまだ実行中であり、ArrayListに完全にアクセスできますが、Statusアクティビティが発生するとすぐに、nullであるかのようにArrayListが再作成されます。

これまでのところ、ObjectOutputStreamを使用してリストを保存し、ステータスページの開始時にリロードしない限り、問題を解決することはできませんでした。私が使用できるよりエレガントなソリューションはありますか?

よろしく、クイント。

4

2 に答える 2

1

2行のコード(nullテストと新しいリストの作成)がアトミックであり、割り当てが他のスレッドから見えることを確認する必要があります。

これを行う最も簡単な方法は、そのコードを同期することです。

synchronized(Global.class) {
    if(Global.statusItems == null) {
        Global.statusItems = new ArrayList<StatusPageItem>();
    }
}

ただし、あるスレッドからリストを読み取り、別のスレッドからリストに書き込む必要がある場合は、追加/削除/反復時に同期を追加して、両方のトレッドに同じリストが表示されるようにする必要があります。そうでない場合は、書き込みスレッドがリストに項目を追加しているのに、読み取りスレッドがそれを認識していない可能性があります。

最も簡単な方法は、リストのスレッドセーフな実装を使用することです。

synchronized(Global.class) {
    if(Global.statusItems == null) {
        Global.statusItems = new CopyOnWriteArrayList<StatusPageItem>();
    }
}

メモリ/オブジェクトの作成が懸念される場合(CopyOnWriteArrayListはその観点からはあまり効率的ではありません)、代わりに同期コレクションを使用することもできます。

synchronized(Global.class) {
    if(Global.statusItems == null) {
        Global.statusItems = Collections.synchronizedList(new ArrayList<StatusPageItem>());
    }
}

その場合、反復するときにコレクションをロックするようにしてください。

synchronized(Global.statusItems) {
    for (StatusPageItem item : Global.statusItems) {

    }
}
于 2012-08-29T11:04:21.953 に答える
1

サービスが別のプロセスで実行されている可能性はありますか?

于 2012-08-29T11:12:51.387 に答える