autojs内存折线图

324 阅读4分钟

牙叔教程 简单易懂

不管新手老手, 都有可能遇到内存泄露的问题, 如何更好的排查内存泄漏的问题呢?

将内存可视化, 以便我们分析内存在整个程序生命周期内的变化规律, 辅助我们解决bug.

什么是折线图

autojs怎么实现折线图

用canvas绘制即可, 折线图有很多数据, 每个数据看成一个点, 两个点连成线, 就实现了折线图;

我们还会给折线图增加平移和缩放的功能

实现折线图的具体步骤

  1. UI界面

折线图是为了在程序运行的时候可视化, 因此, 我们使用悬浮窗来展示UI, 这样不会干扰程序的正常运作;

let window = floaty.rawWindow(
    <vertical id="rootView" alpha="0">
        <horizontal bg="#dee2e6">
            <text id="info"></text>
            <text id="currentTouchMemoryValue"></text>
        </horizontal>
        <canvas id="canvas"></canvas>
    </vertical>
);

顶栏的text标签用来展示具体的数据, canvas用来画折线图


  1. 创建一些数据, 用来测试我们的程序
function MemoryValue(name, value) {
    this.name = name;
    this.value = value;
}
  • name: 我设计这个字段用来存储, 代码的当前作用, 比如读取图片, 创建数组, 回收资源, 等名字
  • value: 是具体的内存大小
for (var i = 0; i < 10; i++) {
    let memoryValue = new MemoryValue("no." + i, random(100, 1000));
    lineGraphWindow.addMemoryValue(memoryValue);
    sleep(1000);
}

addMemoryValue是折线图这个类的方法, 用来增加数据, 我们的程序的内存一直都在变化, 因此, 这个方法是必须的

如何获取程序当前使用的内存, 请看这篇教程: www.yuque.com/yashujs/bfu…


  1. 思考一下折线图怎么画

折线图是一堆数据的展示方式, 他把一个一个的数据变成了点, 再把点连成线;

数据怎么变成点呢?

这是一个比例换算的问题, 我们找出数据中的最大值, 它对应的比例就是canvasView的高度,

那么按照这个比例, 我们取出一个数据, 就可以计算出对应的坐标;

这里要封装两个方法, 一个是找数据中的最大值, 一个是计算数据对应的坐标

找数据中的最大值

function findMaxMemoryValue(memoryValues) {
    let maxMemoryValueIndex = 0;
    for (let i = 0; i < memoryValues.length; i++) {
        if (memoryValues[i].value > memoryValues[maxMemoryValueIndex].value) {
            maxMemoryValueIndex = i;
        }
    }
    return memoryValues[maxMemoryValueIndex];
}

计算数据对应的坐标

LineGraphWindow.prototype.addPoint = function () {
    if (this.memoryValues.length < 2) {
        return;
    }
    let maxMemoryValue = this.maxMemoryValue;
    let unitWidth = this.twoPointDistance;
    let count = 0;
    for (let i = this.memoryValues.length - 1; i >= 0; i--) {
        let memoryValue = this.memoryValues[i];
        let x = this.canvasViewWidth - count * unitWidth;
        let y = this.canvasViewHeight - (this.canvasViewHeight * memoryValue.value) / maxMemoryValue.value;
        memoryValue.point = {
            x: x,
            y: y,
        };
        count++;
    }
};

  1. 坐标有了, 把点连成线

这里的循环次数是: this.memoryValues.length - 1, 因为3个点, 是2条线

LineGraphWindow.prototype.drawMemoryValues = function (canvas) {
    if (this.memoryValues.length < 2) {
        return;
    }
    for (var i = 0; i < this.memoryValues.length - 1; i++) {
        let memoryValue1 = this.memoryValues[i];
        let memoryValue2 = this.memoryValues[i + 1];
        let startX = memoryValue1.point.x;
        let startY = memoryValue1.point.y;
        let stopX = memoryValue2.point.x;
        let stopY = memoryValue2.point.y;
        canvas.drawLine(startX, startY, stopX, stopY, linePaint);
    }
};

  1. 折线图的坐标系

纵轴是表示数据的高度, 横轴呢?

横轴在这里没有具体的含义, 单纯是为了把两个点分开, 让两个点之间有段距离, 这段距离可以在config.js中控制, 我我使用的是悬浮窗宽度的十分之一宽度

twoPointDistanceRatio: 0.1,

某种程度上, 横轴可以看做时间


  1. 到这里, 我们把点连成线, 折线图的基本样式就出现了;

假如折线图有1000条数据, 你要一次绘制1000个点, 999条线, 吗?

手机的屏幕可装不下这么多点和线, 屏幕上撑死显示几十个点;

因此, 我们要增加平移动能, 当手指触摸canvasVIew, 折线图需要左右跟着移动;

LineGraphWindow.prototype.setOnTouchListener = function () {
    ...
    this.window.canvas.setOnTouchListener(function (view, event) {
        pointCount = event.getPointerCount();
        switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                ...
            case MotionEvent.ACTION_POINTER_DOWN:
                ...
                break;
            case MotionEvent.ACTION_MOVE:
                ...
                break;
            case MotionEvent.ACTION_POINTER_UP:
                ...
                break;
            case MotionEvent.ACTION_UP:
                ...
                break;
        }

        return true;
    });
};
  • ACTION_DOWN事件中, 记下手指按下的坐标
  • ACTION_MOVE事件中, 移动后的坐标和按下的坐标, 计算移动的距离
  • 移动的距离计算出来以后, 对应的平移canvas canvas.translate

  1. 上面是平移, 常见的还有双指缩放

如果我们觉得显示的点位, 过多或者过少, 我们可以用双指缩放, 以便展现合适数量的数据;

缩放使用的是 canvas.scale

缩放的难点是什么?

是在缩放以后, 把用户的点击时按下的坐标, 换算为canvasView平移和缩放后的坐标, 他们的关系有点复杂,

新手搞不清除, 一定得花时间屡屡各个坐标系的关系, 才能搞清楚.

把他们的关系搞清楚以后, 我们可以借助matrix, 方便的转换坐标

平移

matrix.postTranslate

缩放

matrix.postScale

最重要的是别忘了重置matrix, 不然效果会叠加的

matrix.reset();

举个例子, 比如

原先canvas坐标系的点A(0,0), canvas向右平移100, 向下平移50,

平移之后的坐标是A'(0,0),

A'在原来坐标中的点位是(100,50)

importClass(android.graphics.Matrix);
matrix = new Matrix();
matrix.setTranslate(100, 100);
points1 = util.java.array("float", 2);
points1[0] = 0;
points1[1] = 0;
log(points1); // [0.0, 0.0] 
matrix.mapPoints(points1);
log(points1); // [100.0, 50.0] 

这里面一共有几个坐标系?

  • canvasView的坐标系, 这个坐标系对应的是用户手指的触摸
  • canvasView里面的canvas的坐标系, 这个是折线图的坐标系, 他会平移和缩放

大家着重要思考的问题是, 用户的触摸坐标, 换算为canvas上的坐标, 要考虑平移和缩放;

折线图的动图

动态加载数据

平移

缩放

点击事件

环境

设备: 小米11pro

Android版本: 12

Autojs版本: 9.2.13

名人名言

思路是最重要的, 其他的百度, bing, stackoverflow, github, 安卓文档, autojs文档, 最后才是群里问问 --- 牙叔教程

声明

部分内容来自网络 本教程仅用于学习, 禁止用于其他用途

微信公众号 牙叔教程