Android 实现根据录音分贝画波浪线

自己整理的用法新的,和更改,以适合自己用:

自己运用

上代码:


这几个很重要:更改,自己定义;

要在文件夹添加:

compile 'com.github.Jay-Goo:AndroidMP3Recorder:v1.0.7'

自己看就行了我就直接复制自己更改的地方

上代码2:

package  com.example.launcherexploit.Shr;

import android.content.Context;
import android.os.Environment;
import android.os.Handler;
import android.util.AttributeSet;

import com.czt.mp3recorder.MP3Recorder;

import java.io.File;
/**
 */
public class WaveMp3Recorder extends WaveLineView {
    private String RECORD_FILE_DIR = Environment.getExternalStorageDirectory()+"/";
    private String recordFileName = "WaveLineViewTest.mp3";
    private MP3Recorder mp3Recorder;
    private long maxRecordTime = 1000 * 60 * 60 * 24;
    private long recordTime = 0;
    private int UPDATE_TIME = 200;
    private OnRecordStateChangeListener mOnRecordStateChangeListener;
    private Handler mHandler = new Handler();

    public WaveMp3Recorder(Context context) {
        this(context,null);
    }

    public WaveMp3Recorder(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public WaveMp3Recorder(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initRecorder();
    }

    private void updateRecordingUI(){
        if (mp3Recorder != null) {
            setVolume(100 * mp3Recorder.getVolume() / mp3Recorder.getMaxVolume());
        }
    }

    private void updateStopRecordUI(){
        stopAnim();
    }

    private void updateStartRecordUI(){
        startAnim();
    }

    /**
     * 录音更新进度条
     */
    private Runnable mRecordProgressTask = new Runnable() {
        public void run() {

            //录音时间超出最大时间,自动停止
            if (recordTime > maxRecordTime){
                stopRecord(true);
            }else {
                updateRecordingUI();
                if (mHandler != null) {
                    mHandler.postDelayed(mRecordProgressTask, UPDATE_TIME);
                }
            }
        }
    };

    public void initRecorder(){
        File recordFile = new File(RECORD_FILE_DIR, recordFileName);
        mp3Recorder = new MP3Recorder(recordFile);
        mp3Recorder.setDefaultLameMp3BitRate(96);
    }

    public void startRecording(){
        try {
            mp3Recorder.start();
            if (mHandler != null) {
                mHandler.post(mRecordProgressTask);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }


    //停止录音按钮状态
    public void stopRecord(boolean isFromUser){
        if (mHandler != null) {
            mHandler.removeCallbacksAndMessages(null);
        }
        try {
            recordTime = 0;
            updateStopRecordUI();
            if (mp3Recorder != null) {
                mp3Recorder.stop();
            }
        }catch (Exception e){
            e.printStackTrace();
        }


        if (mOnRecordStateChangeListener != null){
            mOnRecordStateChangeListener.onStopRecord(getRecordFile(),isFromUser);
        }
    }

    public void stopRecord(){
        stopRecord(false);
    }

    //开始录音
    public void startRecord(){
        updateStartRecordUI();
        try {
            mp3Recorder.start();
            if (mHandler != null) {
                mHandler.post(mRecordProgressTask);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (mOnRecordStateChangeListener != null){
            mOnRecordStateChangeListener.onStartRecord();
        }
    }

    //是否在录音
    public boolean isRecording(){
        if (mp3Recorder != null){
            return mp3Recorder.isRecording();
        }
        return false;
    }

    //设置录音的最大时间
    public void setMaxRecordTime(long millis){
        maxRecordTime = millis;
    }

    //获取录音文件
    public File getRecordFile(){
        return new File(RECORD_FILE_DIR, recordFileName);
    }

    public String getRecordFilePath(){
        return RECORD_FILE_DIR + "/"+recordFileName;
    }

    public MP3Recorder getMp3Recorder(){
        return mp3Recorder;
    }


    //录音状态监听
    public interface OnRecordStateChangeListener{
        void onStartRecord();
        void onStopRecord(File recordFile, boolean isFromUser);
    }

    public void setOnRecordStateChangeListener(OnRecordStateChangeListener listener){
        mOnRecordStateChangeListener = listener;
    }

}
上代码3:

package com.example.launcherexploit.Shr;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.media.MediaRecorder;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.SparseArray;

import com.example.launcherexploit.R;
import com.example.launcherexploit.Utils.ConfigureFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import static android.os.Build.VERSION_CODES.BASE;

/**
 */
public class WaveLineView extends RenderView {

    private final int DEFAULT_SAMPLING_SIZE = 64;
    private final float DEFAULT_OFFSET_SPEED =  250F;
    private final int DEFAULT_SENSIBILITY =  5;

    //采样点的数量,越高越精细,但是高于一定限度肉眼很难分辨,越高绘制效率越低
    private int samplingSize;

    //控制向右偏移速度,越小偏移速度越快
    private float offsetSpeed;
    //平滑改变的音量值
    private float volume=0;

    //用户设置的音量,[0,100]
    private int targetVolume = 0;

    //每次平滑改变的音量单元
    private float perVolume;

    //灵敏度,越大越灵敏[1,10]
    private int sensibility;

    //背景色
    private int backGroundColor=Color.BLACK ;

    //波浪线颜色
    private int lineColor;
    //粗线宽度
    private int thickLineWidth;
    //细线宽度
    private int fineLineWidth;

    private final Paint paint = new Paint();

    {
        //防抖动
        paint.setDither(true);
        //抗锯齿,降低分辨率,提高绘制效率
        paint.setAntiAlias(true);
    }

    private List<Path> paths = new ArrayList<>();
    {
        for (int i = 0; i < 4; i++) {
            paths.add(new Path());
        }
    }

    //不同函数曲线系数
    private float[] pathFuncs = {
            0.6f, 0.35f, 0.1f, -0.1f
    };

    //采样点X坐标
    private float[] samplingX;
    //采样点位置映射到[-2,2]之间
    private float[] mapX;
    //画布宽高
    private int width,height;
    //画布中心的高度
    private int centerHeight;
    //振幅
    private float amplitude;
    //存储衰变系数
    private SparseArray<Double> recessionFuncs = new SparseArray<>();
    //连线动画结束标记
    private boolean isPrepareLineAnimEnd = false;
    //连线动画位移
    private int lineAnimX = 0;
    //渐入动画结束标记
    private boolean isPrepareAlphaAnimEnd = false;
    //渐入动画百分比值[0,1f]
    private float prepareAlpha = 0f;
    //是否开启准备动画
    private boolean isOpenPrepareAnim = false;

    public WaveLineView(Context context) {
        this(context, null);
    }

    public WaveLineView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public WaveLineView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initAttr(attrs);
    }

    private void initAttr(AttributeSet attrs) {
        TypedArray t = getContext().obtainStyledAttributes(attrs,R.styleable.WaveLineView);
        backGroundColor = t.getColor(R.styleable.WaveLineView_wlvBackgroundColor, Color.BLACK);
        samplingSize = t.getInt(R.styleable.WaveLineView_wlvSamplingSize, DEFAULT_SAMPLING_SIZE);
        lineColor = t.getColor(R.styleable.WaveLineView_wlvLineColor, Color.parseColor("#2ED184"));
        thickLineWidth = (int)t.getDimension(R.styleable.WaveLineView_wlvThickLineWidth, 6);
        fineLineWidth = (int)t.getDimension(R.styleable.WaveLineView_wlvFineLineWidth, 2);
        offsetSpeed = t.getFloat(R.styleable.WaveLineView_wlvMoveSpeed, DEFAULT_OFFSET_SPEED);
        sensibility = t.getInt(R.styleable.WaveLineView_wlvSensibility, DEFAULT_SENSIBILITY);
        t.recycle();
        checkVolumeValue();
        checkSensibilityValue();
    }

    @Override
    protected void doDrawBackground(Canvas canvas) {
        //绘制背景
        canvas.drawColor(backGroundColor);
    }

    @Override
    protected void onRender(Canvas canvas, long millisPassed) {
        float offset = millisPassed / offsetSpeed;

        if (null == samplingX){
            initDraw(canvas);
        }

        if (lineAnim(canvas)) {
            resetPaths();
            softerChangeVolume();

            //波形函数的值
            float curY;
            for (int i = 0; i <= samplingSize; i++) {
                float x = samplingX[i];
                curY = (float) (amplitude * calcValue(mapX[i], offset));
                for (int n = 0; n < paths.size(); n++) {
                    //四条线分别乘以不同的函数系数
                    float realY = curY * pathFuncs[n] * volume * 0.01f;
                    paths.get(n).lineTo(x, centerHeight + realY);
                }
            }

            //连线至终点
            for (int i = 0; i < paths.size(); i++) {
                paths.get(i).moveTo(width, centerHeight);
            }

            //绘制曲线
            for (int n = 0; n < paths.size(); n++) {

                if (n == 0) {
                    paint.setStrokeWidth(thickLineWidth);
                    paint.setAlpha((int)(255 * alphaInAnim()));
                } else {
                    paint.setStrokeWidth(fineLineWidth);
                    paint.setAlpha((int)(100 * alphaInAnim()));
                }
                canvas.drawPath(paths.get(n), paint);
            }

        }

    }

    //检查音量是否合法
    private void checkVolumeValue(){
        if (targetVolume > 100)targetVolume = 100;
    }

    //检查灵敏度值是否合法
    private void checkSensibilityValue(){
        if (sensibility > 10)sensibility = 10;
        if (sensibility < 1)sensibility = 1;
    }

    /**
     * 使曲线振幅有较大改变时动画过渡自然
     */
    private void softerChangeVolume(){
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Message msg = handler4.obtainMessage(0);
                msg.sendToTarget();
            }
        };
        new Thread(runnable).start();
        //这里减去perVolume是为了防止volume频繁在targetVolume上下抖动
        if (volume < targetVolume - perVolume){
            volume += perVolume;
        }else if (volume > targetVolume + perVolume){
            if (volume < perVolume * 2){
                volume = perVolume * 2;
            }else {
                volume -= perVolume;
            }
        }else {
            volume = targetVolume;
        }

    }

    /**
     * 渐入动画
     * @return progress of animation
     */
    private float alphaInAnim() {
        if (!isOpenPrepareAnim)return 1;
        if (prepareAlpha < 1f){
            prepareAlpha += 0.02f;
        }else {
            prepareAlpha = 1;
        }
        return prepareAlpha;
    }

    /**
     * 连线动画
     * @param canvas
     * @return whether animation is end
     */
    private boolean lineAnim(Canvas canvas) {
        if (isPrepareLineAnimEnd || !isOpenPrepareAnim)return true;
        paths.get(0).moveTo(0, centerHeight);
        paths.get(1).moveTo(width, centerHeight);

        for (int i = 1; i <= samplingSize; i++) {
            float x = i * lineAnimX / samplingSize;
            paths.get(0).lineTo(x, centerHeight);
            paths.get(1).lineTo(width - x, centerHeight);

        }

        paths.get(0).moveTo(width/2, centerHeight);
        paths.get(1).moveTo(width/2, centerHeight);

        lineAnimX += width / 60;
        canvas.drawPath(paths.get(0), paint);
        canvas.drawPath(paths.get(1), paint);

        if (lineAnimX > width / 2){
            isPrepareLineAnimEnd = true;
            return true;
        }
        return false;
    }

    /**
     * 重置path
     */
    private void resetPaths(){
        for (int i = 0; i < paths.size(); i++) {
            paths.get(i).rewind();
            paths.get(i).moveTo(0, centerHeight);
        }
    }

    //初始化参数
    private void initParameters(){
        lineAnimX = 0;
        prepareAlpha = 0f;
        isPrepareLineAnimEnd = false;
        isPrepareAlphaAnimEnd = false;
        samplingX = null;
    }

    @Override
    public void startAnim() {
        initParameters();
        super.startAnim();
    }

    @Override
    public void stopAnim() {
        super.stopAnim();
        clearDraw();
    }

    //清空画布所有内容
    public void clearDraw(){
        Canvas canvas = null;
        try{
            canvas = getHolder().lockCanvas(null);
            canvas.drawColor(backGroundColor);
            resetPaths();
            for (int i=0; i< paths.size(); i++){
                canvas.drawPath(paths.get(i),paint);
            }
        }catch(Exception e){
        }finally{
            if(canvas != null){
                getHolder().unlockCanvasAndPost(canvas);
            }
        }
    }

    //初始化绘制参数
    private void initDraw(Canvas canvas) {

        width = canvas.getWidth();
        height = canvas.getHeight();
        centerHeight = height >> 1;
        //振幅为高度的1/4
            amplitude = height / 3.0f;

            //适合View的理论最大音量值,和音量不属于同一概念
            perVolume = sensibility * 0.35f;

            //初始化采样点及映射
            //这里因为包括起点和终点,所以需要+1
            samplingX = new float[samplingSize + 1];
            mapX = new float[samplingSize + 1];
            //确定采样点之间的间距
            float gap = width / (float) samplingSize;
            //采样点的位置
            float x;
            for (int i = 0; i <= samplingSize; i++) {
                x = i * gap;
                samplingX[i] = x;
                //将采样点映射到[-22]
                mapX[i] = (x / (float) width) * 4 - 2;
            }

            paint.setStyle(Paint.Style.STROKE);
            paint.setColor(lineColor);
            paint.setStrokeWidth(thickLineWidth);
        }

    /**
     * 计算波形函数中x对应的y     *
     * 使用稀疏矩阵进行暂存计算好的衰减系数值,下次使用时直接查找,减少计算量
     * @param mapX   换算到[-2,2]之间的x     * @param offset 偏移量
     * @return [-1, 1]
     */
    private double calcValue(float mapX, float offset) {
        int keyX = (int) (mapX * 1000);
        offset %= 2;
        double sinFunc = Math.sin(Math.PI * mapX - offset * Math.PI);
        double recessionFunc;
        if(recessionFuncs.indexOfKey(keyX) >= 0 ){
            recessionFunc = recessionFuncs.get(keyX);
        }else {
            recessionFunc = 4 / (4 + Math.pow(mapX, 4));
            recessionFuncs.put(keyX,recessionFunc);
        }
        return sinFunc * recessionFunc ;
    }

    /**
     *  the wave line animation move speed from left to right
     *  you can use negative number to make the animation from right to left
     *  the default value is 290F,the smaller, the faster
     * @param moveSpeed
     */
    public void setMoveSpeed(float moveSpeed) {
        this.offsetSpeed = moveSpeed;
    }


    /**
     * User set volume, [0,100]
     * @param volume
     */
    public void setVolume(int volume) {
        if (Math.abs(targetVolume - volume) > perVolume) {
            this.targetVolume = volume;
            checkVolumeValue();
        }
    }

    public void setBackGroundColor(int backGroundColor) {
        this.backGroundColor = backGroundColor;
    }

    public void setLineColor(int lineColor) {
        this.lineColor = lineColor;
    }

    /**
     *  Sensitivity, the bigger the more sensitive [1,10]
     the default value is 5
     * @param sensibility
     */
    public void setSensibility(int sensibility) {
        this.sensibility = sensibility;
        checkSensibilityValue();
    }
    /**
    *每过秒钟增加一次
     */
    Handler handler4 =new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case 0:
                    if(db<60){
                    targetVolume=(int )db-53;
                    }else {
                        targetVolume=(int)db;
                    }
                    break;

            }
        }
    };
    /**
     * 储存录音的办法
     */
    private ArrayList<File> mRecList = new ArrayList<File>();
    private MediaRecorder mRecorder;
    File myfile;
    public void startRecord(){
        mRecorder = new MediaRecorder();
        mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        mRecorder.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);
        myfile=new File(ConfigureFile.getInstance().getAUDIO_FILE_NAME());
        mRecorder.setOutputFile(myfile.getAbsolutePath());
        mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
        try {
            mRecorder.prepare();
        } catch (IOException e) {
            e.printStackTrace();
        }
        mRecorder.start();
        mRecList.add(myfile);
        mice();
    }
    /**
     * 合并录音
     *
     * @param list
     * @return
     */
    private File getOutputVoiceFile(ArrayList<File> list) {
        // 创建音频文件,合并的文件放这里
        File resFile = new File(ConfigureFile.getInstance().getAUDIO_FILE_NAME());
        FileOutputStream fileOutputStream = null;

        if (!resFile.exists()) {
            try {
                resFile.createNewFile();
            } catch (IOException e) {
            }
        }
        try {
            fileOutputStream = new FileOutputStream(resFile);
        } catch (IOException e) {
        }
        // list里面为暂停录音 所产生的 几段录音文件的名字,中间几段文件的减去前面的6个字节头文件
        for (int i = 0; i < list.size(); i++) {
            File file = list.get(i);
            try {
                FileInputStream fileInputStream = new FileInputStream(file);
                byte[] myByte = new byte[fileInputStream.available()];
                // 文件长度
                int length = myByte.length;
                // 头文件
                if (i == 0) {
                    while (fileInputStream.read(myByte) != -1) {
                        fileOutputStream.write(myByte, 0, length);
                    }
                }
                // 之后的文件,去掉头文件就可以了
                else {
                    while (fileInputStream.read(myByte) != -1) {
                        fileOutputStream.write(myByte, 6, length - 6);
                    }
                }
                fileOutputStream.flush();
                fileInputStream.close();
                file.delete();//删除文件
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        // 结束后关闭流
        try {
            fileOutputStream.close();
        } catch (IOException e) {
        }

        return resFile;
    }


    /**
     * 停止录音
     */

    public void stopRecord(){
        mRecorder.stop();
        File file=getOutputVoiceFile(mRecList);
        String str=myfile.getName();
        file.renameTo(myfile);
        mRecorder.setOutputFile(file.getAbsolutePath());
        mRecorder.release();
        mRecorder = null;
    }
    /**
     * 暂停录音方法
     */
    public void puuRecord(){
        mRecorder.stop();
        mRecorder.release();
        mRecorder = null;
        }
    /**
     * 获取录音分贝的值储存到链表
     */
    public void mice(){
        Runnable runnable=new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(120);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Message msg=handler2.obtainMessage(0);
                msg.sendToTarget();
            }
        };
        new Thread(runnable).start();
    }
    Handler handler2=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case 0:
                    if (mRecorder != null) {
                        double ratio = (double) mRecorder.getMaxAmplitude() / BASE;
                        db = 0;// 分贝
                        if (ratio > 1)
                            db = 20 * Math.log10(ratio);
                        mice();
                    }
                    break;
            }
        }
    };
    public double db=0;
}
上代码4:
package com.example.launcherexploit.Shr;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.example.launcherexploit.R;

