编程语言
首页 > 编程语言> > java-难以理解Android应用中的复杂多线程

java-难以理解Android应用中的复杂多线程

作者:互联网

我在理解我的应用程序中的多线程方面遇到了很大的问题,并且因此发现了一个错误.我检查了所有的可能性,但仍然遇到各种错误(有时是意外的).

也许有人可以给我建议,我应该怎么做.

在我的项目中,我使用了两个外部库:

> GraphView-提供用于图形绘制的视图
> EventBus-提供界面,方便应用程序组件之间的通信

至于应用程序,其结构如下:

           MainActivity
            /        \
           /          \
        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<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 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<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);
        }
    }

不幸的是,它都不起作用.

解决方法:

首先,

您后面的示例中的runnable部分只是为了动画化实时数据更新,您可以选择调用appendData()而不创建新的runnable.您需要从主线程调用appendData().

其次,

您可以直接从onEventMainThread函数调用appendData()函数,但正如您所指出的那样,这种方法有时会挂起UI,此行为的一个可能原因是您可能过于频繁地发布事件,而过于频繁地更新UI最终会挂起用户界面.您可以执行以下操作来避免这种情况:

过于频繁地更新用户界面也可能会挂起用户界面,
这是一个解决方案:

在ProcessThread中放入一些逻辑以保存上次发送的事件时间,并在发送新事件之前对其进行比较,如果相差小于1秒,则将其保存以供稍后发送,并且在下一次计算完成后,再次比较时间(如果是)现在大于1秒,而不是按数组发送事件,或者可能仅发送最新事件,因为最新的计算可以代表图形的最新状态,对吗?

希望有帮助!

编辑:(以回应评论1& 2)

我不确定您尝试过的是发布更新的代码会带来更好的主意.但我认为您尝试在onEventMainThread或可运行的PlotsRun中实现时间检查功能,对吗?如果可以的话,恐怕对您没有多大帮助.您需要做的是在ProcessThread中实施此时间检查检查,并且仅在达到阈值时间时才发布新事件.由于以下原因:

1-后端上的EventBus自动创建一个新的可运行对象,并在其中调用onEventMainThread.因此,在ProcessThread中处理时间检查将在内存中生成较少的不需要的可运行对象,从而减少内存消耗.

2-也无需维护队列并生成新的可运行对象,只需更新onEventMainThread中的数据即可.

以下是仅提供概念证明的最低限度代码,您需要根据需要进行更新:

ProcessThread类:

private class ProcessThread extends Thread{
    private static final long TIME_THRESHOLD = 100; //100 MS but can change as desired
    private long lastSentTime = 0;
    private float value = 0f;
    private ReadingsUpdateData updater = new ReadingsUpdateData(values);
    public void run() {
        while(true) {
            if (System.currentTimeMillis() - lastSentTime < TIME_THRESHOLD) {
                try {
                    Thread.sleep(TIME_THRESHOLD - (System.currentTimeMillis() - lastSentTime));
                } catch (InterruptedException e) {}
            }

            value = getRandom();
            updater.setData(value);
            EventBus.getDefault().post(updater);
            lastSentTime = System.currentTimeMillis();
        }
    }
}

onEventMainThread方法:

public void onEventMainThread(ReadingsUpdateData data){
    mSeries1.appendData(new DataPoint(counter, data), true, 100);
    counter++;
}

标签:android-graphview,multithreading,greenrobot-eventbus,java,android
来源: https://codeday.me/bug/20191028/1951376.html