Android使用MPandroidChart折线双轴多线段实时更新与问题解决

Android使用MPandroidChart折线双轴多线段实时更新与问题解决

记录一次在android开发使用图表框架MpandroidChart时遇到绘制双折线图后,复刻官方demo代码后报错的解决。由于不支持markdown,懒得再去改了。

环境:

版本

JavaSDK11

Gradle7.04

android studio2020.3.1

MPandroidChart3.1.0

问题详情

根据MPandroidChart的demo,我复刻了单轴的实时更新(后文会实现),并且通过独立封装后完美重现。在阅读多轴源码后发现,只需要 开启右边的Y轴,然后向图表实例中加入新的LineDataSet对象,即可创建新折线,而通过getDataSetByIndex(Index)来获取多线段中指定的一条来进行操作,每条互不影响,只是在同一个View里罢了。因为要实时更新,就需要想view提交更新的数据,并且为了有更好的效果,我会在数据更新以后将视图移动到最新的一条。于是问题就出现了,在调用moveViewToX()后就会卡死整个主程序,哪怕我是用的子线程。此时问题就很明显了,就是moveViewToX()错误调用的问题,但我还傻乎乎的没注意,看了报错说超过最大数什么的。。。。好像也告诉我了出什么问题了。。。。于是我成功的避开,然后不断阅读源码,查找资料。。。。最后,终于。。放弃了。本来就想将就一下,虽然能够更新数据,但是最新的数据需要手动划过去,并且还要刷新整个view,就导致下一次数据刷新的时候,就要重新划过去。。。

问题解决


阅读源码,可以发现,移动到最新一条数据,是通过指定X轴的具体值来进行移动的。为什么是float类型?我定义的X轴,明明是时间格式展示的呀。其实那只是改了X轴显示的标签值罢了,真正的X,Y值都是通过float来进行存储的(看源码猜的)。再看看我错误的代码。。。

chart.getData().notifyDataChanged();//提交表内数据更新

chart.notifyDataSetChanged();//提交数据更新,在View没有大的改动,只更新数据就只使用这个就可以了。

//更新视图,当然都跟新View了,数据也是会更新的,但相当于重启,就会导致上面说到的更新以后要重新再划过去最新的目录。

//chart.invalidate();

//移动到最新的数据,数据更新以后就会在最右边显示出来。

chart.moveViewToX(chart.getData().getEntryCount());

这是getEntryCount()的源码


到这里,明白原理的其实已经知道问题所在了。单折线之所以用上面的方法没有问题,是因为mValues.size()返回的数值就只有一根折线的x轴的数值。通过日志输出,是可以发现单折线有几个数据,就返回的是几。在使用双曲线后,再输出,发现竟然变成双倍了!X轴明明是第4个值,却输出了8。这才导致了报错,也是为什么报错说超过最大数的原因。既然大了两倍,那chart.moveViewToX(chart.getData().getEntryCount()/2);不就好了。。。。按道理来说是的,但是结果依然是报错的。正确的解决思路是,既然使用的是多折线, 多折线数据X轴数值都是一致的,那么直接取其中其中一个不就好了

chart.moveViewToX(((LineDataSet)chart.getData().getDataSetByIndex(0)).getEntryCount());

这样,就可以正常运行且不报错了,能够通过线程实时更新数据了,也不会更新View,只会跟新数据。好的,思路讲完。下面上测试代码。

测试代码实现

导入依赖

这个可以直接搜索GitHub的,然后下面有怎么在线导入,但有可能导入了但实际没成功导入(无法使用),就需要使用离线的jar包导入。


界面-activity_main

<?xmlversion="1.0" encoding="utf-8"?>

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"

xmlns:app="http://schemas.android.com/apk/res-auto"

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical"

tools:context=".MainActivity">

<com.github.mikephil.charting.charts.LineChart

android:id="@+id/chart1"

android:layout_width="match_parent"

android:layout_height="200dp"

android:layout_margin="10dp"

android:background="@drawable/background"/>

<com.github.mikephil.charting.charts.LineChart

android:id="@+id/chart2"

android:layout_width="match_parent"

android:layout_height="200dp"

android:layout_margin="10dp"