public class shr_Record extends AppCompatActivity {

    private WaveLineView waveLineView;
    private int sinniet=0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.shr_record);
        waveLineView = (WaveLineView) findViewById(R.id.waveLineView);

        findViewById(R.id.startBtn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(recordopen==1){
                    recordopen=0;
                }
                if(recordopen==0){
                waveLineView.startAnim();
               waveLineView.startRecord();
                button = (Button) findViewById(R.id.startBtn);
                button.setVisibility(View.GONE);
                button1= (Button) findViewById(R.id.poullBtn);
                button1.setVisibility(View.VISIBLE);
                textView= (TextView) findViewById(R.id.recordtext);
                textView.setText("录音中...");
                recordtexttime=true;
                recordtimetext();
                    recordopen=1;
                    sinniet=1;
                }
            }
        });

        findViewById(R.id.stopBtn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (recordopen==1&&sinniet==1){
                    recordtexttime=false;
                    button = (Button) findViewById(R.id.startBtn);
                    button.setVisibility(View.VISIBLE);
                    button1= (Button) findViewById(R.id.poullBtn);
                    button1.setVisibility(View.GONE);
                    textView= (TextView) findViewById(R.id.recordtext);
                    textView.setText("准备录音");
                    textView= (TextView) findViewById(R.id.recordtimetext);
                    textView.setText("0"+":00"+":00");
                    pows=0;
                    mist=0;
                    miss=-1;
                    recordopen=0;
                    waveLineView.stopAnim();
                    waveLineView.stopRecord();
                    Toast.makeText(shr_Record.this,"文件已保存",Toast.LENGTH_LONG).show();
            }else if(recordopen==1&&sinniet==3){
                    waveLineView.startRecord();
                    recordtexttime=false;
                    button = (Button) findViewById(R.id.startBtn);
                    button.setVisibility(View.VISIBLE);
                    button1= (Button) findViewById(R.id.poullBtn);
                    button1.setVisibility(View.GONE);
                    textView= (TextView) findViewById(R.id.recordtext);
                    textView.setText("准备录音");
                    textView= (TextView) findViewById(R.id.recordtimetext);
                    textView.setText("0"+":00"+":00");
                    pows=0;
                    mist=0;
                    miss=-1;
                    recordopen=1;
                    waveLineView.stopRecord();
                    Toast.makeText(shr_Record.this,"文件已保存",Toast.LENGTH_LONG).show();
                }
            }
        });
        findViewById(R.id.poullBtn).setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View view) {
                button = (Button) findViewById(R.id.startBtn);
                button.setVisibility(View.VISIBLE);
                button1= (Button) findViewById(R.id.poullBtn);
                button1.setVisibility(View.GONE);
                textView= (TextView) findViewById(R.id.recordtext);
                textView.setText("暂停录音");
                waveLineView.puuRecord();
                recordopen=1;
                sinniet=3;
                waveLineView.stopAnim();
                recordtexttime=false;
            }
        });
    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        if (hasFocus){
//            waveLineView.justDrawBackground();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        waveLineView.onResume();

    }

    @Override
    protected void onPause() {
        super.onPause();
        waveLineView.onPause();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        waveLineView.release();
    }

    /**
     * 点击录音按钮文字改变
     */
    public TextView textView;
    public int  recordopen=0;

    /**
     * 点击录音按钮开始计时
     */
    public boolean recordtexttime=true;//判断时间是否停止
    public void recordtimetext(){
        Runnable runnable=new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Message message=handler.obtainMessage(0);
                message.sendToTarget();
            }
        };
        if (recordtexttime){
        new Thread(runnable).start();
        }
    }
    int pows=0;
    int mist=0;
    int miss=0;
    Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case 0:
                    if(miss<=60){
                    miss++;
                        if (miss==60){
                            mist++;
                            miss=0;
                            if(mist==60){
                                mist=0;
                                pows++;
                            }
                        }
                    }
                    if (miss<10&&mist<10){
                    textView= (TextView) findViewById(R.id.recordtimetext);
                    textView.setText(""+pows+":0"+mist+":0"+miss);
                    }else if (miss>=10&&mist<10) {
                        textView= (TextView) findViewById(R.id.recordtimetext);
                        textView.setText(""+pows+":0"+mist+":"+miss);
                    }else if (miss<10&&mist>=10){
                        textView= (TextView) findViewById(R.id.recordtimetext);
                        textView.setText(""+pows+":"+mist+":0"+miss);
                    }else if (miss>=10&&mist>=10){
                        textView= (TextView) findViewById(R.id.recordtimetext);
                        textView.setText(""+pows+":"+mist+":"+miss);
                    }
                    recordtimetext();
                    break;
            }
        }
    };

    /**
     * 点击按钮转换按钮形式
     */
    public Button button;
    public Button button1;
    public boolean buttontrue_flas=true;

}
上代码5:
package com.example.launcherexploit.Shr;

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import java.lang.ref.WeakReference;
import java.util.List;

