#安卓打开已有记录数据并显示波形
1、List
1.1 去重和排序
private void Take_number(ArrayList<String> arr, ArrayList<String> arr_temp) {
ArrayList<String> list = new ArrayList();
///先删除重复的数据
for (int i = 2; i < arr.size() - 1; i++) {//前面两组为信息
for (int j = arr.size() - 1; j > i; j--) {
//如果这其中包含的数据相同,则把相同的后面的先替换掉前面的,之后删除掉后面的
if (arr.get(i).substring(0, 1).equals(arr.get(j).substring(0, 1)) && arr.get(i).substring(4, 5).equals(arr.get(j).substring(4, 5))) {
arr.set(i, arr.get(j));
arr.remove(j);
}
}
}
//去重的数据再排序
for(int i=2;i<arr.size()-1;i++){//去除两组存信息的数据
arr_temp.add(arr.get(i));
}
sort_arrylist(arr_temp);//排序
排序完成需要
}
/**
* 排序方法
*/
public static void sort_arrylist(ArrayList<String> arr) {
// System.out.println("排序前:" + stringList);
Collections.sort(arr, new Comparator< String >() {
public int compare(String lhs, String rhs) {
// System.out.println("排序字符串:" + lhs + "," + rhs);
int i = lhs.compareTo(rhs);
// System.out.println("排序结果" + i);
if ( i > 0 ) {
return 1;
} else {
return -1;
}
}
});
2、打开已有数据,并用曲线图的形式显示在手机上
最近做的压力手机压力采集测试火车发动机的压缩压和爆发压。前期已经做好了UI和数据采集的工作,之后甲方要求要在基础上追加功能,能打开已有记录。由于自己很菜,之前也没写过程序。java从0开始花了几个月一面学一面做的能。图表显示的话网上看到过有很多第三方控件。可是总是git下来会有很多问题于是就自己做。
这个功能的顺序是,首先点击按钮打开文件管理器----选已经测量好的文件得到文件路径-有了文件的路径我们就好办,对文件进行操作----再之后读取文件的数据,显示在手机上。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aFkKKgvt-1593656965387)(C:\Users\18395\AppData\Roaming\Typora\typora-user-images\1593652125499.png)]
2.1 打开文件管理器
首先的问题是打开文件管理器得到目标文件的路径。
依照网上的方法整的,效果还不错,我的是一加的手机,对开发比较友好,不知道其他人是什么手机会不会有同样的效果。
在实际测试过程中发现问文件名有“:”–冒号会打开路径不完整。
mbtn_Opent_Test.setOnClickListener(new View.OnClickListener() {//点击事件
@Override
public void onClick(View v) {
vib.vibrate(100);//震动
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
//intent.setType(“image/*”);//选择图片
//intent.setType(“audio/*”); //选择音频
//intent.setType(“video/*”); //选择视频 (mp4 3gp 是android支持的视频格式)
//intent.setType(“video/*;image/*”);//同时选择视频和图片
intent.setType("*/*");//无类型限制
intent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(intent, 1);
}
});
//执行完上面会跳转到下面的方法去执行,具体适合哪个需要根据自己的手机实测
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_OK) {
Uri uri = data.getData();
if ("file".equalsIgnoreCase(uri.getScheme())){//使用第三方应用打开
path = uri.getPath();//这里面就会得到我们想要的文件路径
Intent intent = new Intent(WelcomeActivity.this,ViewActivity.class);//跳转到下一个界面,自己用的
startActivity(intent);
ActivityCollector.finishAll();//结束整个程序
android.os.Process.killProcess(android.os.Process.myPid());//杀死当前进程代码
return;
}
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {//4.4以后,主要测试这个
path = getPath(this, uri);//这里面就会得到我们想要的文件路径
//这里可以用一个TextView显示得到的path,当然,在实际测试过程中发现问文件名有“:”--冒号会打开路径不完整。
New_bulid_folder_flage = true;
startActivity(intent);
ActivityCollector.finishAll();//结束整个程序
android.os.Process.killProcess(android.os.Process.myPid());//杀死当前进程代码
} else {//4.4以下下系统调用方法
path = getRealPathFromURI(uri);
New_bulid_folder_flage = true;
Intent intent = new Intent(WelcomeActivity.this,ViewActivity.class);
intent.putExtra("path",path);//传到下一个界面的路径
startActivity(intent);
ActivityCollector.finishAll();//结束整个程序
android.os.Process.killProcess(android.os.Process.myPid());//杀死当前进程代码
}
}
}
public String getRealPathFromURI(Uri contentUri) {
String res = null;
String[] proj = { MediaStore.Images.Media.DATA };
Cursor cursor = getContentResolver().query(contentUri, proj, null, null, null);
if(null!=cursor&&cursor.moveToFirst()){;
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
res = cursor.getString(column_index);
cursor.close();
}
return res;
}
/**
* 专为Android4.4设计的从Uri获取文件绝对路径,以前的方法已不好使
*/
@SuppressLint("NewApi")
public String getPath(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[]{split[1]};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
///反正这后面我也没看懂,加上就好
/**
* Get the value of the data column for this Uri. This is useful for
* MediaStore Uris, and other file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
* @param selection (Optional) Filter used in the query.
* @param selectionArgs (Optional) Selection arguments used in the query.
* @return The value of the _data column, which is typically a file path.
*/
public String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {column};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
public boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
public boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
public boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
2.2 得到操作的数据处理
这是我自己的数据处理我记录一下,每个人的数据处理都是不一样的。
Take_array(path);//得到初步排序数组,第一行的缸数进行了排列,压缩爆破的顺序没排列
/
str_message = str.get(1).split(",");
_message = str_message[0].split("-");
time_message = _message[1].split(":");//取出时间时分秒
//取出有关于测量的信息,地点、人员的等。具体在项目中查
FolderName = "压力采集测试记录文档";
New_bulid_folder_flage = true;
flge_of_openfile= true;
//2020年7月1日-22时26分12秒
DayData = _message[0]+"-"+time_message[0]+"时"+time_message[1]+"分"+time_message[2]+"秒";
DayData_1 = str_message[0];
PlaceData = str_message[1];
NameData= str_message[2];
EngineTypeData= str_message[4];
Driver_Number= str_message[3];
CylinderNumberData_temp= str_message[5];
//把汉字去掉
CylinderNumberData = CylinderNumberData_temp.substring(0,CylinderNumberData_temp.length()-1);
repairing= str_message[6];
Km= str_message[7];
/
//方法在oncreat外面。
/**
* 读取文件中的内容到list
* @author 汪陈松
* @param filePath 文件路径
*/
private static void readFile(String filePath) {
if (filePath == null) return;
File file = new File(filePath);
if (file.isDirectory()) {
return;
} else {
try {
InputStream is = new FileInputStream(file);
if (is != null) {
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null) {
str.add(line);
}
br.close();
}
} catch (FileNotFoundException e) {
} catch (IOException e) {
}
}
}
/**
* 得到可操作数组
* @author 汪陈松
* @param arr list
*/
private static void Take_list(ArrayList<String> arr) {
///先删除重复的数据
for (int i = 2; i < arr.size() - 1; i++) {//前面两组为信息
for (int j = arr.size() - 1; j > i; j--) {
String[] s1 = arr.get(i).split(",");
Float[] f1 = new Float[400];
for(int i1=0;i1<f1.length-1;i1++){//把split出来的字符串数组转换为Float数组
f1[i1]= Float.parseFloat(s1[i1]);
}
String[] s2 = arr.get(j).split(",");
Float[] f2 = new Float[400];
for(int i2=0;i2<f2.length-1;i2++){//把split出来的字符串数组转换为Float数组
f2[i2]= Float.parseFloat(s2[i2]);
}
if(s1[0].equals(s2[0])&&s1[1].equals(s2[1])){//如果前两个都相等,取后面的到前面,再删掉后面的,
arr.set(i,arr.get(j));
arr.remove(j);
}
if(f1[0]>f2[0]){//前面的数就大于后面的数,交换//好使
swap(arr, i, j);
}
}
}
}
/**
*交换
* @param list
* @param index1 下标1
* @param index2 下标2
* @param <E>
*/
private static <E> void swap(List<E> list, int index1, int index2) {
//定义第三方变量
E e=list.get(index1);
//交换值
list.set(index1, list.get(index2));
list.set(index2, e);
}
/**
* 把每一行读出来的数据变为一个数组,转化为Float存入数组,再存入list中
* @param filePath
*/
private static void Take_array(String filePath){
readFile(filePath);
Take_list(str);//获取到初步删除并简单按第一项排序的Arrylist
for(int i=2;i<str.size();i++){//从新用一个list把数据部分的项装进去
str_1.add(str.get(i));
}
for(int i=0;i<str_1.size();i++){//把split出来的每一项数据存入一个数组中,再把数组存入List中
//那么就有16个数组,每个数组存400个数据
String[] s = str_1.get(i).split(",");
double[] f = new double[s.length];
for(int j=0;j<s.length;j++){
f[j]=Double.parseDouble(s[j]);//字符串转浮点数
}
str_array.add(f);
f=null;//清空数组
}
}
2.3、画图
这里面没有用网上的其他第三方控件的方法。之前做过动态显示用SurfaceView,在这里面也用这个,只是不再用线程去画。直接化啊啊啊啊一个静态的。
首先,我的情况特殊。每个测项有两状态,压缩和爆发,标志01区分。有可能还有重复的数据且有缺失我要表现出来。
int have = 0;
for (int i = 0; i < str_array.size()-1 ; i++) {
if (str_array.get(i)[0]==str_array.get(i + 1)[0]) {
have++;
}
}//得到重复的数据个数
//
int count = str_array.size() - have;//得到要显示画布个数,一个画布理论显示两个波形
for (int i = 1; i < count + 1; i++) {
//显示bu可见,这是tiaoshi看下,实际上,我们在UI界面要给他们设置都不可见,然后得到具体数目之后,显示其可见
//即是--一进这个界面上面是白的,选择后可见几个缸
SurfaceView_array[i].setVisibility(View.VISIBLE);//显示
}
//SurfaceView画图
SurfaceView SurfaceView_array[] = new SurfaceView[17];//控件数组
//更具实际情况定义数目
surfaceView_1 = findViewById(R.id.surfaceView_1);
surfaceView_2 = findViewById(R.id.surfaceView_2);
surfaceView_3 = findViewById(R.id.surfaceView_3);
surfaceView_4 = findViewById(R.id.surfaceView_4);
surfaceView_5 = findViewById(R.id.surfaceView_5);
surfaceView_6 = findViewById(R.id.surfaceView_6);
surfaceView_7 = findViewById(R.id.surfaceView_7);
surfaceView_8 = findViewById(R.id.surfaceView_8);
surfaceView_9 = findViewById(R.id.surfaceView_9);
surfaceView_10 = findViewById(R.id.surfaceView_10);
surfaceView_11 = findViewById(R.id.surfaceView_11);
surfaceView_12 = findViewById(R.id.surfaceView_12);
surfaceView_13 = findViewById(R.id.surfaceView_13);
surfaceView_14 = findViewById(R.id.surfaceView_14);
surfaceView_15 = findViewById(R.id.surfaceView_15);
surfaceView_16 = findViewById(R.id.surfaceView_16);
//把控件都装入数组
SurfaceView_array[1] = surfaceView_1;
SurfaceView_array[2] = surfaceView_2;
SurfaceView_array[3] = surfaceView_3;
SurfaceView_array[4] = surfaceView_4;
SurfaceView_array[5] = surfaceView_5;
SurfaceView_array[6] = surfaceView_6;
SurfaceView_array[7] = surfaceView_7;
SurfaceView_array[8] = surfaceView_8;
SurfaceView_array[9] = surfaceView_9;
SurfaceView_array[10] = surfaceView_10;
SurfaceView_array[11] = surfaceView_11;
SurfaceView_array[12] = surfaceView_12;
SurfaceView_array[13] = surfaceView_13;
SurfaceView_array[14] = surfaceView_14;
SurfaceView_array[15] = surfaceView_15;
SurfaceView_array[16] = surfaceView_16;
for (int i = 1; i < count+1; i++) {//这里就实现了根据数据显示画布数目和显示
SurfaceHolder surfaceHolder = SurfaceView_array[i].getHolder();//动态画布定义
surfaceHolder.addCallback(new SurfaceHolder.Callback() {//回调
@Override
public void surfaceCreated(SurfaceHolder holder) {
//自己的数据处理
boolean mesdata_dis_1_flage = false;
boolean mesdata_dis_flage = false;
//处理数据,对是否有缺失进行的判断
if (str_array.get(j)[0]==str_array.get(j+1)[0]) {//即是爆发压和压缩压都存在
if(str_array.get(j)[1]>str_array.get(j+1)[1]){//前者爆发压
for(int m=0;m<mesdata_dis_1.length;m++){
mesdata_dis_1[m] = str_array.get(j)[m];
}
for(int m=0;m<mesdata_dis.length;m++){//压缩压
mesdata_dis[m] = str_array.get(j+1)[m];
}
mesdata_dis_1_flage= true;
mesdata_dis_flage =true;
}
else if(str_array.get(j)[1]<str_array.get(j+1)[1]){//后 者爆发压
for(int m=0;m<mesdata_dis_1.length;m++){
mesdata_dis_1[m] = str_array.get(j+1)[m];
}
for(int m=0;m<mesdata_dis.length;m++){//压缩压
mesdata_dis[m] = str_array.get(j)[m];
}
mesdata_dis_1_flage= true;
mesdata_dis_flage =true;
}
j=j+2;//直接两组数据显示过了
} else{ //如果值不一样,证明有缺失
if(str_array.get(j)[1]==1.0){//爆发压
for(int m=0;m<mesdata_dis_1.length;m++){
mesdata_dis_1[m] = str_array.get(j)[m];
}
mesdata_dis_1_flage =true;
}
if(str_array.get(j)[1]==0.0){//压缩压
for(int m=0;m<mesdata_dis.length;m++){
mesdata_dis[m] = str_array.get(j)[m];
}
mesdata_dis_flage =true;
}
j=j+1;//只有一组数据显示
}
//这里才是画布要设置的
Canvas canvas = holder.lockCanvas(); //获得canvas对象
canvas.drawColor(Color.YELLOW);
Paint paint = new Paint();
paint.setAntiAlias(true); //是用来防止边缘的锯齿
paint.setFilterBitmap(true); //函数是用来对位图进行滤波处理
Paint pen1 = new Paint();
pen1.setColor(Color.YELLOW);
pen1.setStrokeWidth(4);
pen1.setAntiAlias(true);
pen1.setTextSize(30);
Paint pen = new Paint();
pen.setColor(getResources().getColor(R.color.lineColor));
pen.setStrokeWidth(4);
pen.setAntiAlias(true);
pen.setTextSize(30);
Paint pen2 = new Paint();
pen2.setColor(getResources().getColor(android.R.color.holo_red_dark));
pen2.setStrokeWidth(4);
pen2.setAntiAlias(true);
pen2.setTextSize(30);
int wi = 900;//canvas1.getWidth();
int he = 500;//canvas1.getHeight();
canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG));//滤锯齿
Bitmap bitmap1 = Bitmap.createBitmap(wi, he, Bitmap.Config.ARGB_8888);
Canvas tempCanvas1 = new Canvas(bitmap1);
tempCanvas1.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG
| Paint.FILTER_BITMAP_FLAG));
tempCanvas1.drawColor(getResources().getColor(R.color.black)); //绘制背景
DecimalFormat drk = new DecimalFormat("0.00");//#则不保留0的
float cx, cy, dx, dy; //画线需要的起点坐标和终点坐标
if(mesdata_dis_flage) {
for (int i = 9; i < ((int) mesdata_dis[8]-1 ); i++) {//对数据集合中的数据点进行两个两个的绘制多画20个点
//起点:int//第九个记录是数据
// int xsc = (500 / ((int) mesdata_dis[8]));//shuipingfendian
cx = i * 6 + 330;// xScale+xoffset;//扫描周期
cy = (float) (he - he * mesdata_dis[((int) mesdata_dis[4] - 5) + i] / 14);
//并根据Canvas高度对数据进行一定比例的放大
//终点:
dx = (i + 1) * 6 + 330;//xScale+xoffset;
dy = (float) (he - he * mesdata_dis[((int) mesdata_dis[4] - 5) + i + 1] / 14);
//在起点和重点之间画一条线段
tempCanvas1.drawLine(cx, cy, dx, dy, pen1);
}
}
/需要根据数据来改变放大倍数,写死的方法是不行的。目前还没想到解决的方法
if(mesdata_dis_1_flage) {
for (int i = 9; i < ((int) mesdata_dis_1[8]-1); i++) {//对数据集合中的数据点进行两个两个的绘制多画20个点
//起点:int
// int xsc = (500 / ((int) mesdata_dis_1[8]));//shuipingfendian
cx = i * 6 + 330;// xScale+xoffset;//扫描周期
cy = (float) (he - he * mesdata_dis_1[((int) mesdata_dis_1[4] - 5) + i] / 14);//由于左上角为(0,0),需要对画出来的图进行上下颠倒,
//并根据Canvas高度对数据进行一定比例的放大
//终点:
dx = (i + 1) * 6 + 330;//xScale+xoffset;
dy = (float) (he - he * mesdata_dis_1[((int) mesdata_dis_1[4] - 5) + i + 1] / 14);
//在起点和重点之间画一条线段
tempCanvas1.drawLine(cx, cy, dx, dy, pen2);
}
}
tempCanvas1.drawLine(300, 10, 300, he - 10, pen);//中间划线
//爆发压
if(mesdata_dis_1_flage){
tempCanvas1.drawText("缸 号:" + (int) mesdata_dis_1[0], 10, 40, pen);//1
tempCanvas1.drawText("峰 值:" + drk.format(mesdata_dis_1[3]) + "Mp", 10, 90, pen2);//2
tempCanvas1.drawText("右 值:" + drk.format(mesdata_dis_1[7]) + "Mp", 10, 140, pen2);//3
tempCanvas1.drawText("左 值:" + drk.format(mesdata_dis_1[5]) + "Mp", 10, 190, pen2);//4
tempCanvas1.drawText("爆发压", 420, 40, pen2);//5"类 型:"+
tempCanvas1.drawLine(340, 30, 400, 30, pen2);}
///压缩压
if(mesdata_dis_flage) {
tempCanvas1.drawText("缸 号:" + (int) mesdata_dis[0], 10, 40, pen);//1
tempCanvas1.drawText("压缩压", 630, 40, pen1);//5"类 型:"+
tempCanvas1.drawLine(550, 30, 610, 30, pen1);
tempCanvas1.drawText("峰 值:" + drk.format(mesdata_dis[3]) + "Mp", 10, 300, pen1);//2
tempCanvas1.drawText("右 值:" + drk.format(mesdata_dis[7]) + "Mp", 10, 350, pen1);//3
tempCanvas1.drawText("左 值:" + drk.format(mesdata_dis[5]) + "Mp", 10, 400, pen1);//4
}
///
//这里也是画布操作,中间是数据显示操作
canvas.drawBitmap(bitmap1, 0, 0, pen);
holder.unlockCanvasAndPost(canvas); //释放canvas对象}
}
记录格式#+缸号+测量类型,最大值(xy),左最小(xy),右最小(xy),记录长度,9个记录值
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
});
}
); holder.unlockCanvasAndPost(canvas); //释放canvas对象}
}
记录格式#+缸号+测量类型,最大值(xy),左最小(xy),右最小(xy),记录长度,9个记录值
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
});
}
安卓项目打开已有数据并显示