我们在安卓开发中,有时会用到统计图表的功能,而曲线绘制是其中比较典型的一种,一般是利用给定的坐标点集和安卓自带的绘图模块进行绘制,直接得到的是一张完整的静态的曲线图。但有时,我们需要动态绘制一些曲线图,就像我们打开电脑的任务管理器,里面有一个cpu使用记录的动态变化的带网格的曲线图,对于这一类的曲线绘制,安卓sdk自带的绘图模块貌似就不那么好用了。
上述就是android开发分享Android实现动态曲线绘制的全部内容,如果对大家有所用处且需要了解更多关于Android学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
在这里,我就利用handler+timer机制和第三方开发包achartengine实现动态绘制安卓手机充放电曲线的应用。
1、下载第三方开发包achartengine,也就是jar包,可以在网上找到下载源,我下载的是achartengine-1.1.0.jar;
2、在创建的应用工程文件中引入该jar包,以eclipse为例方法是:在包资源管理器目录中右键单击已创建的项目名称——>构建路径——>配置构建路径——>java构建路径——>库——>外部jar,然后找到achartengine包的存放路径,找到achartengine-1.1.0.jar文件,点击打开即完成了该包的引用,这时会在项目目录下出现一个名为引用的库文件,里面就是我们刚才引入的jar包。
3、接下来就可以按正常步骤开发该应用了,需要注意的是:需要在主类中引入jar中绘图需要的库文件,如下:
import org.achartengine.chartfactory; import org.achartengine.graphicalview; import org.achartengine.chart.pointstyle; import org.achartengine.model.xymultipleseriesdataset; import org.achartengine.model.xyseries; import org.achartengine.renderer.xymultipleseriesrenderer; import org.achartengine.renderer.xyseriesrenderer;
同时需要在androidmanifest.xml文件中加上语句:
<application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <activity android:name="org.achartengine.graphicalactivity" />
4、接下来需要定义一些绘图的变量和样式:
private xyseries series; private xymultipleseriesdataset mdataset; private graphicalview chart; private xymultipleseriesrenderer renderer; private context context, context1; private int addx = -1, addy; int[] xv = new int[720];// x轴数组元素个数 int[] yv = new int[720];// y轴数组元素个数 context = getapplicationcontext(); // 这里获得main界面上的布局,下面会把图表画在这个布局里面 linearlayout layout = (linearlayout) findviewbyid(r.id.linearlayout1); // 这个类用来放置曲线上的所有点,是一个点的集合,根据这些点画出曲线 series = new xyseries(title); // 创建一个数据集的实例,这个数据集将被用来创建图表 mdataset = new xymultipleseriesdataset(); // 将点集添加到这个数据集中 mdataset.addseries(series); // 以下都是曲线的样式和属性等等的设置,renderer相当于一个用来给图表做渲染的句柄 int color = color.green; pointstyle style = pointstyle.circle; renderer = buildrenderer(color, style, true); // 设置好图表的样式(横轴时间分钟值,纵轴电压毫伏值) setchartsettings(renderer, "x", "y", 0, 240, 3400, 4400, color.white,color.white); // 生成图表 chart = chartfactory.getlinechartview(context, mdataset, renderer); // 将图表添加到布局中去 layout.addview(chart, new layoutparams(layoutparams.fill_parent, layoutparams.wrap_content)); protected xymultipleseriesrenderer buildrenderer(int color,pointstyle style, boolean fill)// 配置绘图属性 { xymultipleseriesrenderer renderer = new xymultipleseriesrenderer(); // 设置图表中曲线本身的样式,包括颜色、点的大小以及线的粗细等 xyseriesrenderer r = new xyseriesrenderer(); r.setcolor(color); r.setpointstyle(style); r.setfillpoints(fill); r.setlinewidth((float) 1);// 线粗尺寸 renderer.addseriesrenderer(r); return renderer; } protected void setchartsettings(xymultipleseriesrenderer renderer, string xtitle, string ytitle, double xmin, double xmax, double ymin, double ymax, int axescolor, int labelscolor) { // 有关对图表的渲染可参看api文档 renderer.setcharttitle(title); renderer.setxtitle(xtitle); renderer.setytitle(ytitle); renderer.setxaxismin(xmin); renderer.setxaxismax(xmax); renderer.setyaxismin(ymin); renderer.setyaxismax(ymax); renderer.setaxescolor(axescolor); renderer.setlabelscolor(labelscolor); renderer.setshowgrid(true); renderer.setgridcolor(color.green);// 曲线颜色 renderer.setxlabels(20); renderer.setylabels(10); renderer.setcharttitle("时间/电压变化曲线图");// 图表名称 renderer.setxtitle("时间(min)");// 横坐标名称 renderer.setytitle("电压(mv)");// 纵坐标名称 renderer.setylabelsalign(align.right); renderer.setpointsize((float) 1.5);// 设置点的大小 renderer.setshowlegend(false); renderer.setpanenabled(true, false);// 设置滑动,这边是横向可以滑动,纵向不可滑动 renderer.setzoomenabled(true, false);// 设置缩放,横向可以,纵向不可以 // renderer.setzoomlimits(new double[] { 0, 720, 3400, 4400 });//设置缩放的范围 // renderer.setpanlimits(new double[] { -0.5, 720, 3400, 4400 // });//设置拉动的范围 }
5、动态绘制的实现:动态绘制主要需要实现两方面的内容,一是更新绘图的方法、二是动态绘图时间任务的定义。
1)更新绘图方法:
private void updatechart()// 更新绘图方法</strong> { // 设置好下一个需要增加的节点 addx = (int) (addx + 1); addy = batteryv; // 移除数据集中旧的点集 mdataset.removeseries(series); // 判断当前点集中到底有多少点,因为屏幕总共只能容纳240个,所以当点数超过240时,长度永远是240 int length = series.getitemcount(); if (length > 720) { length = 720; } // 将旧的点集中x和y的数值取出来放入backup中,并且将x的值加1,造成曲线向右平移的效果 for (int i = 0; i < length; i++) { xv[i] = (int) series.getx(i); yv[i] = (int) series.gety(i); } // 点集先清空,为了做成新的点集而准备 series.clear(); // 将新产生的点首先加入到点集中,然后在循环体中将坐标变换后的一系列点都重新加入到点集中 // 这里可以试验一下把顺序颠倒过来是什么效果,即先运行循环体,再添加新产生的点 series.add(addx, addy); for (int k = 0; k < length; k++) { series.add(xv[k], yv[k]); } // 在数据集中添加新的点集 mdataset.addseries(series); // 视图更新,没有这一步,曲线不会呈现动态 // 如果在非ui主线程中,需要调用postinvalidate(),具体参考api chart.invalidate(); }
2)时间任务定义:
handler = new handler() { @override public void handlemessage(message msg) { // 刷新图表 updatechart();// 电压变化曲线刷新 updatechart1();// 电量变化曲线刷新 super.handlemessage(msg); } }; task = new timertask()// 刷新绘图计时任务配置 { @override public void run() { message message = new message(); message.what = 1; handler.sendmessage(message); } }; timer.schedule(task, 0, 60000);// 以一分钟为时间间隔运行
再发一下完整的代码:
主类:
package com.cfzz.vcd; import java.io.fileoutputstream; import java.text.simpledateformat; import java.util.date; import java.util.locale; import java.util.timer; import java.util.timertask; import org.achartengine.chartfactory; import org.achartengine.graphicalview; import org.achartengine.chart.pointstyle; import org.achartengine.model.xymultipleseriesdataset; import org.achartengine.model.xyseries; import org.achartengine.renderer.xymultipleseriesrenderer; import org.achartengine.renderer.xyseriesrenderer; //import com.cfzz.vqcd.r; //import com.cfzz.wy.r; import android.app.activity; import android.content.broadcastreceiver; import android.content.context; import android.content.intent; import android.content.intentfilter; import android.graphics.bitmap; import android.graphics.color; import android.graphics.paint.align; import android.os.batterymanager; import android.os.bundle; import android.os.handler; import android.os.message; import android.os.powermanager; import android.view.keyevent; import android.view.view; import android.view.viewgroup.layoutparams; import android.view.windowmanager; import android.widget.button; import android.widget.linearlayout; import android.widget.textview; import android.widget.toast; import android.view.view.onclicklistener; public class voltagechangedraw extends activity { // protected static final activity activity = null; private powermanager.wakelock wl; private timer timer = new timer(); private long mexittime = 0; private timertask task, task1; private handler handler; private string title = "signal strength"; private xyseries series, series1; private xymultipleseriesdataset mdataset, mdataset1; private graphicalview chart, chart1; private xymultipleseriesrenderer renderer, renderer1; private context context, context1; private int addx = -1, addy; private int addx1 = -1, addy1; private button button; int[] xv = new int[720];// x轴数组元素个数 int[] yv = new int[720];// y轴数组元素个数 int[] xv1 = new int[720];// x轴数组元素个数 int[] yv1 = new int[720];// y轴数组元素个数 public textview tv; // screenshot screenshot = new screenshot(); private int batteryn; // 目前电量 private int batteryv; // 电池电压 // private double batteryt; //电池温度 private string batterystatus; // 电池状态 private string batterytemp; // 电池使用情况 /** called when the activity is first created. */ @override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); getwindow().setflags(windowmanager.layoutparams.flag_keep_screen_on, windowmanager.layoutparams.flag_keep_screen_on); setcontentview(r.layout.main); this.button = (button) this.findviewbyid(r.id.my_button);// 截图按键定义 // 截图按键监听 this.button.setonclicklistener(new onclicklistener() { public void onclick(view v) { simpledateformat sdf = new simpledateformat( "yyyy-mm-dd_hh-mm-ss", locale.us);// 日期格式名定义 string fname = "/sdcard/" + sdf.format(new date()) + ".png";// 存储路径及文件名定义 view view = v.getrootview(); view.setdrawingcacheenabled(true); view.builddrawingcache(); bitmap bitmap = view.getdrawingcache(); if (bitmap != null) { system.out.println("bitmap got!"); try { fileoutputstream out = new fileoutputstream(fname); bitmap.compress(bitmap.compressformat.png, 100, out);// 图片格式及质量输出 system.out.println("file" + fname + "output done."); } catch (exception e) { e.printstacktrace(); } } else { system.out.println("bitmap is null!"); } } }); // mytag可以随便写,可以写应用名称等 powermanager pm = (powermanager) getsystemservice(context.power_service); // 换成powermanager.screen_dim_wake_lock会变暗) powermanager.wakelock wl = pm.newwakelock( powermanager.screen_bright_wake_lock, "mytest"); wl.acquire();// 开启屏幕常亮 tv = (textview) findviewbyid(r.id.tv);// 电池信息打印控件定义 // 注册一个系统 broadcastreceiver,作为访问电池计量之用,这个不能直接在androidmanifest.xml中注册 registerreceiver(mbatinforeceiver, new intentfilter( intent.action_battery_changed)); context = getapplicationcontext(); context1 = getapplicationcontext();// 图2 // 这里获得main界面上的布局,下面会把图表画在这个布局里面 linearlayout layout = (linearlayout) findviewbyid(r.id.linearlayout1); // 这个类用来放置曲线上的所有点,是一个点的集合,根据这些点画出曲线 series = new xyseries(title); series1 = new xyseries(title);// 图2 // 创建一个数据集的实例,这个数据集将被用来创建图表 mdataset = new xymultipleseriesdataset(); mdataset1 = new xymultipleseriesdataset(); // 将点集添加到这个数据集中 mdataset.addseries(series); mdataset1.addseries(series1);// 图2 // 以下都是曲线的样式和属性等等的设置,renderer相当于一个用来给图表做渲染的句柄 int color = color.green; int color1 = color.red; pointstyle style = pointstyle.circle; renderer = buildrenderer(color, style, true); renderer1 = buildrenderer(color1, style, true);// 图2 // 设置好图表的样式(横轴时间分钟值,纵轴电压毫伏值) setchartsettings(renderer, "x", "y", 0, 240, 3400, 4400, color.white, color.white); setchart1settings(renderer1, "x", "y", 0, 240, 0, 100, color.white, color.white); // 生成图表 chart = chartfactory.getlinechartview(context, mdataset, renderer); chart1 = chartfactory.getlinechartview(context1, mdataset1, renderer1);// 图2 </span><span style="font-size:12px;">// 将图表添加到布局中去,此处的纵向尺寸设置存在一些问题,当两张图都设置<span style="font-family: arial, helvetica, sans-serif;">wrap_content</span>时,在实际界面上只显示第一张图,在这里可根据手 // </span><span style="font-family: arial, helvetica, sans-serif;">机屏幕的大小设置具</span><span style="font-family: arial, helvetica, sans-serif;">体的数值(像素点个数),可以保证两张图都能显示在屏幕上 </span><span style="font-size:14px;"> layout.addview(chart, new layoutparams(layoutparams.fill_parent,layoutparams.wrap_content)); layout.addview(chart1, new layoutparams(layoutparams.fill_parent,layoutparams.wrap_content)); // layout.addview(chart, new layoutparams(layoutparams.fill_parent, // 400));//525 // layout.addview(chart1, new layoutparams(layoutparams.fill_parent, // 400));//图2 525 // 这里的handler实例将配合下面的timer实例,完成定时更新图表的功能 handler = new handler() { @override public void handlemessage(message msg) { // 刷新图表 updatechart();// 电压变化曲线刷新 updatechart1();// 电量变化曲线刷新 super.handlemessage(msg); } }; task = new timertask()// 刷新绘图计时任务配置 { @override public void run() { message message = new message(); message.what = 1; handler.sendmessage(message); } }; timer.schedule(task, 0, 60000);// 以一分钟为时间间隔运行 task1 = new timertask()// 保存绘图计时任务配置 { @override public void run() { if (batterystatus == "充满电" || (batterystatus == "放电状态" && batteryn == 1))// 充/放电完成条件设定 { button.callonclick();// 保存曲线图按键触发 timer.cancel(); // 停止计时功能 } } }; timer.schedule(task1, 0, 10000);// 以十秒钟为时间间隔运行 } @override public void ondestroy() // 结束程序声明 { button.callonclick();// 保存曲线图按键触发 // 当结束程序时关掉timer timer.cancel(); // wl.release(); // wl = null; super.ondestroy(); } protected xymultipleseriesrenderer buildrenderer(int color, pointstyle style, boolean fill)// 配置绘图属性 { xymultipleseriesrenderer renderer = new xymultipleseriesrenderer(); // 设置图表中曲线本身的样式,包括颜色、点的大小以及线的粗细等 xyseriesrenderer r = new xyseriesrenderer(); r.setcolor(color); r.setpointstyle(style); r.setfillpoints(fill); r.setlinewidth((float) 1);// 线粗尺寸 renderer.addseriesrenderer(r); return renderer; } // 图2 protected xymultipleseriesrenderer buildrenderer1(int color1, pointstyle style, boolean fill)// 配置绘图属性 { xymultipleseriesrenderer renderer1 = new xymultipleseriesrenderer();// 图2 // 设置图表中曲线本身的样式,包括颜色、点的大小以及线的粗细等 xyseriesrenderer r = new xyseriesrenderer(); r.setcolor(color1); r.setpointstyle(style); r.setfillpoints(fill); r.setlinewidth((float) 1);// 线粗尺寸 renderer1.addseriesrenderer(r); return renderer1; } protected void setchartsettings(xymultipleseriesrenderer renderer, string xtitle, string ytitle, double xmin, double xmax, double ymin, double ymax, int axescolor, int labelscolor) { // 有关对图表的渲染可参看api文档 renderer.setcharttitle(title); renderer.setxtitle(xtitle); renderer.setytitle(ytitle); renderer.setxaxismin(xmin); renderer.setxaxismax(xmax); renderer.setyaxismin(ymin); renderer.setyaxismax(ymax); renderer.setaxescolor(axescolor); renderer.setlabelscolor(labelscolor); renderer.setshowgrid(true); renderer.setgridcolor(color.green);// 曲线颜色 renderer.setxlabels(20); renderer.setylabels(10); renderer.setcharttitle("时间/电压变化曲线图");// 图表名称 renderer.setxtitle("时间(min)");// 横坐标名称 renderer.setytitle("电压(mv)");// 纵坐标名称 renderer.setylabelsalign(align.right); renderer.setpointsize((float) 1.5);// 设置点的大小 renderer.setshowlegend(false); renderer.setpanenabled(true, false);// 设置滑动,这边是横向可以滑动,纵向不可滑动 renderer.setzoomenabled(true, false);// 设置缩放,横向可以,纵向不可以 // renderer.setzoomlimits(new double[] { 0, 720, 3400, 4400 });//设置缩放的范围 // renderer.setpanlimits(new double[] { -0.5, 720, 3400, 4400 // });//设置拉动的范围 } // 图2 protected void setchart1settings(xymultipleseriesrenderer renderer1, string xtitle, string ytitle, double xmin, double xmax, double ymin, double ymax, int axescolor, int labelscolor) { // 有关对图表的渲染可参看api文档 renderer1.setcharttitle(title); renderer1.setxtitle(xtitle); renderer1.setytitle(ytitle); renderer1.setxaxismin(xmin); renderer1.setxaxismax(xmax); renderer1.setyaxismin(ymin); renderer1.setyaxismax(ymax); renderer1.setaxescolor(axescolor); renderer1.setlabelscolor(labelscolor); renderer1.setshowgrid(true); renderer1.setgridcolor(color.green);// 曲线颜色 renderer1.setxlabels(20); renderer1.setylabels(10); renderer1.setcharttitle("时间/电量变化曲线图");// 图表名称 renderer1.setxtitle("时间(min)");// 横坐标名称 renderer1.setytitle("电量(%)");// 纵坐标名称 renderer1.setylabelsalign(align.right); renderer1.setpointsize((float) 1.5);// 设置点的大小 renderer1.setshowlegend(false); renderer1.setpanenabled(true, false);// 设置滑动,这边是横向可以滑动,纵向不可滑动 renderer1.setzoomenabled(true, false);// 设置缩放,横向可以,纵向不可以 // renderer1.setzoomlimits(new double[] { 0, 720, 0, 100 });//设置缩放的范围 // renderer1.setpanlimits(new double[] { -0.5, 720, 0, 100 });//设置拉动的范围 } private void updatechart()// 更新绘图方法 { // 设置好下一个需要增加的节点 addx = (int) (addx + 1); addy = batteryv; // 移除数据集中旧的点集 mdataset.removeseries(series); // 判断当前点集中到底有多少点,因为屏幕总共只能容纳240个,所以当点数超过240时,长度永远是240 int length = series.getitemcount(); if (length > 720) { length = 720; } // 将旧的点集中x和y的数值取出来放入backup中,并且将x的值加1,造成曲线向右平移的效果 for (int i = 0; i < length; i++) { xv[i] = (int) series.getx(i); yv[i] = (int) series.gety(i); } // 点集先清空,为了做成新的点集而准备 series.clear(); // 将新产生的点首先加入到点集中,然后在循环体中将坐标变换后的一系列点都重新加入到点集中 // 这里可以试验一下把顺序颠倒过来是什么效果,即先运行循环体,再添加新产生的点 series.add(addx, addy); for (int k = 0; k < length; k++) { series.add(xv[k], yv[k]); } // 在数据集中添加新的点集 mdataset.addseries(series); // 视图更新,没有这一步,曲线不会呈现动态 // 如果在非ui主线程中,需要调用postinvalidate(),具体参考api chart.invalidate(); } // 图2 private void updatechart1()// 更新绘图方法 { // 设置好下一个需要增加的节点 addx1 = (int) (addx1 + 1); addy1 = batteryn; // 移除数据集中旧的点集 mdataset1.removeseries(series1); // 判断当前点集中到底有多少点,因为屏幕总共只能容纳240个,所以当点数超过240时,长度永远是240 int length1 = series1.getitemcount(); if (length1 > 720) { length1 = 720; } // 将旧的点集中x和y的数值取出来放入backup中,并且将x的值加1,造成曲线向右平移的效果 for (int j = 0; j < length1; j++) { xv1[j] = (int) series1.getx(j); yv1[j] = (int) series1.gety(j); } // 点集先清空,为了做成新的点集而准备 series1.clear(); // 将新产生的点首先加入到点集中,然后在循环体中将坐标变换后的一系列点都重新加入到点集中 // 这里可以试验一下把顺序颠倒过来是什么效果,即先运行循环体,再添加新产生的点 series1.add(addx1, addy1); for (int l = 0; l < length1; l++) { series1.add(xv1[l], yv1[l]); } // 在数据集中添加新的点集 mdataset1.addseries(series1); // 视图更新,没有这一步,曲线不会呈现动态 // 如果在非ui主线程中,需要调用postinvalidate(),具体参考api chart1.invalidate(); } /* 创建电池状态广播接收器 */ public broadcastreceiver mbatinforeceiver = new broadcastreceiver() { public void onreceive(context context, intent intent) { string action = intent.getaction(); // 如果捕捉到的action是action_battery_changed, 就运行onbatteryinforeceiver() if (intent.action_battery_changed.equals(action)) { batteryn = intent.getintextra("level", 0); // 目前电量 batteryv = intent.getintextra("voltage", 0); // 电池电压 // batteryt = intent.getintextra("temperature", 0); //电池温度 switch (intent.getintextra("status", batterymanager.battery_status_unknown)) { case batterymanager.battery_status_charging: batterystatus = "充电状态"; break; case batterymanager.battery_status_discharging: batterystatus = "放电状态"; break; case batterymanager.battery_status_not_charging: batterystatus = "未充电"; break; case batterymanager.battery_status_full: batterystatus = "充满电"; break; case batterymanager.battery_status_unknown: batterystatus = "未知道状态"; break; } switch (intent.getintextra("health", batterymanager.battery_health_unknown)) { case batterymanager.battery_health_unknown: batterytemp = "未知错误"; break; case batterymanager.battery_health_good: batterytemp = "状态良好"; break; case batterymanager.battery_health_dead: batterytemp = "电池没有电"; break; case batterymanager.battery_health_over_voltage: batterytemp = "电池电压过高"; break; case batterymanager.battery_health_overheat: batterytemp = "电池过热"; break; } tv.settext("目前电量为" + batteryn + "% --- " + batterystatus + "n" + "电压为" + batteryv + "mv ----- " + batterytemp); } } }; @override public boolean onkeydown(int keycode, keyevent event)// 程序按返回键退出处理 { switch (keycode) { case keyevent.keycode_back: // 双击退出 // if (isstart == true){isstart = false;}//关闭前确认频闪是否关闭 if ((system.currenttimemillis() - mexittime) > 2000) { toast.maketext(this, "再按一次退出", toast.length_short).show(); mexittime = system.currenttimemillis(); } else { // isstart = false; finish(); } return true; default: break; } return super.onkeydown(keycode, event); } }
布局文件:
<?xml version="1.0" encoding="utf-8"?> <linearlayout xmlns:android="https://schemas.android.com/apk/res/android" android:id="@+id/linearlayout1" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1" > <!-- --> <textview android:id = "@+id/tv" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <button android:text="保存该曲线图" android:textsize="4pt" android:id="@+id/my_button" android:layout_width="fill_parent" android:layout_height="28dp" android:layout_alignbottom="@+id/tv"> <!--android:layout_alignparentbottom="true"--> </button> </linearlayout>
androidmanifest.xml配置文件
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="https://schemas.android.com/apk/res/android" package="com.cfzz.vcd" android:versioncode="1" android:versionname="1.0"> <uses-sdk android:minsdkversion="10" /> <uses-permission android:name="android.permission.read_frame_buffer"/> <uses-permission android:name="android.permission.write_external_storage"/> <uses-permission android:name="android.permission.wake_lock" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <activity android:name="org.achartengine.graphicalactivity" /> <activity android:name="com.cfzz.vcd.voltagechangedraw" android:screenorientation="portrait" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.main" /> <category android:name="android.intent.category.launcher" /> </intent-filter> </activity> </application> </manifest>
在该源码中,我们绘制了两条曲线,一条是电压变化曲线,另一条是电量变化曲线,并加一个保存手机屏幕的截图按钮和自动保存时间任务(也可手动保存),用来保存绘制的截图。
运行结果图(充电曲线图):
以上就是android开发分享Android实现动态曲线绘制的全部内容,希望对大家的学习有所帮助,也希望大家多多支持<计算机技术网(www.ctvol.com)!!>。
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/addevelopment/1111648.html