ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

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

2019-10-28 09:14:16  阅读:275  来源: 互联网

标签:android-graphview multithreading greenrobot-eventbus 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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有