安卓打开已有记录数据并显示波形

    技术2022-07-13  65

    #安卓打开已有记录数据并显示波形

    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) { } }); }

    安卓项目打开已有数据并显示

    Processed: 0.018, SQL: 9