Android内存泄漏自定义视图

时间:2016-05-18 10:07:07

标签: android memory-leaks android-custom-view

我试图制作小型应用。此应用程序具有活动,自定义视图类和服务。

1)活动向新数据请求服务并重绘自定义视图 2)服务列表到蓝牙设备并解析数据。

一切都很好,但我发现应用程序在工作40分钟后正在放慢速度。

我做了另一个项目删除服务,发现它也在减速!所以问题是我的Customview类,也许我在服务中有内存泄漏...但我的图纸100%有问题。

我发现我有一些我在onDraw()方法上创建的对象..我试图将所有这些人员移动到onSizeChanged() - 但得到更多的滞后。

现在我需要帮助。我需要一些简单图纸的例子,这些图纸取决于设备的宽度和高度(我认为我的方法是错误的 - 我使用我的' Design'来计算px中的demetions的比例)

顺便说一句,我使用动画制作动画更加流畅))

public class Dynamics {

    /**
     * Used to compare floats, if the difference is smaller than this, they are
     * considered equal
     */
    private static final float TOLERANCE = 0.01f;

    /** The position the dynamics should to be at */
    private float targetPosition;

    /** The current position of the dynamics */
    private float position;

    /** The current velocity of the dynamics */
    private float velocity;

    /** The time the last update happened */
    private long lastTime;

    /** The amount of springiness that the dynamics has */
    private float springiness;

    /** The damping that the dynamics has */
    private double damping;

    public Dynamics(float springiness, float dampingRatio) {
        this.springiness = springiness;
        this.damping = dampingRatio * 2 * Math.sqrt(springiness);
    }

    public void setPosition(float position, long now) {
        this.position = position;
        lastTime = now;
    }

    public void setVelocity(float velocity, long now) {
        this.velocity = velocity;
        lastTime = now;
    }

    public void setTargetPosition(float targetPosition, long now) {
        this.targetPosition = targetPosition;
        lastTime = now;
    }

    public void update(long now) {
        float dt = Math.min(now - lastTime, 50) / 1000f;

        float x = position - targetPosition;
        double acceleration = -springiness * x - damping * velocity;

        velocity += acceleration * dt;
        position += velocity * dt;

        lastTime = now;
    }

    public boolean isAtRest() {
        final boolean standingStill = Math.abs(velocity) < TOLERANCE;
        final boolean isAtTarget = (targetPosition - position) < TOLERANCE;
        return standingStill && isAtTarget;
    }

    public float getPosition() {
        return position;
    }

    public float getTargetPos() {
        return targetPosition;
    }

    public float getVelocity() {
        return velocity;
    }

}

在我的自定义视图中,我有这个来设置新数据:

public void  SetData(int[] NewData2,float[]newDatapoints)
{


    this.NewData=NewData2;

    long now = AnimationUtils.currentAnimationTimeMillis();
    if (datapoints == null || datapoints.length != newDatapoints.length) {
        datapoints = new Dynamics[newDatapoints.length];
        for (int i = 0; i < newDatapoints.length; i++) {
            datapoints[i] = new Dynamics(70f, 0.50f);
            datapoints[i].setPosition(newDatapoints[i], now);
            datapoints[i].setTargetPosition(newDatapoints[i], now);
        }
        invalidate();
    } else {
        for (int i = 0; i < newDatapoints.length; i++) {
            datapoints[i].setTargetPosition(newDatapoints[i], now);
        }
        removeCallbacks(animator);
        post(animator);
    }
    LastData=NewData;

    //redraw();
}

这是&#34;代码&#34;我的自定义视图,经过所有更改后看起来很明显,所以我减少了90%。我制作了一些测试代码:

        import android.content.Context;
        import android.content.res.AssetManager;
        import android.content.res.TypedArray;
        import android.graphics.Canvas;
        import android.graphics.Color;
        import android.graphics.ComposeShader;
        import android.graphics.LinearGradient;
        import android.graphics.Paint;
        import android.graphics.Paint.Style;
        import android.graphics.Path;
        import android.graphics.PorterDuff;
        import android.graphics.RadialGradient;
        import android.graphics.RectF;
        import android.graphics.Shader;
        import android.graphics.Typeface;
        import android.graphics.drawable.Drawable;
        import android.util.AttributeSet;
        import android.util.DisplayMetrics;
        import android.view.View;
        import android.view.animation.AnimationUtils;

        import java.io.IOException;
        import java.math.RoundingMode;
        import java.text.DecimalFormat;
        import java.util.Random;



