0

CommonsWare 5.9 イベント バスの例に関して、スレッド セーフの問題/質問があります。

model ArrayList複数のスレッドからアクセスする方法に問題があるように見えます。これが機能する場合、その理由を理解していただければ幸いです。

このコードは、 の宣言、初期化、および入力を実行しますmodel

private static final String[] items= { "lorem", "ipsum", "dolor",
  "sit", "amet", "consectetuer", "adipiscing", "elit", "morbi",
  "vel", "ligula", "vitae", "arcu", "aliquet", "mollis", "etiam",
  "vel", "erat", "placerat", "ante", "porttitor", "sodales",
  "pellentesque", "augue", "purus" };
private ArrayList<String> model=new ArrayList<String>();
private boolean isStarted=false;

@Override
public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);

  setRetainInstance(true);

  if (!isStarted) {
    isStarted=true;
    new LoadWordsThread().start();
  }
}

public ArrayList<String> getModel() {
  return(model);
}

class LoadWordsThread extends Thread {
  @Override
  public void run() {
    for (String item : items) {
      if (!isInterrupted()) {
        model.add(item);
        EventBus.getDefault().post(new WordReadyEvent());
        SystemClock.sleep(400);
      }
    }
  }
}

400 ミリ秒ごとに起動し、エントリを に追加しmodelます。の消費modelは、投稿するのに便利なコードをすぐに持っていないという点で、もう少し複雑です。のどこかに落ちていArrayAdapterます。モデルの消費は、 への呼び出しによってトリガーされArrayAdapter.notifyDataSetChanged()ます。

私が抱えている問題/質問はmodel、(Android UI スレッドではなく) 1 つのスレッドに書き込まれますが、消費は UI スレッドで発生しています。のすべての要素model ArrayListが不変であるため、これは役に立ちますが、それでも私には正しくないように思えます。

このコードが実際に正しい場合、その理由を理解したいと思います。ありがとう、リー。

アップデート:

私の問題はイベントバス部分にあるとは思いません。私はそれを得ると思います。モデルが1つのスレッド(ワーカースレッド、上記のコード)で書き込まれているのに対し、理論的には別のスレッド(UIスレッド)で同時に読み取ることができるというJavaの問題です。モデルには、ある種の同時アクセス制御が必要なようです。同期ブロックまたは並行ArrayList. しかし、モデルの最終的な消費者は、自分のアプリで制御できないコードであり、ArrayAdapterどこかに落ちています。同期を追加できません。がArrayAdapterモデルで初期化されると、ArrayAdapterがそれを所有し、UI スレッドからアクセスします。非 UI スレッドがこの方法でモデルを変更できるかどうかはわかりません。

4

1 に答える 1

1

その通りです。このサンプル アプリには欠陥があります。私は積極的にコードを最小化しようとしましたが、行き過ぎました。

必要な変更は次の 2 つです。

  1. AsyncDemoFragment実際のモデルArrayList<String>ではなく、当時のモデルから初期化されモデルのコピーから作業する必要があります

  2. 起動に加えて、 がモデルのコピーを更新WordReadyEventできるようにするために、in という単語を指定する必要があります。AsyncDemoFragmentnotifyDataSetChanged()

これにより、バックグラウンド スレッドがバックグラウンド スレッドでモデル マスター コピーを更新および維持できるようになり、必要に応じて UI スレッドに変更が通知され、UI スレッドがそのモデルのコピーを取得して UI で使用できるようになります。

他のシナリオでは、共有され、同期されたモデルを持つことは問題外ではありません。この場合、カスタマイズされたアダプター クラスを作成するという kcoppock の提案を除けば、これは非現実的です。これは、この場合、ビュイックでハエをたたくようなものです。

次の本の更新のためにこれを修正するように努めます。

ところで、この章を読んだかどうかを尋ねたのは、レポの調査だけに基づいて質問する人がいるからです。サンプルに付属する資料を読んだかどうかを知りたかったのです。私のコメントは、この章を読めば質問に対する答えが得られるという意味で解釈された可能性がありますが、決してそのつもりはありませんでした。私のお粗末な言い回しが問題を引き起こした場合は、お詫び申し上げます。

問題を指摘してくれてありがとう!

于 2014-07-15T22:49:44.837 に答える