问题描述
From copying and pasting:我设法实现了从 API (ETH/USDT) 获取实时数据的烛台图。
该应用实际上正在读取数据并且正在显示烛台,但我现在的两个问题是:
-
我必须手动刷新活动才能加载数据。我想知道我是否可以实现一个监听器,它可以实时加载数据,而不必每秒手动刷新。
-
我想看到我的烛台形成和收盘,就像元交易者应用程序所做的那样。例如在 1 分钟图上:从一分钟开始,我想看到烛台建筑做一些运动(也许我应该称之为动画?)直到它在 1 分钟处关闭。
我可能在想,如果我能解决 1 号提到的问题,2 号会做出相应的反应,但不确定。
MainActivity.java:看起来像:
private String URL = "https://openapi.dragonex.im/api/v1/market/kline/?symbol_id=......................................";
private final String[] KLINE = {"1m","5m","15m","30m","1h","1d"};
private int[] KL_TYPE = {1,2,3,4,5,6};
private int[] KL_INTERVAL = {1,15,30,60,1440};//单位: Min
private final long M1 = 60 * 1000L;//1 Min的毫秒数
//5日均线、10日均线
private String Kline5_10 = "<font color=#B230ED>MA5:%s</font> <font color=#EFBB40>MA10:%s</font>";
private LoadingDialog loadingDialog;
private Gson gson = new GsonBuilder().create();
private DecimalFormat format4p = new DecimalFormat("0.0000");//格式化数字,保留小数点后4位
private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm",Locale.getDefault());
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);//默认竖屏
initView();
loadData();
}
private void initView() {
ivBack = findViewById(R.id.iv_klBack);
ivOri = findViewById(R.id.iv_klOrientation);
tabLayout = findViewById(R.id.tl_kl);
clHl = findViewById(R.id.cl_klHighlight);
tvOpen = findViewById(R.id.tv_klOpen);
tvClose = findViewById(R.id.tv_klClose);
tvHigh = findViewById(R.id.tv_klHigh);
tvLow = findViewById(R.id.tv_klLow);
tvVol = findViewById(R.id.tv_klVol);
tvLine = findViewById(R.id.tv_klLineInfo);
cc = findViewById(R.id.cc_kl);
bc = findViewById(R.id.bc_kl);
ivBack.setonClickListener(this);
ivOri.setonClickListener(this);
for (int i = 0; i < KLINE.length; i++) {
TextView v = (TextView) LayoutInflater.from(this).inflate(R.layout.item_tab_kline,null);
v.setText(KLINE[i]);
tabLayout.addTab(tabLayout.newTab().setCustomView(v),i == index);
}
tabLayout.addOnTabSelectedListener(this);
initChart();
}
private void initChart() {
int black = getColorById(R.color.black3B);
int gray = getColorById(R.color.gray8B);
int red = getColorById(R.color.redEB);
int green = getColorById(R.color.green4C);
int highlightColor = getColorById(R.color.brown);
float highlightWidth = 0.5F;//高亮线的线宽
float sp8 = sp2px(8);
//K线
cc.setNoDataTextColor(gray);//无数据时提示文字的颜色
cc.setDescription(null);//取消描述
cc.getLegend().setEnabled(false);//取消图例
cc.setDragDecelerationEnabled(false);//不允许甩动惯性滑动 和moveView方法有冲突 设置为false
cc.setMinOffset(0);//设置外边缘偏移量
cc.setExtraBottomOffset(6);//设置底部外边缘偏移量 便于显示X轴
cc.setScaleEnabled(false);//不可缩放
cc.setAutoScaleMinMaxEnabled(true);//自适应最大最小值
cc.setDrawOrder(new CombinedChart.DrawOrder[]{CombinedChart.DrawOrder.CANDLE,CombinedChart.DrawOrder.LINE});
Transformer trans = cc.getTransformer(YAxis.AxisDependency.LEFT);
//自定义X轴标签位置
cc.setXAxisRenderer(new InBoundXAxisRenderer(cc.getViewPortHandler(),cc.getXAxis(),trans,10));
//自定义Y轴标签位置
cc.setRendererLeftYAxis(new InBoundYAxisRenderer(cc.getViewPortHandler(),cc.getAxisLeft(),trans));
//自定义渲染器 重绘高亮
cc.setRenderer(new HighlightCombinedRenderer(cc,cc.getAnimator(),cc.getViewPortHandler(),sp8));
//X轴
XAxis xac = cc.getXAxis();
xac.setPosition(XAxis.XAxisPosition.BottOM);
xac.setGridColor(black);//网格线颜色
xac.setTextColor(gray);//标签颜色
xac.setTextSize(8);//标签字体大小
xac.setAxisLineColor(black);//轴线颜色
xac.disableAxisLineDashedLine();//取消轴线虚线设置
xac.setAvoidFirstLastClipping(true);//避免首尾端标签被裁剪
xac.setLabelCount(2,true);//强制显示2个标签
xac.setValueFormatter(new IAxisValueFormatter() {//转换X轴的数字为文字
@Override
public String getFormattedValue(float value,AxisBase axis) {
int v = (int) value;
if (!xValues.containsKey(v) && xValues.containsKey(v - 1)) {
v = v - 1;
}
String x = xValues.get(v);
return TextUtils.isEmpty(x) ? "" : x;
}
});
//左Y轴
YAxis yac = cc.getAxisLeft();
yac.setPosition(YAxis.YAxisLabelPosition.INSIDE_CHART);//标签显示在内侧
yac.setGridColor(black);
yac.setTextColor(gray);
yac.setTextSize(8);
yac.setLabelCount(5,true);
yac.enableGridDashedLine(5,0);//横向网格线设置为虚线
yac.setValueFormatter(new IAxisValueFormatter() {
@Override
public String getFormattedValue(float value,AxisBase axis) {//只显示部分标签
int index = getIndexY(value,axis.getAxisMinimum(),axis.getAxisMaximum());
return index == 0 || index == 2 ? format4p.format(value) : "";//不显示的标签不能返回null
}
});
//右Y轴
cc.getAxisRight().setEnabled(false);
//蜡烛图
candleSet = new CandleDataSet(new ArrayList<CandleEntry>(),"Kline");
candleSet.setAxisDependency(YAxis.AxisDependency.LEFT);
candleSet.setDrawHorizontalHighlightIndicator(false);
candleSet.setHighlightlinewidth(highlightWidth);
candleSet.setHighLightColor(highlightColor);
candleSet.setShadowWidth(0.7f);
candleSet.setIncreasingColor(red);//上涨为红色
candleSet.setIncreasingPaintStyle(Paint.Style.FILL);
candleSet.setDecreasingColor(green);//下跌为绿色
candleSet.setDecreasingPaintStyle(Paint.Style.stroke);
candleSet.setNeutralColor(red);
candleSet.setShadowColorSameAsCandle(true);
candleSet.setDrawValues(false);
candleSet.setHighlightEnabled(false);
//均线
lineset5 = new LineDataSet(new ArrayList<Entry>(),"MA5");
lineset5.setAxisDependency(YAxis.AxisDependency.LEFT);
lineset5.setColor(getColorById(R.color.purple));
lineset5.setDrawCircles(false);
lineset5.setDrawValues(false);
lineset5.setHighlightEnabled(false);
lineset10 = new LineDataSet(new ArrayList<Entry>(),"MA10");
lineset10.setAxisDependency(YAxis.AxisDependency.LEFT);
lineset10.setColor(getColorById(R.color.yellow));
lineset10.setDrawCircles(false);
lineset10.setDrawValues(false);
lineset10.setHighlightEnabled(false);
//分时线
linesetMin = new LineDataSet(new ArrayList<Entry>(),"Minutes");
linesetMin.setAxisDependency(YAxis.AxisDependency.LEFT);
linesetMin.setColor(Color.WHITE);
linesetMin.setDrawCircles(false);
linesetMin.setDrawValues(false);
linesetMin.setDrawFilled(true);
linesetMin.setHighlightEnabled(false);
linesetMin.setFillColor(gray);
linesetMin.setFillAlpha(60);
//成交量
bc.setNoDataTextColor(gray);
bc.setDescription(null);
bc.getLegend().setEnabled(false);
bc.setDragDecelerationEnabled(false);//不允许甩动惯性滑动
bc.setMinOffset(0);//设置外边缘偏移量
bc.setScaleEnabled(false);//不可缩放
bc.setAutoScaleMinMaxEnabled(true);//自适应最大最小值
//自定义Y轴标签位置
bc.setRendererLeftYAxis(new InBoundYAxisRenderer(bc.getViewPortHandler(),bc.getAxisLeft(),bc.getTransformer(YAxis.AxisDependency.LEFT)));
//设置渲染器控制颜色、偏移,以及高亮
bc.setRenderer(new OffsetBarRenderer(bc,bc.getAnimator(),bc.getViewPortHandler(),barOffset)
.setHighlightWidthSize(highlightWidth,sp8));
bc.getXAxis().setEnabled(false);
YAxis yab = bc.getAxisLeft();
yab.setPosition(YAxis.YAxisLabelPosition.INSIDE_CHART);//标签显示在内侧
yab.setDrawAxisLine(false);
yab.setGridColor(black);
yab.setTextColor(gray);
yab.setTextSize(8);
yab.setLabelCount(2,true);
yab.setAxisMinimum(0);
yab.setValueFormatter(new IAxisValueFormatter() {
@Override
public String getFormattedValue(float value,AxisBase axis) {
return value == 0 ? "" : value + "";
}
});
bc.getAxisRight().setEnabled(false);
barSet = new BarDataSet(new ArrayList<BarEntry>(),"VOL");
barSet.setHighLightColor(highlightColor);
barSet.setColors(red,green);
barSet.setDrawValues(false);
barSet.setHighlightEnabled(false);
ccGesture = new CoupleChartGestureListener(this,cc,bc) {//设置成全局变量,后续要用到
@Override
public void chartDoubleTapped(MotionEvent me) {
doubleTapped();
}
};
cc.setonChartGestureListener(ccGesture);//设置手势联动监听
bcGesture = new CoupleChartGestureListener(this,bc,cc) {
@Override
public void chartDoubleTapped(MotionEvent me) {
doubleTapped();
}
};
bc.setonChartGestureListener(bcGesture);
cc.setonChartValueSelectedListener(new CoupleChartValueSelectedListener(this,bc));//设置高亮联动监听
bc.setonChartValueSelectedListener(new CoupleChartValueSelectedListener(this,cc));
cc.setonTouchListener(new ChartFingerTouchListener(cc,this));//手指长按滑动高亮
bc.setonTouchListener(new ChartFingerTouchListener(bc,this));
}
/**
* 计算value是当前Y轴的第几个
*/
private int getIndexY(float value,float min,float max) {
float piece = (max - min) / 4;
return Math.round((value - min) / piece);
}
protected void loadData() {
clearChart();
toLeft = true;
getData("0");
}
private void clearChart() {
if (dataList == null) {
dataList = new ArrayList<>();
} else {
dataList.clear();
}
if (xValues == null) {
xValues = new HashMap<>();
} else {
xValues.clear();
}
cc.setNoDataText("加载中...");
cc.clear();
bc.setNoDataText("加载中...");
bc.clear();
}
private void getData(String time) {
String url = String.format(URL,time,toLeft ? "2" : "1",KL_TYPE[index]);
OkHttpUtil.getJSON(url,this);
}
@Override
public void onTabSelected(TabLayout.Tab tab) {
index = tab.getPosition();
loadData();
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
onTabSelected(tab);
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {}
@Override
public void onResponse(String url,String json) {
Log.e("loge","Kline: " + json);
KlineEntity kl = gson.fromJson(json,KlineEntity.class);
if (kl.isOk()) {
int size = xValues.size();
List<List<String>> lists = kl.getData().getLists();
if (lists.size() <= 0) {
dismissLoading();
return;
}
if (lists.size() == 1) {
long time = Long.parseLong(lists.get(0).get(6)) * 1000;
String x = sdf.format(new Date(time));
if (!xValues.containsValue(x)) {
handleData(lists,size);
}
} else {
handleData(lists,size);
}
}
dismissLoading();
}
/**
* size是指追加数据之前,已有的数据个数
*/
private void handleData(List<List<String>> lists,int size) {
if (toLeft) {
dataList.addAll(0,lists);//添加到左侧
} else {
dataList.addAll(lists);
}
configData();
if (xValues.size() > 0) {
int x = xValues.size() - (toLeft ? size : 0);
//如果设置了惯性甩动 move方法将会无效
if (!toLeft && size > 0) {
cc.moveViewToAnimated(x,YAxis.AxisDependency.LEFT,200);
bc.moveViewToAnimated(x + barOffset,200);
} else {
cc.moveViewToX(x);
bc.moveViewToX(x + barOffset);
}
cc.notifyDataSetChanged();
bc.notifyDataSetChanged();
}
}
private void configData() {
if (dataList.size() == 0) {
cc.setNoDataText("暂无相关数据");
cc.clear();
bc.setNoDataText("暂无相关数据");
bc.clear();
} else {
if (combinedData == null) {
combinedData = new CombinedData();
}
xValues.clear();
List<CandleEntry> candleValues = candleSet.getValues();
candleValues.clear();
List<Entry> ma5Values = lineset5.getValues();
ma5Values.clear();
List<Entry> ma10Values = lineset10.getValues();
ma10Values.clear();
List<Entry> minValues = linesetMin.getValues();
minValues.clear();
List<BarEntry> barValues = barSet.getValues();
barValues.clear();
for (int i = 0; i < dataList.size(); i++) {
List<String> k = dataList.get(i);
Date d = new Date(Long.parseLong(k.get(6)) * 1000);//毫秒
String x = sdf.format(d);//显示日期
if (xValues.containsValue(x)) {//x重复
dataList.remove(i);
i--;
} else {
xValues.put(i,x);
float open = Float.parseFloat(k.get(4));
float close = Float.parseFloat(k.get(1));
candleValues.add(new CandleEntry(i,Float.parseFloat(k.get(2)),Float.parseFloat(k.get(3)),open,close,x));
minValues.add(new Entry(i,x));
barValues.add(new BarEntry(i,Float.parseFloat(k.get(8)),close >= open ? 0 : 1));
if (i >=4) {
ma5Values.add(new Entry(i,getMA(i,5)));
if (i >= 9) {
ma10Values.add(new Entry(i,10)));
}
}
}
}
candleSet.setValues(candleValues);
lineset5.setValues(ma5Values);
lineset10.setValues(ma10Values);
linesetMin.setValues(minValues);
if (tabLayout.getSelectedTabPosition() == 0) {
combinedData.removeDataSet(candleSet);//分时图时移除蜡烛图
combinedData.setData(new LineData(linesetMin));
} else {
combinedData.setData(new CandleData(candleSet));
combinedData.setData(new LineData(lineset5,lineset10));
}
cc.setData(combinedData);
float xMax = xValues.size() - 0.5F;//默认X轴最大值是 xValues.size() - 1
cc.getXAxis().setAxisMaximum(xMax);//使最后一个显示完整
barSet.setValues(barValues);
BarData barData = new BarData(barSet);
barData.setBarWidth(1 - candleSet.getBarSpace() * 2);//使Candle和Bar宽度一致
bc.setData(barData);
bc.getXAxis().setAxisMaximum(xMax + barOffset);//保持边缘对齐
cc.setVisiblexrange(range,range);//设置显示X轴个数的上下限,竖屏固定52个
bc.setVisiblexrange(range,range);
}
}
private void dismissLoading() {
if (loadingDialog != null) {
loadingDialog.dismiss();
}
}
@Override
public void onFailure(String url,String error) {
dismissLoading();
cc.setNoDataText("加载失败 点击标签重试");
cc.invalidate();
bc.setNoDataText("加载失败");
bc.invalidate();
}
private float getMA(int index,int maxCount) {
int count = 1;
float sum = Float.parseFloat(dataList.get(index).get(1));
while (count < maxCount) {
if (--index < 0) {
break;
}
sum += Float.parseFloat(dataList.get(index).get(1));
count++;
}
return sum / count;
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.iv_klBack://后退键
onBackpressed();
break;
case R.id.iv_klOrientation://切换横竖屏
highVisX = cc.getHighestVisibleX();
setRequestedOrientation(isPort() ? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE :
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
break;
}
}
/**
* 滑动到边缘后加载更多
*/
@Override
public void edgeLoad(float x,boolean left) {
int v = (int) x;
if (!left && !xValues.containsKey(v) && xValues.containsKey(v - 1)) {
v = v - 1;
}
String time = xValues.get(v);
if (!TextUtils.isEmpty(time)) {
try {
long t = sdf.parse(time).getTime();
if (!left) {//向右获取数据时判断时间间隔
long interval = KL_INTERVAL[tabLayout.getSelectedTabPosition()] * M1;
if (System.currentTimeMillis() - t < interval) {//不会有新数据
return;
}
}
loadingDialog = LoadingDialog.newInstance();
loadingDialog.show(this);
toLeft = left;
getData(t * 1000000L + "");
} catch (ParseException e) {
e.printstacktrace();
}
}
}
/**
* 双击图表
*/
private void doubleTapped() {
if (isPort()) {
highVisX = cc.getHighestVisibleX();
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
}
@Override
public void valueSelected(Entry e) {
float x = e.getX();
clHl.setVisibility(View.VISIBLE);
CandleEntry candle = candleSet.getEntryForXValue(x,0);
if (candle != null) {
tvOpen.setText(format4p.format(candle.getopen()));
tvOpen.setSelected(candle.getopen() < candle.getClose());
tvClose.setText(format4p.format(candle.getClose()));
tvClose.setSelected(candle.getopen() >= candle.getClose());
tvHigh.setText(format4p.format(candle.getHigh()));
tvHigh.setSelected(false);
tvLow.setText(format4p.format(candle.getLow()));
tvLow.setSelected(true);
}
BarEntry bar = barSet.getEntryForXValue(x,0);
if (bar != null) {
tvVol.setText(format4p.format(bar.getY()));
}
if (tabLayout.getSelectedTabPosition() != 0) {
Entry line5 = lineset5.getEntryForXValue(x,0);
Entry line10 = lineset10.getEntryForXValue(x,0);
if (line5 != null && line10 != null) {
tvLine.setVisibility(View.VISIBLE);
String line = String.format(Kline5_10,format4p.format(line5.getY()),format4p.format(line10.getY()));
tvLine.setText(fromHtml(line));
}
}
}
@Override
public void nothingSelected() {
clHl.setVisibility(View.GONE);
tvLine.setVisibility(View.GONE);
}
@Override
public void enableHighlight() {
if (!barSet.isHighlightEnabled()) {
candleSet.setHighlightEnabled(true);
linesetMin.setHighlightEnabled(true);
barSet.setHighlightEnabled(true);
}
}
@Override
public void disableHighlight() {
if (barSet.isHighlightEnabled()) {
candleSet.setHighlightEnabled(false);
linesetMin.setHighlightEnabled(false);
barSet.setHighlightEnabled(false);
if (ccGesture != null) {
ccGesture.setHighlight(true);
}
if (bcGesture != null) {
bcGesture.setHighlight(true);
}
}
}
@Override
public void onBackpressed() {
if (isPort()) {
super.onBackpressed();
} else {
highVisX = cc.getHighestVisibleX();
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
}
@Override
protected void onRestart() {
super.onRestart();
float rightX = cc.getHighestVisibleX();
if (rightX == cc.getXChartMax()) {//停留在最右端
edgeLoad(rightX,false);
}
}
/**
* 横竖屏切换
*/
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
setContentView(R.layout.activity_main);
initView();
range = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT ? 52 : 86;//竖屏显示52个 横屏显示86个
configData();
if (xValues.size() > 0) {
cc.post(new Runnable() {
@Override
public void run() {
float x = highVisX - range;
cc.moveViewToX(x);
bc.moveViewToX(x + barOffset);
cc.notifyDataSetChanged();
bc.notifyDataSetChanged();
}
});
}
}
/**
* 当前是否是竖屏
*/
public boolean isPort() {
return getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
}
public int getColorById(int colorId) {
return ContextCompat.getColor(this,colorId);
}
public int sp2px(float spValue) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,spValue,getResources().getdisplayMetrics());
}
public static Spanned fromHtml(String source) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return Html.fromHtml(source,Html.FROM_HTML_MODE_LEGACY);
} else {
return Html.fromHtml(source);
}
}
}
嗯,肯定会从这些代码助手中获得概念并检测可以在何处实施解决方案。
如果你需要看我有的其他课程,请告知。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)