我在理解我的应用程序中的多线程方面遇到了很大的问题,并且因此发现了一个错误.我检查了所有的可能性,但仍然遇到各种错误(有时是意外的).
也许有人可以给我建议,我应该怎么做.
在我的项目中,我使用了两个外部库:
> GraphView-提供用于图形绘制的视图
> EventBus-提供界面,方便应用程序组件之间的通信
至于应用程序,其结构如下:
MainActivity
/ \n / \n Thread Fragment
(ProcessThread) (GraphFragment)
这个想法是ProcessThread计算数据并通过EventBus向GraphFragment提供恒定的值流.在GraphFragment中,我有一个GraphView所需的系列.
要根据example实时更新图形,我需要制作一个新的Runnable,所以我做了一个:
private class PlotsRun implements Runnable{
@Override
public void run() {
mSeries1.appendData(new DataPoint(counter, getRandom()), true, 100);
counter++;
mHandler.post(this);
}
}
当我从fragment的onResume()方法启动它时,一切都像一个魅力一样工作.
不幸的是,正如我提到的那样,我正在使用另一个线程的外部数据.为了在GraphFragment中获取它,我正在使用(根据documentation)onEventMainThread()方法.
在这里,无论我做什么,我都无法传递数据来更新PlotsRun对象中的图形.到目前为止,我已经尝试过:
>使用队列-在onEventMainThread中添加值并获取PlotsRun.事实证明,runnable的读取速度快于方法更新队列的速度.
>创建各种缓冲区-结果与Queue完全相同.
>调用mSeries1.appendData(new DataPoint(counter,getRandom()),true,100);直接从onEventMainThread-在某个时候它会冻结.
>在我的可运行对象内部创建onEvent()方法并从那里调用mHandler.post()-它阻止了UI,并且更新看起来像快照.
>使用提到的所有内容(带或不带sync()块).
对于我来说,很难理解的是这个可运行的(正确的)运行状态.
由于官方Android博客上的版本为said,因此您无法通过非UI线程更新UI.这就是为什么我不能在GraphFragment中使用另一个线程的原因.但是,当我检查了可运行对象时,它正在主线程(UI)上运行.这就是为什么我不能在那里创建无限的while循环,而不得不调用mHandler.post(this)的原因.
而且它仍然像另一个线程一样工作,因为它比onEventMainThread方法更快(更频繁地调用).
我该怎么做才能使用ProcessThread中的数据更新图形(或应显示的位置)?
编辑1:
回答@Matt Wolfe的请求时,我包括我认为是此问题代码中最重要的部分,其中所有必需的变量均显示了它们的声明方式.这是非常简化的示例:
主要活动:
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 mSeries1;
long counter = 0;
private Queue 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 in runnable来进行保护.但这不应该在这里,因为总应该有东西(至少我希望如此).
要添加的另一件事-当我将简单的Log.d放在onEventMainThread中并对其进行计数时,它正在正确更新并正确显示其值,但是不幸的是logcat不是主UI.
编辑2:
这主要是对@MattWolfe comment的回复
mHandler只是在GrapgFragment中声明和创建的变量:
private final Handler mHandler = new Handler();
private Runnable mTimer2;
是的,没错,我正在使用mHandler.post(),没有任何延迟.我会尝试使用一些延迟来看看是否有任何区别.
我之前没有提到的是,ProcessThread还向其他片段提供数据-不用担心它们不会互相干扰或共享任何资源.这就是为什么我使用EventBus.
编辑3:
这是我在GraphFragment和runOnMainThread方法中与另一个线程一起使用的另一个代码的代码:
private MyThread thread = new MyThread();
private class MyThread extends Thread {
Queue 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);
}
}
不幸的是,它都不起作用.