android:background="@drawable/background"/>

<LinearLayout

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_marginTop="10dp">

<Button

android:id="@+id/addOne"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_margin="10dp"

android:text="添加1个"/>

<Button

android:id="@+id/addAll"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_margin="10dp"

android:text="自动"/>

</LinearLayout>

</LinearLayout>

样式-background.XML

<?xmlversion="1.0" encoding="utf-8"?>

<shapexmlns:android="http://schemas.android.com/apk/res/android">

<cornersandroid:radius="10dp"/>

<paddingandroid:bottom="10dp"

android:top="10dp"

android:left="10dp"

android:right="10dp"/>

<solidandroid:color="@color/teal_200"/>

</shape>

MainActivity

publicclassMainActivityextendsAppCompatActivity{

privateLineChartchart,chart1;

privateCreationChartsetChart1,setChart2;

privateThreadthread;

@Override

protectedvoidonCreate(BundlesavedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

initView();

   }

/**

* 初始化控件

*/

privatevoidinitView() {

chart=findViewById(R.id.chart1);

chart1=findViewById(R.id.chart2);

setChart1=newCreationChart(chart);

setChart2=newCreationChart(chart1);

setChart1.init();

setChart2.init();

//单折线添加一个随机数据

findViewById(R.id.addOne).setOnClickListener(newView.OnClickListener() {

@Override

publicvoidonClick(Viewview) {

setChart1.AddData((float) (Math.random()*40)+30f);

           }

       });

//双折线 添加2个

findViewById(R.id.addTwo).setOnClickListener(newView.OnClickListener() {

@Override

publicvoidonClick(Viewview) {

setChart2.AddData((float) (Math.random()*40)+30f, (float) (Math.random()*40)+30f);

           }

       });

//启动线程

findViewById(R.id.addAll).setOnClickListener(newView.OnClickListener() {

@Override

publicvoidonClick(Viewview) {

AddDataThread();

           }

       });

   }

/**

* 循环添加数据   每100毫秒添加一次

*/

privatevoidAddDataThread() {

if(thread!=null)

thread.interrupt();

thread=newThread(newRunnable() {

@Override

publicvoidrun() {

for(inti=0;i<100;i++) {

try{

runOnUiThread(newRunnable() {

@Override

publicvoidrun() {

setChart1.AddData((float) (Math.random()*40)+30f);

setChart2.AddData((float) (Math.random()*40)+30f, (float) (Math.random()*40)+30f);

                           }

                       });

Thread.sleep(100);

}catch(InterruptedExceptione) {

Log.e("绘制",e.toString());

                   }

               }

           }

       });

thread.start();

   }

}

封装的图表类 - CreationChart

/**

* 简单封装一下

*/