public class CustomDisplayView extends View {



    //paint for drawing custom view
    private Paint RectPaint = new Paint();

    //Динамические данные float
    private Dynamics[] datapoints;
    //Динамические статические Int
    private int[] NewData = new int[500];
    //созадем новый объект квадрат
    private RectF rectf= new RectF();

    //Задаем массив динамических цветов
    int[] CurColors= new int[100];
    int[] TargetColors= new int[100];

    public CustomDisplayView(Context context, AttributeSet attrs){
        super(context, attrs);

        //Установка парметров красок
        RectPaint.setAntiAlias(true);



    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        if (w != 0 && h != 0) {
            //create Bitmap here

        }

    }

    /**
     * Override the onDraw method to specify custom view appearance using canvas
     */
       @Override
    protected void onDraw(Canvas canvas) {

        //Get Screen size
        //int viewWidth=this.getMeasuredWidth();
       // int viewHeight = this.getMeasuredHeight();


        //Выводим код цвета

        RectPaint.setColor(0xff000000);
        RectPaint.setTextSize(40);


        canvas.restore();
        canvas.drawText("V: " + datapoints[1].getPosition(), 20, 60, RectPaint);

        //int saveCount = canvas.save();
        for(int a=0;a<1000;a++)
        {
            rectf.set(datapoints[a].getPosition(), datapoints[a + 1].getPosition(), datapoints[a].getPosition() + datapoints[a + 1].getPosition() / 10, datapoints[a + 1].getPosition() + datapoints[a + 1].getPosition() / 10);

            RectPaint.setColor(0x88005020);
            //RectPaint.setColor(CurColor[a]);
            //canvas.rotate(datapoints[1].getPosition(), viewWidth/2, viewHeight/2);
            canvas.drawRoundRect(rectf, 0, 0, RectPaint);
            //canvas.restore();
        }
        //canvas.restoreToCount(saveCount);


/*
        for(int a=0;a<999;a++)
        {
            CurColors[a]=progressiveColor(CurColors[a], TargetColors[a], 2);
            if(CurColors[a]==TargetColors[a])
            {
                TargetColors[a]=randomColor();
            }
        }
*/

        canvas.restore();
    }



    //Рандом колор
    public static int randomColor(){
        Random random = new Random();
        int[] ColorParams= new int[4];
        ColorParams[0]=random.nextInt(235)+20;
        ColorParams[1]=random.nextInt(255);
        ColorParams[2]=random.nextInt(255);
        ColorParams[3]=random.nextInt(255);
        return Color.argb(ColorParams[0], ColorParams[1], ColorParams[2], ColorParams[3]);

    }

    //Интерполяция цвета
    public static int progressiveColor(int CurColor,int TargetColor,int Step){

        //Current color
        int[] ColorParams= new int[4];
        ColorParams[0]=(CurColor >> 24) & 0xFF;
        ColorParams[1]=(CurColor >> 16) & 0xFF;
        ColorParams[2]=(CurColor >> 8) & 0xFF;
        ColorParams[3]=CurColor & 0xFF;



        //TargetColor
        int[] TargetColorParams= new int[4];
        TargetColorParams[0]=(TargetColor >> 24) & 0xFF;
        TargetColorParams[1]=(TargetColor >> 16) & 0xFF;
        TargetColorParams[2]=(TargetColor >> 8) & 0xFF;
        TargetColorParams[3]=TargetColor & 0xFF;

        for(int i=0;i<4;i++)
        {
            if(ColorParams[i]<TargetColorParams[i])
            {
                ColorParams[i]+=Step;
                if(ColorParams[i]>TargetColorParams[i])
                {
                    ColorParams[i]=TargetColorParams[i];
                }
            }
            else if(ColorParams[i]>TargetColorParams[i])
            {
                ColorParams[i]-=Step;
                if(ColorParams[i]<TargetColorParams[i])
                {
                    ColorParams[i]=TargetColorParams[i];
                }
            }
        }

        //int red = r - (int)((float)(r*255)/(float)all);
        //int green = (int)((float)(g*255)/(float)all);
        return Color.argb(ColorParams[0], ColorParams[1], ColorParams[2], ColorParams[3]);
        //return String.format("#%06X", (0xFFFFFF & Color.argb(ColorParams[0], ColorParams[1], ColorParams[2], ColorParams[3])));
        //return " "+opacity+" "+red+" "+green+" "+blue;
    }








