自己整理的用法新的,和更改,以适合自己用:
自己运用
上代码:
这几个很重要:更改,自己定义;
要在文件夹添加:
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; //将采样点映射到[-2,2] 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); } } }