如何解决使用 Firebase 数据更新 mpandroidchart 时出现问题
我的问题总结是我正在从 Firebase 数据库中检索实时数据,并且我正在尝试将模拟数据输入到我的数据库中。每次我加载一个新值时,我的图表都不会反映我想要的方式。我的代码和支持图片如下。提前感谢您的帮助!
图表基本上不会从 Firebase 中绘制我输入数据的新值并刷新图表,它只是绘制了一条奇怪的线,我不知道它来自哪里。
Homepage.java 包含我的图表
package com.example.myapplication;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.components.IMarker;
import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet;
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
import com.github.mikephil.charting.utils.Utils;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.Query;
import com.google.firebase.database.ValueEventListener;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.Month;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Date;
public class Homepage extends AppCompatActivity{
private LineChart chart;
private FirebaseUser user;
private DatabaseReference reference;
private String userID;
private TextView tvTitle;
long reference_timestamp;
ArrayList<Long> acTime = new ArrayList<>();
ArrayList<Long> newAcTime = new ArrayList<>();
ArrayList<Long> acValues = new ArrayList<>();
ArrayList<Entry> result = new ArrayList<>();
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_homepage);
tvTitle = findViewById(R.id.tvTitle);
chart = findViewById(R.id.petChart);
chart.setDragEnabled(true);
chart.setScaleEnabled(true);
LocalDateTime dt = LocalDateTime.of(2021,Month.FEBRUARY,20,0);
LocalDateTime dt2 = LocalDateTime.of(2021,23,59,59);
long startTime = dt.toEpochSecond(ZoneOffset.UTC);
System.out.println("startTime:" + startTime + " " + dt);
long endTime = dt2.toEpochSecond(ZoneOffset.UTC);
System.out.println("endTime:" + endTime + " " + dt2);
user = FirebaseAuth.getInstance().getCurrentUser();
userID = user.getUid();
reference = FirebaseDatabase.getInstance().getReference("Users/" + userID + "/Data");
Query query = reference.orderByKey().startAt(String.valueOf(startTime)).endAt(String.valueOf(endTime));
System.out.println("Printing query:" + query);
System.out.println("Printing reference:" + reference);
query.addValueEventListener(new ValueEventListener() {
boolean wasCalled = false;
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
System.out.println("wasCalled: " + wasCalled);
if (!wasCalled)
{
System.out.println("getting accelerometer values");
for (DataSnapshot valueSnapshot : dataSnapshot.getChildren())
{
acValues.add(Long.parseLong((valueSnapshot.getValue(String.class))));
acTime.add(Long.parseLong((valueSnapshot.getKey())));
}
long temp_time;
System.out.println("acTimeRef:" + acTime.get(0));
for (int i = 0; i < acTime.size(); i++)
{
System.out.println(acValues.get(i));
reference_timestamp = acTime.get(0);
temp_time = acTime.get(i) - reference_timestamp;
newAcTime.add(temp_time);
result.add(new Entry(newAcTime.get(i),acValues.get(i)));
}
Date date = new Date(acTime.get(0)*1000);
DateFormat format = new SimpleDateFormat("MMMM d,yyyy");
String formatted = format.format(date);
tvTitle.setText("Accelerometer Data for " + formatted);
chart.setBackgroundColor(Color.WHITE);
chart.getDescription().setEnabled(false);
chart.setTouchEnabled(true);
chart.setDragEnabled(true);
chart.setScaleEnabled(true);
chart.setDrawGridBackground(false);
chart.setHighlightPerDragEnabled(true);
chart.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
@Override
public void onGlobalLayout() {
chart.getViewTreeObserver().removeOnGlobalLayoutListener(this);
int offset = (chart.getHeight() - chart.getWidth()) / 100;
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) chart.getLayoutParams();
layoutParams.width = chart.getHeight();
layoutParams.height = chart.getWidth();
chart.setLayoutParams(layoutParams);
chart.setTranslationX(offset);
chart.setTranslationY(offset);
IMarker marker = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
marker = new YourMarkerView(getApplicationContext(),R.layout.marker,reference_timestamp);
}
chart.setMarker(marker);
chart.setExtraOffsets(10,10,10);
Legend l = chart.getLegend();
l.setForm(Legend.LegendForm.LINE);
l.setVerticalAlignment(Legend.LegendVerticalAlignment.TOP);
l.setHorizontalAlignment(Legend.LegendHorizontalAlignment.RIGHT);
l.setorientation(Legend.LegendOrientation.HORIZONTAL);
l.setDrawInside(false);
XAxis xAxis = chart.getXAxis();
xAxis.setPosition(XAxis.XAxisPosition.BottOM);
xAxis.setTextSize(16f);
xAxis.setValueFormatter(new XAxisValueFormatter(reference_timestamp));
xAxis.setDrawGridLines(false);
xAxis.setCenteraxisLabels(true);
xAxis.setLabelCount(5);
xAxis.setCenteraxisLabels(true);
YAxis leftAxis = chart.getAxisLeft();
leftAxis.setPosition(YAxis.YAxisLabelPosition.OUTSIDE_CHART);
leftAxis.setDrawGridLines(false);
leftAxis.setGranularityEnabled(true);
leftAxis.setLabelCount(5);
leftAxis.setTextSize(16f);
leftAxis.setTextColor(Color.BLACK);
YAxis rightAxis = chart.getAxisRight();
rightAxis.setEnabled(false);
}
});
}
LineDataSet set1;
if (chart.getData() != null &&
chart.getData().getDataSetCount() > 0) {
set1 = (LineDataSet) chart.getData().getDataSetByIndex(0);
set1.notifyDataSetChanged();
set1.setValues(result);
System.out.println("set1: " + set1);
chart.animateX(1000);
chart.getData().notifyDataChanged();
chart.notifyDataSetChanged();
}
else
{
set1 = new LineDataSet(result,"Accelerometer Data");
set1.setDrawValues(false);
set1.setAxisDependency(YAxis.AxisDependency.LEFT);
set1.setColor(Color.rgb(57,57,57));
set1.setlinewidth(3f);
set1.setDrawCircles(true);
set1.setCircleRadius(3.5f);
set1.setCircleColor(Color.rgb(112,141,255));
if (Utils.getSDKInt() >= 18) {
// fill drawable only supported on api level 18 and above
Drawable drawable = ContextCompat.getDrawable(Homepage.this,R.drawable.blue_gradient);
set1.setFillDrawable(drawable);
} else {
set1.setFillColor(Color.BLACK);
}
set1.setDrawFilled(true);
ArrayList<ILineDataSet> dataSets = new ArrayList<>();
dataSets.add(set1);
LineData data2 = new LineData(dataSets);
chart.setData(data2);
chart.notifyDataSetChanged();
chart.invalidate();
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
throw databaseError.toException();
}
});
}
}
YourMarkerView.java(创建这个类是为了让用户点击标记以在图表上显示更详细的时间)
package com.example.myapplication;
import android.content.Context;
import android.graphics.Canvas;
import android.os.Build;
import android.widget.TextView;
import androidx.annotation.RequiresApi;
import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.components.MarkerView;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.utils.MPPointF;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
@RequiresApi(api = Build.VERSION_CODES.O)
public class YourMarkerView extends MarkerView {
private TextView tvContent;
long reference_timestamp;
private LocalDateTime mDate;
private DateTimeFormatter mDataFormat;
private LineChart chart;
private Context mContext;
public YourMarkerView(Context context,int layoutResource,long reference_timestamp) {
super(context,layoutResource);
// find your layout components
chart = findViewById(R.id.petChart);
tvContent = (TextView) findViewById(R.id.tvContent);
this.mContext = context;
this.reference_timestamp = reference_timestamp;
this.mDataFormat = DateTimeFormatter.ofPattern("h:mm:ss a");
}
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public void refreshContent(Entry e,Highlight highlight) {
long currentTimestamp = (long)e.getX() + reference_timestamp;
System.out.println("currentTimestamp:" + currentTimestamp);
tvContent.setText(e.getY() + " m/s^2 at " + getTimedate(currentTimestamp)); // set the entry-value as the display text
// this will perform necessary layouting
super.refreshContent(e,highlight);
}
@Override
public void draw(Canvas canvas,float posx,float posy)
{
// Check marker position and update offsets.
System.out.println("Posx:" + posx);
int w = getWidth();
int h = getHeight();
if((getResources().getdisplayMetrics().widthPixels-posx-w) < w) {
posx -= w;
}
System.out.println("Posx:" + posx);
if (getResources().getdisplayMetrics().heightPixels-posy-h < h)
{
posy-=h;
}
if (posx < 0)
{
posx+=w;
}
canvas.translate(posx,posy);
draw(canvas);
canvas.translate(-posx,-posy);
}
private MPPointF mOffset;
@Override
public MPPointF getoffset() {
if (mOffset == null) {
mOffset = new MPPointF(-(getWidth() / 2),-getHeight());
}
return mOffset;
}
@RequiresApi(api = Build.VERSION_CODES.O)
private String getTimedate(long timestamp) {
try {
Instant instant = Instant.ofEpochSecond(timestamp);
LocalDateTime dt =
instant.atZone(ZoneId.systemDefault()).toLocalDateTime();
// System.out.println("Marker: " + dt);
String formatted = mDataFormat.format(dt);
return formatted;
} catch (Exception ex) {
return "xx";
}
}
}
XAxisValueFormatter.java(格式化x轴以使其易于理解)
package com.example.myapplication;
import android.os.Build;
import androidx.annotation.RequiresApi;
import com.github.mikephil.charting.components.AxisBase;
import com.github.mikephil.charting.formatter.ValueFormatter;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
public class XAxisValueFormatter extends ValueFormatter {
long reference_timestamp;
public XAxisValueFormatter(long reference_timestamp)
{
this.reference_timestamp = reference_timestamp;
}
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public String getFormattedValue(float value) {
long epoch = (((long)value + reference_timestamp));
// Show time in local version
Instant instant = Instant.ofEpochSecond(epoch);
LocalDateTime dt =
instant.atZone(ZoneId.systemDefault()).toLocalDateTime();
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("h:mm:ss a");
String formatted = dtf.format(dt);
return formatted;
}
@RequiresApi(api = Build.VERSION_CODES.O)
public String getAxisLabel(float value,AxisBase axis) {
return getFormattedValue(value);
}
}
What I want the graph to look like when new values are being inputted
What the graph looks like instead
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。