我在理解应用程序中的多线程方面遇到了很大的问题,因此发现了一个错误。我已经检查过我认为所有的可能性,但仍然遇到各种(有时是意外的)错误。
也许这里有人可以建议我,我应该做什么。
在我的项目中,我使用两个外部库:
-
图形视图 https://github.com/jjoe64/GraphView- 提供图形绘制视图
-
EventBus https://github.com/greenrobot/EventBus- 提供应用程序组件之间轻松通信的接口
至于应用程序,它的结构如下:
MainActivity
/ \
/ \
Thread Fragment
(ProcessThread) (GraphFragment)
这个想法是ProcessThread
计算数据并提供恒定的值流GraphFragment
贯穿EventBus
. In GraphFragment
我有一个Series
要求由GraphView
.
根据数据实时更新图表example http://www.android-graphview.org/documentation/realtime-updates我需要制作一个新的Runnable
所以我做了一个:
private class PlotsRun implements Runnable{
@Override
public void run() {
mSeries1.appendData(new DataPoint(counter, getRandom()), true, 100);
counter++;
mHandler.post(this);
}
}
当我从片段开始时onResume()
方法一切都很顺利。
不幸的是,正如我所提到的,我正在使用来自另一个线程的外部数据。为了把它放进去GraphFragment
我正在使用(根据文档 https://github.com/greenrobot/EventBus/blob/master/HOWTO.md) onEventMainThread()
method.
在这里,无论我做什么,我都无法传递数据来更新我的图表PlotsRun
目的。到目前为止我已经尝试过:
- using
Queue
- 增加价值onEventMainThread
并进入PlotsRun
。事实证明,可运行的读取速度比方法更新队列的速度快。
- 创建各种缓冲区 - 结果与
Queue
.
- calling
mSeries1.appendData(new DataPoint(counter, getRandom()), true, 100);
直接来自onEventMainThread
- 在某些时候它会冻结。
- 创造
onEvent()
我的可运行对象中的方法并从那里调用mHandler.post()
- 它阻塞了 UI 并且更新看起来像快照。
- 使用或不使用提到的所有内容
synchronized()
block.
对我来说很难理解的是这个可运行的程序(在某些时候)可以正常工作。
因为它是said http://android-developers.blogspot.com/2009/05/painless-threading.html在官方 Android 博客上,您无法从非 UI 线程更新 UI。这就是为什么我不能在里面使用另一个线程GraphFragment
。但是当我检查我的可运行程序时,它正在主线程(UI)上运行。这就是为什么我无法创造无限while loop
那里必须打电话mHandler.post(this)
.
而且它的行为仍然像另一个线程,因为它更快(调用更频繁)onEventMainThread
method.
我该怎么做才能使用来自的数据更新我的图表(或我应该查看的位置)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);
}
}
由于存在快速读取问题,因此添加了 runnable 中的 if 来进行保护。但它不应该在这里,因为应该总是有一些东西(至少我期望如此)。
还要补充一件事 - 当我简单地说Log.d
并计算里面的变量onEventMainThread
它正在更新并正确显示它的值,但不幸的是 logcat 不是主 UI。
EDIT2:
这主要是对@MattWolfe的回应comment https://stackoverflow.com/questions/30403513/difficulty-in-understanding-complex-multi-threading-in-android-app?noredirect=1#comment48897550_30403513
mHandler 只是在 GrapgFragment 中声明和创建的变量:
private final Handler mHandler = new Handler();
private Runnable mTimer2;
是的,没错,我正在使用mHandler.post()
没有任何延迟。我会尝试使用一些延迟来查看是否有任何差异。
我之前没有提到的是ProcessThread
还向其他片段提供数据 - 不用担心它们不会互相干扰或共享任何资源。这就是我使用的原因EventBus
.
EDIT3:
这是我在另一个线程中用作另一个想法的代码GraphFragment
and runOnMainThread
method:
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);
}
}
不幸的是,它也不起作用。