    //each custom attribute should have a get and set method
    //this allows updating these properties in Java
    //we call these in the main Activity class



    /**
     * Get the current text label color
     * @return color as an int
     */
    public int getLabelColor(){
        return 1;
    }

    /**
     * Set the label color
     * @param newColor new color as an int
     */
    public void setLabelColor(int newColor){
        //update the instance variable
        //labelCol=newColor;
        //redraw the view
        invalidate();
        requestLayout();
    }



    public void redraw(){
        //redraw the view
        invalidate();
        requestLayout();
    }



    public void  SetData(int[] NewData2,float[]newDatapoints)
    {


        this.NewData=NewData2;

        long now = AnimationUtils.currentAnimationTimeMillis();
        if (datapoints == null || datapoints.length != newDatapoints.length) {
            datapoints = new Dynamics[newDatapoints.length];
            for (int i = 0; i < newDatapoints.length; i++) {
                datapoints[i] = new Dynamics(70f, 0.50f);
                datapoints[i].setPosition(newDatapoints[i], now);
                datapoints[i].setTargetPosition(newDatapoints[i], now);
            }
            invalidate();
        } else {
            for (int i = 0; i < newDatapoints.length; i++) {
                datapoints[i].setTargetPosition(newDatapoints[i], now);
            }
            removeCallbacks(animator);
            post(animator);
        }


        //redraw();
    }

    public int GetAction(float x,float y)
    {
        /*
        if(x>(DicsCenterX-LineHalfSpeedZone) && x<(DicsCenterX+LineHalfSpeedZone) && y>(DicsCenterY-PowerOutRadius) && y<(DicsCenterY-SpeedZoneRadius2))
        {
            // private int SpeedZoneRadius2=0;
            // private int PowerOutRadius=0;
            //Смена режима
            //начинаем смену размеру index / ms
            ChangeVal(0,700);

            return 1;
        }
        else if(x>(CofCantBGDrop*2) && x<(CofCantBGDrop*4) && y>(DicsCenterY-PowerOutRadius) && y<(DicsCenterY-SpeedZoneRadius2))
        {
            return 2;
        }
        else
        {
            return 0;
        }
        //return 0;

        */
        return 1;
    }


    public static String fmt(double d)
    {
        double val =  d/100;
        String result;
        if(val == (long) val)
            result= String.format("%d",(long)d);
        else
            result= String.format("%s",d);

        if(result.length()<2)
        {
            String result2=result;
            result="0"+result2;
        }

        return result;
    }


    private Runnable animator = new Runnable() {
        @Override
        public void run() {
            boolean needNewFrame = false;
            long now = AnimationUtils.currentAnimationTimeMillis();
            for (Dynamics dynamics : datapoints) {
                dynamics.update(now);
                if (!dynamics.isAtRest()) {
                    needNewFrame = true;
                }
            }
            if (needNewFrame) {
                postDelayed(this, 15);
            }
            invalidate();
        }
    };

}

我只想了解我需要声明缩放值的位置,我需要在px ..和et.c中计算实际尺寸。没有内存泄漏..

如果我删除颜色变化并且更新Rects的数量最多为1000 - 我会滞后。

所有方法o如何调试内存泄漏的任何信息 - 你很好!

1 个答案:

答案 0 :(得分:2)

分离视图时,您必须删除动画的runnable。

if (needNewFrame) {
    postDelayed(this, 15);  <--- memory leak
} 

试试这样。

@Override
protected void onDetachedFromWindow() {
    super.onDetachedFromWindow();
    removeCallback(your runnable);
}

每15毫秒刷新一次也很重。