public abstract class RenderView extends SurfaceView implements SurfaceHolder.Callback {

    //是否正在绘制动画
    private boolean isStartAnim = false;
    private final static Object surfaceLock = new Object();
    private RenderThread renderThread;
    /**
     * 绘制背景,防止开始时黑屏
     * View可以执行此方法
     * @param canvas
     */
    protected abstract void doDrawBackground(Canvas canvas);
    /**
     * 渲染surfaceView的回调方法。
     *
     * @param canvas 画布
     */
    protected abstract void onRender(Canvas canvas, long millisPassed);

    public RenderView(Context context) {
        this(context, null);
    }

    public RenderView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RenderView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        getHolder().addCallback(this);
    }


    /*回调/线程*/
    private static class RenderThread extends Thread {

        private static final long SLEEP_TIME = 16;
        private WeakReference<RenderView> renderView;
        private boolean running = false;
        private boolean destoryed = false;
        private boolean isPause = false;
        public RenderThread(RenderView renderView) {
            super("RenderThread");
            this.renderView = new WeakReference<>(renderView);
        }

        private SurfaceHolder getSurfaceHolder(){
            if (getRenderView() != null ){
                return getRenderView().getHolder();
            }
            return null;
        }

        private RenderView getRenderView(){
            return renderView.get();
        }

        @Override
        public void run() {
            long startAt = System.currentTimeMillis();
            while (!destoryed) {
                synchronized (surfaceLock) {

                    //这里并没有真正的结束Thread,防止部分手机连续调用同一Thread出错
                    while (isPause){
                        try {
                            surfaceLock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }

                    if (running) {
                        if (getSurfaceHolder() != null && getRenderView() != null) {
                            Canvas canvas = getSurfaceHolder().lockCanvas();
                            if (canvas != null) {
                                getRenderView().doDrawBackground(canvas);
                                if (getRenderView().isStartAnim) {
                                    getRenderView().render(canvas, System.currentTimeMillis() - startAt);  //这里做真正绘制的事情
                                }
                                getSurfaceHolder().unlockCanvasAndPost(canvas);
                            }
                        }else {
                            running = false;
                        }

                    }

                }
                try {
                    Thread.sleep(SLEEP_TIME);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }

        }


        public void setRun(boolean isRun) {
            this.running = isRun;
        }

    }



    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        renderer = onCreateRenderer();
        if (renderer != null && renderer.isEmpty()) {
            throw new IllegalStateException();
        }

        renderThread = new RenderThread(this);
    }

    /**
     * 解锁暂停,继续执行绘制任务
     * 默认当Resume时不自动启动动画
     */
    public void onResume(){
        synchronized (surfaceLock){
            if (renderThread != null) {
                renderThread.isPause = false;
                surfaceLock.notifyAll();
            }
        }
    }


    //假暂停,并没有结束Thread
    public void onPause(){
        synchronized (surfaceLock){
            if (renderThread != null) {
                renderThread.isPause = true;
            }
        }
    }


    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        //这里可以获取SurfaceView的宽高等信息
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        synchronized (surfaceLock) {  //这里需要加锁,否则doDraw中有可能会crash
            renderThread.setRun(false);
            renderThread.destoryed = true;
        }
    }

    public void onWindowFocusChanged(boolean hasFocus) {
        if (hasFocus && isStartAnim){
            startAnim();
        }else {
            startThread();
        }
    }

    /*绘图*/
    public interface IRenderer {
        void onRender(Canvas canvas, long millisPassed);
    }

    private List<IRenderer> renderer;

    protected List<IRenderer> onCreateRenderer() {
        return null;
    }

    private void render(Canvas canvas, long millisPassed) {
        if (renderer != null) {
            for (int i = 0, size = renderer.size(); i < size; i++) {
                renderer.get(i).onRender(canvas, millisPassed);
            }
        } else {
            onRender(canvas, millisPassed);
        }
    }

    public void startAnim(){
        isStartAnim = true;
        startThread();
    }

    private void startThread(){

        if (renderThread != null && !renderThread.running) {
            renderThread.setRun(true);
            try {
                if (renderThread.getState() == Thread.State.NEW) {
                    renderThread.start();
                }

            }catch (RuntimeException e){
                e.printStackTrace();
            }

        }
    }

    public void stopAnim(){
        isStartAnim = false;
        if (renderThread != null && renderThread.running) {
            renderThread.setRun(false);
            renderThread.interrupt();
        }
    }

    public boolean isRunning(){
        if (renderThread != null) {
            return renderThread.running;
        }
        return false;
    }

    //释放相关资源,防止内存泄漏
    public void release(){
        if (getHolder() != null && getHolder().getSurface() != null) {
            getHolder().getSurface().release();
            getHolder().removeCallback(this);
        }
    }

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值