publicclassCreationChart{

privateLineChartchart;

privateList<String>dateTime=newArrayList<>();

publicCreationChart(LineChartchart) {

this.chart=chart;

   }

/***

* 初始化

*/

publicvoidinit() {

// 开启文本描述

chart.getDescription().setEnabled(false);

chart.setDragDecelerationFrictionCoef(0.9f);

// 开启触摸手势

chart.setTouchEnabled(true);

// 允许缩放和拖动

chart.setDragEnabled(true);//拖动

chart.setScaleEnabled(false);//缩放

chart.setDrawGridBackground(false);

chart.setHighlightPerDragEnabled(true);

// 如果禁用,可以分别在x轴和y轴上进行缩放

chart.setPinchZoom(true);

// 设置一个替代背景

//chart.setBackgroundColor(Color.rgb(255, 255, 255));

LineDatadata=newLineData();

data.setValueTextColor(Color.WHITE);

XAxisxl=chart.getXAxis();

xl.setPosition(XAxis.XAxisPosition.BOTTOM_INSIDE);//标签位置

xl.setTextColor(Color.WHITE);// x值为白色

xl.setDrawGridLines(false);

xl.setLabelCount(4);//分为几个

xl.setAxisLineColor(Color.rgb(248,248,255));//x线的颜色

xl.setAvoidFirstLastClipping(true);

xl.setEnabled(true);

//左边的Y轴数据

YAxisleftAxis=chart.getAxisLeft();

leftAxis.setTextColor(Color.WHITE);

//leftAxis.setAxisMaximum(200f); //最大条目

leftAxis.setAxisMinimum(0f);//最小条目

leftAxis.setLabelCount(6);//设置最大分为几格

leftAxis.setDrawGridLines(true);

leftAxis.setAxisLineColor(Color.rgb(248,248,255));

//右边的Y轴数据

YAxisrightAxis=chart.getAxisRight();

rightAxis.setEnabled(false);

   }

/**

* 添加数据

*

* @param data

*/

publicvoidAddData(float...data) {

//获取当前时间  格式为“HH:mm:ss”

SimpleDateFormatformatter=newSimpleDateFormat("HH:mm:ss");

Stringdate=formatter.format(newDate());

dateTime.add(date);

LineDataSetnewDataSet,newDataSet2;

chart.getXAxis().setValueFormatter(newIndexAxisValueFormatter(dateTime));

switch(data.length) {

// 单折线

case1:

if(chart.getData()!=null&&

chart.getData().getDataSetCount()>0) {

newDataSet=(LineDataSet)chart.getData().getDataSetByIndex(0);

newDataSet.addEntry(newEntry(newDataSet.getEntryCount(),data[0]));

}else{

newDataSet=CreateSet(LineChartType.CHART1);

LineDatalineData1=newLineData(newDataSet);

chart.setData(lineData1);

               }

break;

// 多折线

case2:

if(chart.getData()!=null&&

chart.getData().getDataSetCount()>0) {

newDataSet=(LineDataSet)chart.getData().getDataSetByIndex(0);

newDataSet2=(LineDataSet)chart.getData().getDataSetByIndex(1);

newDataSet.addEntry(newEntry(newDataSet.getEntryCount(),data[0]));

newDataSet2.addEntry(newEntry(newDataSet2.getEntryCount(),data[1]));

}else{

newDataSet=CreateSet(LineChartType.CHART1);

newDataSet2=CreateSet(LineChartType.CHART2);

LineDatalineData1=newLineData(newDataSet,newDataSet2);

chart.setData(lineData1);

               }

break;

       }

chart.getData().notifyDataChanged();

//提交数据更新

chart.notifyDataSetChanged();

//设置X最大可见条目

chart.setVisibleXRange(2,10);

//移动到最新数据

if(chart.getData().getDataSetByIndex(0).getEntryCount()>0)

chart.moveViewToX(chart.getData().getDataSetByIndex(0).getEntryCount());

   }

/**

* 设置数据格式

*

* @param type chart1 或者 chart2

* @return LineDataSet

*/

privateLineDataSetCreateSet(LineChartTypetype) {

LineDataSetset=null;

switch(type) {

caseCHART1:

set=newLineDataSet(null,"测试1");

set.setColor(ColorTemplate.getHoloBlue());//折线颜色

set.setFillAlpha(65);//填充透明度

set.setFillColor(ColorTemplate.getHoloBlue());

break;

caseCHART2:

set=newLineDataSet(null,"测试2");

set.setColor(Color.YELLOW);//折线颜色

set.setFillAlpha(65);//填充透明度

set.setFillColor(ColorTemplate.colorWithAlpha(Color.YELLOW,200));

break;

       }

set.setAxisDependency(YAxis.AxisDependency.LEFT);

set.setLineWidth(1f);

set.setCircleRadius(4f);

set.setHighLightColor(Color.rgb(124,117,117));//高亮颜色

set.setDrawValues(true);//绘画值

set.setDrawCircles(false);//绘画圆圈

set.setDrawFilled(true);//充满底部

set.setMode(LineDataSet.Mode.CUBIC_BEZIER);// 类型,折线还是曲线还是 平线

returnset;

   }

/**

* 枚举类型

*/

privateenumLineChartType{

CHART1,CHART2

   }

}

效果展示


注:转载请标明出处

CSDN:Android使用MPandroidChart折线双轴多线段实时更新与问题解决_Dream's的博客-CSDN博客

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,546评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,224评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,911评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,737评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,753评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,598评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,338评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,249评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,696评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,888评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,013评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,731评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,348评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,929评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,048评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,203评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,960评论 2 355