アプリケーションのマルチスレッドを理解するのに大きな問題があり、そのためにバグが見つかりました。私はすべての可能性を考えていることを確認しましたが、それでもさまざまな (時には予期しない) エラーが発生しています。
たぶん、ここにいる誰かが私にアドバイスをくれるでしょう、私が何をすべきか。
私のプロジェクトでは、2 つの外部ライブラリを使用しています。
アプリに関しては、次のような構造になっています。
MainActivity
/ \
/ \
Thread Fragment
(ProcessThread) (GraphFragment)
アイデアは、ProcessThread
データを計算し、一定の値のストリームをGraphFragment
throughtに提供することですEventBus
。で必要なものがありGraphFragment
ます。Series
GraphView
例に従ってリアルタイムでグラフを更新するには、新しいグラフを作成する必要があるため、次のRunnable
ように作成しました。
private class PlotsRun implements Runnable{
@Override
public void run() {
mSeries1.appendData(new DataPoint(counter, getRandom()), true, 100);
counter++;
mHandler.post(this);
}
}
フラグメントのメソッドから開始すると、onResume()
すべてが魅力的に機能します。
残念ながら、私が言及したように、私は別のスレッドからの外部データを使用しています。それを取得するには、(ドキュメントGraphFragment
によると)メソッドを使用しています。onEventMainThread()
そして、ここで何をしようとも、データを渡してPlotsRun
オブジェクトのグラフを更新することはできません。これまでのところ、私は試しました:
- using
Queue
- add value inonEventMainThread
と get inPlotsRun
。runnable は、メソッドがキューを更新できるよりも高速に読み取りを行うことが判明しました。 - さまざまなバッファの作成 - 結果は とまったく同じ
Queue
です。 mSeries1.appendData(new DataPoint(counter, getRandom()), true, 100);
から直接呼び出すonEventMainThread
- ある時点でフリーズします。onEvent()
ランナブル内にメソッドを作成し、そこから呼び出します-UIをmHandler.post()
ブロックしていて、更新がスナップショットのように見えます。synchronized()
ブロックの有無にかかわらず、言及されているすべてを使用します。
私が理解するのが非常に難しいのは、(ある時点で)正しく機能しているこのランナブルです。
公式の Android ブログで述べられているように、非 UI スレッドから UI を更新することはできません。これが、内部で別のスレッドを使用できない理由ですGraphFragment
。しかし、ランナブルをチェックすると、メインスレッド (UI) で実行されています。これが、無限を作成できず、while loop
代わりに呼び出す必要がある理由mHandler.post(this)
です。
それでも、onEventMainThread
メソッドよりも高速である (より頻繁に呼び出される) ため、別のスレッドのように動作します。
からのデータを使用してグラフ (またはどこを見るべきか) を更新できるようにするにはどうすればよいProcessThread
ですか?
EDIT1:
@Matt Wolfe リクエストに答えると、この問題のコードの最も重要な部分であると思われるものを含め、必要なすべての変数がどのように宣言されているかを示しています。これは非常に単純化された例です:
MainActivity
:
private ProcessThread testThread = new ProcessThread();
@Override
protected void onResume() {
super.onResume();
testThread.start();
}
private class ProcessThread extends Thread{
private float value = 0f;
private ReadingsUpdateData updater = new ReadingsUpdateData(values);
public void run() {
while(true) {
value = getRandom();
updater.setData(value);
EventBus.getDefault().post(updater);
}
}
}
GraphFragment
:
private LineGraphSeries<DataPoint> mSeries1;
long counter = 0;
private Queue<ReadingsUpdateData> queue;
@Override
public void onResume() {
super.onResume();
mTimer2.run();
}
public void onEventMainThread(ReadingsUpdateData data){
synchronized(queue){
queue.add(data);
}
}
private class PlotsRun implements Runnable{
@Override
public void run() {
if (queue.size()>0) {
mSeries1.appendData(new DataPoint(counter, queue.poll()), true, 100);
counter++;
}
mHandler.post(this);
}
}
この高速読み取りの問題のため、保護のために実行可能な if が追加されています。しかし、常に何かがあるはずなので、ここにあるべきではありません (少なくとも私はそれを期待しています)。
追加するもう1つのこと-単純Log.d
でカウントする変数を内部onEventMainThread
に配置すると、その値が正しく更新および表示されましたが、残念ながらlogcatはメインUIではありません.
EDIT2:
これは主に @MattWolfeコメントへの応答です
mHandler は、GrapgFragment で宣言および作成された単なる変数です。
private final Handler mHandler = new Handler();
private Runnable mTimer2;
はい、そうです、私はmHandler.post()
遅滞なく使用しています。多少の遅延を使用して、違いがあるかどうかを確認します。
前に触れていなかったのは、ProcessThread
が他のフラグメントにもデータを提供しているということです。互いに干渉したり、リソースを共有したりしないことを心配しないでください。これが私が使用している理由ですEventBus
。
EDIT3:
GraphFragment
これは、別のスレッドとrunOnMainThread
メソッドを使用して別のアイデアとして使用したコードです。
private MyThread thread = new MyThread();
private class MyThread extends Thread {
Queue<ReadingsUpdateData> inputList;
ReadingsUpdateData msg;
public MyThread() {
inputList = new LinkedList<>();
}
public void run() {
while(true) {
try{
msg = inputList.poll();
} catch(NoSuchElementException nse){
continue;
}
if (msg == null) {
continue;
}
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
mSeries1.appendData(new DataPoint(counter, getRandom()), true, 100);
counter++;
}
});
}
}
public void onEvent(ReadingsUpdateData data){
inputList.add(data);
}
}
残念ながら、どちらも機能していません。