Android實(shí)現(xiàn)錄音聲波圖
本文實(shí)例為大家分享了Android實(shí)現(xiàn)錄音聲波圖的具體代碼,供大家參考,具體內(nèi)容如下
圖像類:
package com.akm.test; /** ?* Created by toge on 15/12/9. ?*/ import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; import android.view.SurfaceView; import java.util.LinkedList; /** ?* A view that displays audio data on the screen as a waveform. ?*/ public class WaveformView extends SurfaceView { ? ? // The number of buffer frames to keep around (for a nice fade-out visualization). ? ? private static final int HISTORY_SIZE = 6; ? ? // To make quieter sounds still show up well on the display, we use +/- 8192 as the amplitude ? ? // that reaches the top/bottom of the view instead of +/- 32767. Any samples that have ? ? // magnitude higher than this limit will simply be clipped during drawing. ? ? private static final float MAX_AMPLITUDE_TO_DRAW = 8192.0f; ? ? // The queue that will hold historical audio data. ? ? private final LinkedList<short[]> mAudioData; ? ? private final Paint mPaint; ? ? public WaveformView(Context context) { ? ? ? ? this(context, null, 0); ? ? } ? ? public WaveformView(Context context, AttributeSet attrs) { ? ? ? ? this(context, attrs, 0); ? ? } ? ? public WaveformView(Context context, AttributeSet attrs, int defStyle) { ? ? ? ? super(context, attrs, defStyle); ? ? ? ? mAudioData = new LinkedList<short[]>(); ? ? ? ? mPaint = new Paint(); ? ? ? ? mPaint.setStyle(Paint.Style.STROKE); ? ? ? ? mPaint.setColor(Color.WHITE); ? ? ? ? mPaint.setStrokeWidth(0); ? ? ? ? mPaint.setAntiAlias(true); ? ? } ? ? /** ? ? ?* Updates the waveform view with a new "frame" of samples and renders it. The new frame gets ? ? ?* added to the front of the rendering queue, pushing the previous frames back, causing them to ? ? ?* be faded out visually. ? ? ?* ? ? ?* @param buffer the most recent buffer of audio samples ? ? ?*/ ? ? public synchronized void updateAudioData(short[] buffer) { ? ? ? ? short[] newBuffer; ? ? ? ? // We want to keep a small amount of history in the view to provide a nice fading effect. ? ? ? ? // We use a linked list that we treat as a queue for this. ? ? ? ? if (mAudioData.size() == HISTORY_SIZE) { ? ? ? ? ? ? newBuffer = mAudioData.removeFirst(); ? ? ? ? ? ? System.arraycopy(buffer, 0, newBuffer, 0, buffer.length); ? ? ? ? } else { ? ? ? ? ? ? newBuffer = buffer.clone(); ? ? ? ? } ? ? ? ? mAudioData.addLast(newBuffer); ? ? ? ? // Update the display. ? ? ? ? Canvas canvas = getHolder().lockCanvas(); ? ? ? ? if (canvas != null) { ? ? ? ? ? ? drawWaveform(canvas); ? ? ? ? ? ? getHolder().unlockCanvasAndPost(canvas); ? ? ? ? } ? ? } ? ? /** ? ? ?* Repaints the view's surface. ? ? ?* ? ? ?* @param canvas the {@link Canvas} object on which to draw ? ? ?*/ ? ? private void drawWaveform(Canvas canvas) { ? ? ? ? // Clear the screen each time because SurfaceView won't do this for us. ? ? ? ? canvas.drawColor(Color.BLACK); ? ? ? ? float width = getWidth(); ? ? ? ? float height = getHeight(); ? ? ? ? float centerY = height / 2; ? ? ? ? // We draw the history from oldest to newest so that the older audio data is further back ? ? ? ? // and darker than the most recent data. ? ? ? ? int colorDelta = 255 / (HISTORY_SIZE + 1); ? ? ? ? int brightness = colorDelta; ? ? ? ? for (short[] buffer : mAudioData) { ? ? ? ? ? ? mPaint.setColor(Color.argb(brightness, 128, 255, 192)); ? ? ? ? ? ? float lastX = -1; ? ? ? ? ? ? float lastY = -1; ? ? ? ? ? ? // For efficiency, we don't draw all of the samples in the buffer, but only the ones ? ? ? ? ? ? // that align with pixel boundaries. ? ? ? ? ? ? for (int x = 0; x < width; x++) { ? ? ? ? ? ? ? ? int index = (int) ((x / width) * buffer.length); ? ? ? ? ? ? ? ? short sample = buffer[index]; ? ? ? ? ? ? ? ? float y = (sample / MAX_AMPLITUDE_TO_DRAW) * centerY + centerY; ? ? ? ? ? ? ? ? if (lastX != -1) { ? ? ? ? ? ? ? ? ? ? canvas.drawLine(lastX, lastY, x, y, mPaint); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? lastX = x; ? ? ? ? ? ? ? ? lastY = y; ? ? ? ? ? ? } ? ? ? ? ? ? brightness += colorDelta; ? ? ? ? } ? ? } }
頭文件:
/* ?* Copyright (C) 2015 Google Inc. ?* ?* Licensed under the Apache License, Version 2.0 (the "License"); ?* you may not use this file except in compliance with the License. ?* You may obtain a copy of the License at ?* ?* ? ? ?http://www.apache.org/licenses/LICENSE-2.0 ?* ?* Unless required by applicable law or agreed to in writing, software ?* distributed under the License is distributed on an "AS IS" BASIS, ?* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ?* See the License for the specific language governing permissions and ?* limitations under the License. ?*/ package com.akm.test; import java.io.FileOutputStream; import java.io.IOException; /** ?* Created by Akm at 15/12/1 上午10:07 ?* 文件制作 ?*/ public class WAVHeader { ? ? private byte[] mHeader; ? ? ? ? ?// the complete header. ? ? private int mSampleRate; ? ? ? ? // sampling frequency in Hz (e.g. 44100). ? ? private int mChannels; ? ? ? ? ? // number of channels. ? ? private int mNumSamples; ? ? ? ? // total number of samples per channel. ? ? private int mNumBytesPerSample; ?// number of bytes per sample, all channels included. ? ? public WAVHeader(int sampleRate, int numChannels, int numSamples) { ? ? ? ? mSampleRate = sampleRate; ? ? ? ? mChannels = numChannels; ? ? ? ? mNumSamples = numSamples; ? ? ? ? mNumBytesPerSample = 2 * mChannels; ?// assuming 2 bytes per sample (for 1 channel) ? ? ? ? mHeader = null; ? ? ? ? setHeader(); ? ? } ? ? public byte[] getWAVHeader() { ? ? ? ? return mHeader; ? ? } ? ? public static byte[] getWAVHeader(int sampleRate, int numChannels, int numSamples) { ? ? ? ? return new WAVHeader(sampleRate, numChannels, numSamples).mHeader; ? ? } ? ? public String toString() { ? ? ? ? String str = ""; ? ? ? ? if (mHeader == null) { ? ? ? ? ? ? return str; ? ? ? ? } ? ? ? ? int num_32bits_per_lines = 8; ? ? ? ? int count = 0; ? ? ? ? for (byte b : mHeader) { ? ? ? ? ? ? boolean break_line = count > 0 && count % (num_32bits_per_lines * 4) == 0; ? ? ? ? ? ? boolean insert_space = count > 0 && count % 4 == 0 && !break_line; ? ? ? ? ? ? if (break_line) { ? ? ? ? ? ? ? ? str += '\n'; ? ? ? ? ? ? } ? ? ? ? ? ? if (insert_space) { ? ? ? ? ? ? ? ? str += ' '; ? ? ? ? ? ? } ? ? ? ? ? ? str += String.format("%02X", b); ? ? ? ? ? ? count++; ? ? ? ? } ? ? ? ? return str; ? ? } ? ? private void setHeader() { ? ? ? ? byte[] header = new byte[46]; ? ? ? ? int offset = 0; ? ? ? ? int size; ? ? ? ? // set the RIFF chunk ? ? ? ? System.arraycopy(new byte[]{'R', 'I', 'F', 'F'}, 0, header, offset, 4); ? ? ? ? offset += 4; ? ? ? ? size = 36 + mNumSamples * mNumBytesPerSample; ? ? ? ? header[offset++] = (byte) (size & 0xFF); ? ? ? ? header[offset++] = (byte) ((size >> 8) & 0xFF); ? ? ? ? header[offset++] = (byte) ((size >> 16) & 0xFF); ? ? ? ? header[offset++] = (byte) ((size >> 24) & 0xFF); ? ? ? ? System.arraycopy(new byte[]{'W', 'A', 'V', 'E'}, 0, header, offset, 4); ? ? ? ? offset += 4; ? ? ? ? // set the fmt chunk ? ? ? ? System.arraycopy(new byte[]{'f', 'm', 't', ' '}, 0, header, offset, 4); ? ? ? ? offset += 4; ? ? ? ? System.arraycopy(new byte[]{0x10, 0, 0, 0}, 0, header, offset, 4); ?// chunk size = 16 ? ? ? ? offset += 4; ? ? ? ? System.arraycopy(new byte[]{1, 0}, 0, header, offset, 2); ?// format = 1 for PCM ? ? ? ? offset += 2; ? ? ? ? header[offset++] = (byte) (mChannels & 0xFF); ? ? ? ? header[offset++] = (byte) ((mChannels >> 8) & 0xFF); ? ? ? ? header[offset++] = (byte) (mSampleRate & 0xFF); ? ? ? ? header[offset++] = (byte) ((mSampleRate >> 8) & 0xFF); ? ? ? ? header[offset++] = (byte) ((mSampleRate >> 16) & 0xFF); ? ? ? ? header[offset++] = (byte) ((mSampleRate >> 24) & 0xFF); ? ? ? ? int byteRate = mSampleRate * mNumBytesPerSample; ? ? ? ? header[offset++] = (byte) (byteRate & 0xFF); ? ? ? ? header[offset++] = (byte) ((byteRate >> 8) & 0xFF); ? ? ? ? header[offset++] = (byte) ((byteRate >> 16) & 0xFF); ? ? ? ? header[offset++] = (byte) ((byteRate >> 24) & 0xFF); ? ? ? ? header[offset++] = (byte) (mNumBytesPerSample & 0xFF); ? ? ? ? header[offset++] = (byte) ((mNumBytesPerSample >> 8) & 0xFF); ? ? ? ? System.arraycopy(new byte[]{0x10, 0}, 0, header, offset, 2); ? ? ? ? offset += 2; ? ? ? ? // set the beginning of the data chunk ? ? ? ? System.arraycopy(new byte[]{'d', 'a', 't', 'a'}, 0, header, offset, 4); ? ? ? ? offset += 4; ? ? ? ? size = mNumSamples * mNumBytesPerSample; ? ? ? ? header[offset++] = (byte) (size & 0xFF); ? ? ? ? header[offset++] = (byte) ((size >> 8) & 0xFF); ? ? ? ? header[offset++] = (byte) ((size >> 16) & 0xFF); ? ? ? ? header[offset++] = (byte) ((size >> 24) & 0xFF); ? ? ? ? mHeader = header; ? ? } ? ? public static byte[] getHeader( ?long totalAudioLen, ? ? ? ? ? ? ? ? ? ? ? ? ? ? long totalDataLen, long longSampleRate, int channels, long byteRate) throws IOException { ? ? ? ? byte[] header = new byte[44]; ? ? ? ? header[0] = 'R'; // RIFF/WAVE header ? ? ? ? header[1] = 'I'; ? ? ? ? header[2] = 'F'; ? ? ? ? header[3] = 'F'; ? ? ? ? header[4] = (byte) (totalDataLen & 0xff); ? ? ? ? header[5] = (byte) ((totalDataLen >> 8) & 0xff); ? ? ? ? header[6] = (byte) ((totalDataLen >> 16) & 0xff); ? ? ? ? header[7] = (byte) ((totalDataLen >> 24) & 0xff); ? ? ? ? header[8] = 'W'; ? ? ? ? header[9] = 'A'; ? ? ? ? header[10] = 'V'; ? ? ? ? header[11] = 'E'; ? ? ? ? header[12] = 'f'; // 'fmt ' chunk ? ? ? ? header[13] = 'm'; ? ? ? ? header[14] = 't'; ? ? ? ? header[15] = ' '; ? ? ? ? header[16] = 16; // 4 bytes: size of 'fmt ' chunk ? ? ? ? header[17] = 0; ? ? ? ? header[18] = 0; ? ? ? ? header[19] = 0; ? ? ? ? header[20] = 1; // format = 1 ? ? ? ? header[21] = 0; ? ? ? ? header[22] = (byte) channels; ? ? ? ? header[23] = 0; ? ? ? ? header[24] = (byte) (longSampleRate & 0xff); ? ? ? ? header[25] = (byte) ((longSampleRate >> 8) & 0xff); ? ? ? ? header[26] = (byte) ((longSampleRate >> 16) & 0xff); ? ? ? ? header[27] = (byte) ((longSampleRate >> 24) & 0xff); ? ? ? ? header[28] = (byte) (byteRate & 0xff); ? ? ? ? header[29] = (byte) ((byteRate >> 8) & 0xff); ? ? ? ? header[30] = (byte) ((byteRate >> 16) & 0xff); ? ? ? ? header[31] = (byte) ((byteRate >> 24) & 0xff); ? ? ? ? header[32] = (byte) (2 * 16 / 8); // block align ? ? ? ? header[33] = 0; ? ? ? ? header[34] = 16; // bits per sample ? ? ? ? header[35] = 0; ? ? ? ? header[36] = 'd'; ? ? ? ? header[37] = 'a'; ? ? ? ? header[38] = 't'; ? ? ? ? header[39] = 'a'; ? ? ? ? header[40] = (byte) (totalAudioLen & 0xff); ? ? ? ? header[41] = (byte) ((totalAudioLen >> 8) & 0xff); ? ? ? ? header[42] = (byte) ((totalAudioLen >> 16) & 0xff); ? ? ? ? header[43] = (byte) ((totalAudioLen >> 24) & 0xff); ? ? ? ? return header; ? ? } }
測(cè)試:
package com.akm.test; import android.app.Activity; import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioRecord; import android.media.AudioTrack; import android.media.MediaPlayer; import android.media.MediaRecorder; import android.os.Bundle; import android.os.Environment; import android.os.Message; import android.os.SystemClock; import android.util.DisplayMetrics; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.Chronometer; import android.widget.SeekBar; import android.widget.TextView; import com.ringdroid.R; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.ShortBuffer; import java.nio.channels.FileChannel; /** ?* Created by toge on 15/11/30. ?*/ public class Test extends Activity implements View.OnClickListener { ? ? WaveformView waveformView; ? ? private Button btnStart; ? ? private Button btnStop; ? ? private String filePath; ? ? private boolean mRecordingKeepGoing; ? ? private SoundFile soundFile; ? ? private RandomAccessFile randomAccessFile; ? ? private int totalLength;//總長(zhǎng) ? ? private int duration;//時(shí)長(zhǎng) ? ? private int rate;//采樣率 ? ? private int channelConfig;//聲道 ? ? private int samples; ? ? private int startPos; ? ? private int bufferSize;//緩沖區(qū)大小 ? ? private int minBufferSize;//最小緩沖區(qū) ? ? private AudioRecord audioRecord; ? ? private AudioTrack audioTrack; ? ? private boolean mThreadFlag; ? ? private int i; ? ? private int j; ? ? private int STATUS = 1; ? ? private int STATUS_PAUSE = 2; ? ? private int STATUS_PREPARED = 1; ? ? private int STATUS_RECORDING = 1; ? ? private Thread audioTrackThread; ? ? private Thread thread; ? ? private int endPos; ? ? private int curFileLength; ? ? OnFileChangedListener onFileChangedListener; ? ? private boolean isRewrite; ? ? private boolean audioTrackFlag; ? ? private int frequency = 22050;//22050; ? ? private int recBufSize; ? ? private String outPath; ? ? private byte[] bytes; ? ? private int time; ? ? private Button btnPasue; ? ? private Button btnPlay; ? ? private Button btnPlay2; ? ? private long startTime; ? ? private long restOfTime; ? ? private int audioFormat;//采集 ? ? private int bufferSizeInBytes;//緩沖區(qū)大小 ? ? private Button btnSave; ? ? // ? ?private ByteBuffer mDecodedBytes; // ? ?private ByteBuffer mDecodedSamples; ? ? private byte[] sampleBytes; ? ? private MediaPlayer mediaPlayer; ? ? private SeekBar seekBar; ? ? private android.os.Handler handler = new android.os.Handler(); ? ? Runnable updateThread = new Runnable() { ? ? ? ? public void run() { ? ? ? ? ? ? // 獲得歌曲現(xiàn)在播放位置并設(shè)置成播放進(jìn)度條的值 ? ? ? ? ? ? if (mediaPlayer != null) { ? ? ? ? ? ? ? ? seekBar.setProgress(mediaPlayer.getCurrentPosition()); ? ? ? ? ? ? ? ? Log.e("Test", "run------ updateThread:getCurrentPosition " + mediaPlayer.getCurrentPosition()); ? ? ? ? ? ? ? ? // 每次延遲100毫秒再啟動(dòng)線程 ? ? ? ? ? ? ? ? handler.postDelayed(updateThread, 100); ? ? ? ? ? ? } ? ? ? ? } ? ? }; ? ? private Chronometer et_time; ? ? private long falgTime; ? ? private long pauseTime; ? ? private long subtime; ? ? private long beginTime; ? ? private TextView currentTime; ? ? private int currentProgress; ? ? @Override ? ? protected void onCreate(Bundle savedInstanceState) { ? ? ? ? super.onCreate(savedInstanceState); ? ? ? ? setContentView(R.layout.test); ? ? ? ? waveformView = (WaveformView) findViewById(R.id.waveform); ? ? ? ? btnStart = (Button) findViewById(R.id.button_start); ? ? ? ? btnPasue = (Button) findViewById(R.id.button_pasue); ? ? ? ? btnStop = (Button) findViewById(R.id.button2_stop); ? ? ? ? btnPlay = (Button) findViewById(R.id.button_play); ? ? ? ? btnPlay2 = (Button) findViewById(R.id.button_play2); ? ? ? ? btnSave = (Button) findViewById(R.id.button_save); ? ? ? ? seekBar = (SeekBar) findViewById(R.id.sb); ? ? ? ? et_time = (Chronometer) this.findViewById(R.id.et_time); ? ? ? ? currentTime = (TextView) this.findViewById(R.id.currentTime); ? ? ? ? btnStart.setOnClickListener(this); ? ? ? ? btnPasue.setOnClickListener(this); ? ? ? ? btnStop.setOnClickListener(this); ? ? ? ? btnPlay.setOnClickListener(this); ? ? ? ? btnPlay2.setOnClickListener(this); ? ? ? ? btnSave.setOnClickListener(this); ? ? ? ? initPar(); ? ? ? ? initRecorder(true); ? ? ? ? initAudioTack(); ? ? } ? ? @Override ? ? protected void onResume() { ? ? ? ? super.onResume(); ? ? ? ? initRecorder(false); ? ? } ? ? private void initAudioTack() { ? ? ? ? minBufferSize = AudioTrack.getMinBufferSize(rate, 3, audioFormat); ? ? ? ? Log.e("Test", "initAudioTack------ minBufferSize:" + minBufferSize); ? ? ? ? audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, rate, 1, audioFormat, minBufferSize, AudioTrack.MODE_STREAM); ? ? } ? ? private void initPar() { ? ? ? ? duration = 60 * 1000;//毫秒 ? ? ? ? rate = 44100;//聲卡一般提供11.025kHz、22.05kHz和44.1kHz等不同的采樣頻率 ? ? ? ? channelConfig = AudioFormat.CHANNEL_IN_DEFAULT; ? ? ? ? audioFormat = AudioFormat.ENCODING_PCM_16BIT; ? ? ? ? restOfTime = duration; ? ? } ? ? private void initRecorder(boolean isNew) { ? ? ? ? initAudioFile(isNew); ? ? ? ? bufferSize = AudioRecord.getMinBufferSize(rate, channelConfig, audioFormat); ? ? ? ? Log.d("Test", "initRecorder: bufferSize:" + bufferSize);//44100 1 2 = v fc // ? ? ? ?int k = audioFormat * rate / 25; // ? ? ? ?if (bufferSize % k != 0) { // ? ? ? ? ? ?bufferSize = (k * (channelConfig + bufferSize / k)); // ? ? ? ?} ? ? ? ? audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, rate, channelConfig, audioFormat, bufferSize); ? ? } ? ? public boolean isRecording() { ? ? ? ? return audioRecord.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING; ? ? } ? ? private void initAudioFile(boolean isNew) { ? ? ? ? filePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/akm/t.wav"; ? ? ? ? new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/akm").mkdir(); ? ? ? ? File f = new File(filePath); ? ? ? ? try { ? ? ? ? ? ? if (f.exists() && isNew) { ? ? ? ? ? ? ? ? f.delete(); ? ? ? ? ? ? } ? ? ? ? ? ? randomAccessFile = new RandomAccessFile(filePath, "rw"); ? ? ? ? ? ? //文件長(zhǎng)度 = 比特率*時(shí)間 ? ? ? ? ? ? //= 采樣率*位數(shù)*聲道 / 8 ? ? ? ? ? ? totalLength = (rate * 1 * 16 / 8) * (duration / 1000); // ? ? ? ? ? ?totalLength = (int) (4l * (duration * rate / 1000l)); ? ? ? ? ? ? createWaveFile(randomAccessFile, true, totalLength); ? ? ? ? ? ? totalLength = 44 + totalLength; ? ? ? ? ? ? randomAccessFile = new RandomAccessFile(filePath, "rw"); ? ? ? ? } catch (Exception e) { ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? } ? ? } ? ? private void createWaveFile(RandomAccessFile randomAccessFile, boolean b, int totalLength) { ? ? ? ? if (b) { ? ? ? ? ? ? try { // ? ? ? ? ? ? ? ?randomAccessFile.write(WAVHeader.getHeader(rate,channels,samples)); ? ? ? ? ? ? ? ? // long totalAudioLen,long totalDataLen, long longSampleRate, int channels, long byteRate ? ? ? ? ? ? ? ? //數(shù)據(jù)長(zhǎng)度 文件長(zhǎng)度 采樣率 聲道 比特率 ? ? ? ? ? ? ? ? //比特率(字節(jié)/秒)= (采樣頻率(Hz)× 采樣位數(shù)(bit) × 聲道數(shù))/ 8 ? ? ? ? ? ? ? ? // ? ? ? ? ? ? ? ? long byteRate = (channelConfig * audioFormat * rate) / 8; ? ? ? ? ? ? ? ? byte[] bytes = WAVHeader.getHeader(totalLength - 36l, totalLength, rate, channelConfig, byteRate); ? ? ? ? ? ? ? ? FileChannel localFileChannel = randomAccessFile.getChannel(); ? ? ? ? ? ? ? ? localFileChannel.map(FileChannel.MapMode.READ_WRITE, 0l, 44l).put(bytes); ? ? ? ? ? ? ? ? localFileChannel.close(); ? ? ? ? ? ? ? ? Log.e("Test", "createWaveFile------ OK "); ? ? ? ? ? ? } catch (IOException e) { ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? } ? ? ? ? } ? ? } ? ? @Override ? ? public void onClick(View view) { ? ? ? ? switch (view.getId()) { ? ? ? ? ? ? case R.id.button_start: ? ? ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? ? ? mRecordingKeepGoing = true; ? ? ? ? ? ? ? ? ? ? new Thread() { ? ? ? ? ? ? ? ? ? ? ? ? @Override ? ? ? ? ? ? ? ? ? ? ? ? public void run() { ? ? ? ? ? ? ? ? ? ? ? ? ? ? startRecording(); ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? }.start(); ? ? ? ? ? ? ? ? } catch (Exception e) { ? ? ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? case R.id.button_pasue: ? ? ? ? ? ? ? ? mRecordingKeepGoing = false; ? ? ? ? ? ? ? ? pauseRecord(); ? ? ? ? ? ? ? ? try {//暫停后,設(shè)置文件索引為末尾 ? ? ? ? ? ? ? ? ? ? startPos = (int) randomAccessFile.getFilePointer(); ? ? ? ? ? ? ? ? } catch (IOException e) { ? ? ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? pausePlay(); ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? case R.id.button_play: ? ? ? ? ? ? ? ? startReview(true); ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? case R.id.button2_stop: ? ? ? ? ? ? ? ? mRecordingKeepGoing = false; ? ? ? ? ? ? ? ? stopRecord(); ? ? ? ? ? ? ? ? stopPlay(); ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? case R.id.button_save: ? ? ? ? ? ? ? ? startPos = currentProgress; ? ? ? ? ? ? ? ? if (randomAccessFile==null){ ? ? ? ? ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? ? ? ? ? randomAccessFile = new RandomAccessFile(filePath, "rw"); ? ? ? ? ? ? ? ? ? ? } catch (IOException e) { ? ? ? ? ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? ? ? Log.e("Test", "onClick: pos" + randomAccessFile.getFilePointer()); ? ? ? ? ? ? ? ? ? ? int size = ((rate * 1 * 16 / 8) * (currentProgress / 1000)); ? ? ? ? ? ? ? ? ? ? Log.e("Test", "onClick------ size "+size); ? ? ? ? ? ? ? ? ? ? if (size<44){ ? ? ? ? ? ? ? ? ? ? ? ? size = 44; ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? randomAccessFile.seek(size); ? ? ? ? ? ? ? ? ? ? randomAccessFile.write(sampleBytes); ? ? ? ? ? ? ? ? ? ? randomAccessFile.close(); ? ? ? ? ? ? ? ? } catch (IOException e) { ? ? ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? Log.e("Test", "onClick------pos "+currentProgress); ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? case R.id.button_play2: ? ? ? ? ? ? ? ? play(); ? ? ? ? ? ? ? ? break; ? ? ? ? } ? ? } ? ? private void pausePlay() { ? ? ? ? if (mediaPlayer != null && mediaPlayer.isPlaying()) { ? ? ? ? ? ? // 暫停音樂(lè)播放器 ? ? ? ? ? ? mediaPlayer.pause(); ? ? ? ? ? ? btnPasue.setText("續(xù)播"); ? ? ? ? ? ? seekBar.setEnabled(false); ? ? ? ? ? ? et_time.stop(); ? ? ? ? ? ? pauseTime = SystemClock.elapsedRealtime(); ? ? ? ? ? ? // System.out.println("1 pauseTime" + pauseTime); ? ? ? ? } else if (mediaPlayer != null ? ? ? ? ? ? ? ? && "續(xù)播".equals(btnPasue.getText().toString())) { ? ? ? ? ? ? subtime += SystemClock.elapsedRealtime() - pauseTime; ? ? ? ? ? ? // System.out.println("2 subtime:" + subtime); ? ? ? ? ? ? mediaPlayer.start(); ? ? ? ? ? ? btnPasue.setText("暫停"); ? ? ? ? ? ? seekBar.setEnabled(true); ? ? ? ? ? ? beginTime = falgTime + subtime; ? ? ? ? ? ? // System.out.println("3 beginTime" + beginTime); ? ? ? ? ? ? et_time.setBase(beginTime); ? ? ? ? ? ? et_time.start(); ? ? ? ? } ? ? } ? ? private void stopPlay() { ? ? ? ? if (mediaPlayer != null && mediaPlayer.isPlaying()) { ? ? ? ? ? ? mediaPlayer.stop(); ? ? ? ? ? ? mediaPlayer = null; ? ? ? ? ? ? et_time.setBase(SystemClock.elapsedRealtime()); ? ? ? ? ? ? et_time.start(); ? ? ? ? ? ? et_time.stop(); ? ? ? ? ? ? btnPlay2.setEnabled(true); ? ? ? ? ? ? btnPlay2.setClickable(true); ? ? ? ? } ? ? ? ? falgTime = 0; ? ? ? ? subtime = 0; ? ? ? ? seekBar.setProgress(0); ? ? ? ? seekBar.setEnabled(false); ? ? } ? ? private void play() { ? ? ? ? mediaPlayer = new MediaPlayer(); ? ? ? ? try { ? ? ? ? ? ? mediaPlayer.setDataSource(filePath); ? ? ? ? ? ? mediaPlayer.prepareAsync(); ? ? ? ? ? ? // 為播放器注冊(cè) ? ? ? ? ? ? mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { ? ? ? ? ? ? ? ? public void onPrepared(MediaPlayer mp) { ? ? ? ? ? ? ? ? ? ? // TODO Auto-generated method stub ? ? ? ? ? ? ? ? ? ? mediaPlayer.start(); ? ? ? ? ? ? ? ? ? ? btnPlay2.setEnabled(false); ? ? ? ? ? ? ? ? ? ? btnPlay2.setClickable(false); ? ? ? ? ? ? ? ? ? ? seekBar.setMax(mediaPlayer.getDuration()); ? ? ? ? ? ? ? ? ? ? handler.post(updateThread); ? ? ? ? ? ? ? ? ? ? seekBar.setEnabled(true); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? }); ? ? ? ? ? ? // 注冊(cè)播放完畢后的監(jiān)聽事件 ? ? ? ? ? ? mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { ? ? ? ? ? ? ? ? public void onCompletion(MediaPlayer mp) { // ? ? ? ? ? ? ? ? ? ?mediaPlayer.release(); // ? ? ? ? ? ? ? ? ? ?mediaPlayer = null; ? ? ? ? ? ? ? ? ? ? btnPlay2.setEnabled(true); ? ? ? ? ? ? ? ? ? ? btnPlay2.setClickable(true); ? ? ? ? ? ? ? ? ? ? et_time.setBase(SystemClock.elapsedRealtime()); ? ? ? ? ? ? ? ? ? ? et_time.start(); ? ? ? ? ? ? ? ? ? ? et_time.stop(); ? ? ? ? ? ? ? ? ? ? seekBar.setProgress(0); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? }); ? ? ? ? ? ? falgTime = SystemClock.elapsedRealtime(); ? ? ? ? ? ? et_time.setBase(falgTime); ? ? ? ? ? ? et_time.start(); ? ? ? ? ? ? et_time.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() { ? ? ? ? ? ? ? ? @Override ? ? ? ? ? ? ? ? public void onChronometerTick(Chronometer chronometer) { ? ? ? ? ? ? ? ? } ? ? ? ? ? ? }); ? ? ? ? ? ? seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { ? ? ? ? ? ? ? ? @Override ? ? ? ? ? ? ? ? public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { ? ? ? ? ? ? ? ? ? ? if (fromUser == true && mediaPlayer != null) { ? ? ? ? ? ? ? ? ? ? ? ? Log.e("Test", "onProgressChanged------ progress "+progress); ? ? ? ? ? ? ? ? ? ? ? ? mediaPlayer.seekTo(progress); ? ? ? ? ? ? ? ? ? ? ? ? falgTime = SystemClock.elapsedRealtime(); ? ? ? ? ? ? ? ? ? ? ? ? beginTime = falgTime - seekBar.getProgress(); ? ? ? ? ? ? ? ? ? ? ? ? et_time.setBase(beginTime); // ? ? ? ? ? ? ? ? ? ? ? ?et_time.start(); // ? ? ? ? ? ? ? ? ? ? ? ?final int ctime = mediaPlayer.getDuration() / progress; ? ? ? ? ? ? ? ? ? ? ? ? //時(shí)間*比特率 = 大小 (rate * 1 * 16 / 8) * (duration / 1000); ? ? ? ? ? ? ? ? ? ? ? ? //時(shí)間 = 大小/比特率 ? ? ? ? ? ? ? ? ? ? ? ? int ctime = progress/((rate * 1 * 16 / 8) * (duration / 1000)); ? ? ? ? ? ? ? ? ? ? ? ? currentTime.setText( ctime+ "s"); ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? @Override ? ? ? ? ? ? ? ? public void onStartTrackingTouch(SeekBar seekBar) { ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? @Override ? ? ? ? ? ? ? ? public void onStopTrackingTouch(SeekBar seekBar) { // ? ? ? ? ? ? ? ? ? ?startPos = seekBar.getProgress(); ? ? ? ? ? ? ? ? ? ? currentProgress = seekBar.getProgress(); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? }); ? ? ? ? } catch (IOException e) { ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? } ? ? ? ? // mediaPlayer.prepare(); // c/c++ 播放器引擎的初始化 ? ? ? ? // 同步方法 ? ? ? ? // 采用異步的方式 ? ? } ? ? private OnEventListener onEventListener; ? ? public void setOnEventListener(OnEventListener onEventListener) { ? ? ? ? this.onEventListener = onEventListener; ? ? } ? ? android.os.Handler errorHandler = new android.os.Handler() { ? ? ? ? @Override ? ? ? ? public void handleMessage(Message msg) { ? ? ? ? ? ? if (onEventListener != null) { ? ? ? ? ? ? ? ? onEventListener.onError("error"); ? ? ? ? ? ? } ? ? ? ? } ? ? }; ? ? private void startThread() { ? ? ? ? if (startPos == 0) {//開始位置 ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? randomAccessFile.seek(44); ? ? ? ? ? ? } catch (IOException e) { ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? mThreadFlag = true; ? ? ? ? i = 0; ? ? ? ? j = -1; ? ? ? ? STATUS = 1; ? ? ? ? thread = new Thread() { ? ? ? ? ? ? @Override ? ? ? ? ? ? public void run() { ? ? ? ? ? ? ? ? if (startTime == 0) { ? ? ? ? ? ? ? ? ? ? startTime = System.currentTimeMillis(); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? byte[] arrayOfByte = new byte[bufferSize]; ? ? ? ? ? ? ? ? short[] arrayOfShort = new short[bufferSize]; ? ? ? ? ? ? ? ? while (mThreadFlag) { ? ? ? ? ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? ? ? ? ? if (audioRecord == null || STATUS != 1) { ? ? ? ? ? ? ? ? ? ? ? ? ? ? continue; ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? ? ? int bufferReadResult = audioRecord.read(arrayOfByte, 0, bufferSize); ? ? ? ? ? ? ? ? ? ? ? ? int bufferReadResult2 = audioRecord.read(arrayOfShort, 0, bufferSize); ? ? ? ? ? ? ? ? ? ? ? ? Log.e("Test", "run------ bufferReadResult "+bufferReadResult); ? ? ? ? ? ? ? ? ? ? ? ? Log.e("Test", "run------ bufferReadResult2 "+bufferReadResult2); ? ? ? ? ? ? ? ? ? ? ? ? if (audioRecord.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING || bufferReadResult <= 0) { ? ? ? ? ? ? ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? ? ? i = 1; ? ? ? ? ? ? ? ? ? ? ? ? randomAccessFile.write(arrayOfByte); ? ? ? ? ? ? ? ? ? ? ? ? waveformView.updateAudioData(arrayOfShort); ? ? ? ? ? ? ? ? ? ? ? ? byte[] tmpBuf = new byte[bufferReadResult]; ? ? ? ? ? ? ? ? ? ? ? ? System.arraycopy(arrayOfByte, 0, tmpBuf, 0, bufferReadResult); ? ? ? ? ? ? ? ? ? ? ? ? audioTrack.write(tmpBuf, 0, tmpBuf.length); ? ? ? ? ? ? ? ? ? ? ? ? pjByteBuffer(tmpBuf); ? ? ? ? ? ? ? ? ? ? ? ? curFileLength = (int) randomAccessFile.length() / 1024; ? ? ? ? ? ? ? ? ? ? ? ? Log.e("Test", "run------ curFilelength:" + curFileLength + ",startPos:" + startPos + ",endPos:" + endPos + ",isRewrite:" + isRewrite); ? ? ? ? ? ? ? ? ? ? ? ? int time = (int) (System.currentTimeMillis() - startTime); ? ? ? ? ? ? ? ? ? ? ? ? Log.e("Test", "run------ time: " + time); ? ? ? ? ? ? ? ? ? ? ? ? Log.e("Test", "run------ bytes:" + arrayOfByte.length); ? ? ? ? ? ? ? ? ? ? ? ? Log.e("Test", "run------ getFilePointer:" + randomAccessFile.getFilePointer()); ? ? ? ? ? ? ? ? ? ? ? ? startPos = (int) randomAccessFile.getFilePointer(); ? ? ? ? ? ? ? ? ? ? ? ? if (time >= restOfTime) { ? ? ? ? ? ? ? ? ? ? ? ? ? ? stopRecord(); ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? ? ? onFileChangedListener.onBufferRecevied(startPos, endPos, arrayOfByte, curFileLength, isRewrite); // ? ? ? ? ? ? ? ? ? ? ? ?Test t1 = Test.this; // ? ? ? ? ? ? ? ? ? ? ? ?t1.i = 1+t1.i; // // ? ? ? ? ? ? ? ? ? ? ? ?long length = randomAccessFile.getFilePointer() + arrayOfByte.length; // ? ? ? ? ? ? ? ? ? ? ? ?xxx(this,length); // ? ? ? ? ? ? ? ? ? ? ? ?if (endPos>curFileLength){ // ? ? ? ? ? ? ? ? ? ? ? ? ? ?xxx(this,endPos); // ? ? ? ? ? ? ? ? ? ? ? ?} // ? ? ? ? ? ? ? ? ? ? ? ?randomAccessFile.write(arrayOfByte); // ? ? ? ? ? ? ? ? ? ? ? ?onFileChangedListener.onBufferRecevied(startPos,endPos,arrayOfByte,curFileLength,isRewrite); // // ? ? ? ? ? ? ? ? ? ? ? ?Test t2 =Test.this; // ? ? ? ? ? ? ? ? ? ? ? ?t2.j = 1+t2.j; // ? ? ? ? ? ? ? ? ? ? ? ?if (i!=0||j!=0){ // ? ? ? ? ? ? ? ? ? ? ? ? ? ?continue; // ? ? ? ? ? ? ? ? ? ? ? ?} // ? ? ? ? ? ? ? ? ? ? ? ?xxx(this,false); // ? ? ? ? ? ? ? ? ? ? ? ?errorHandler.sendEmptyMessage(0); ? ? ? ? ? ? ? ? ? ? } catch (Exception e) { ? ? ? ? ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? ? ? ? ? ? ? errorHandler.sendEmptyMessage(0); ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? }; ? ? ? ? thread.start(); ? ? } ? ? private byte[] pjArray(byte[] src, byte[] dest) { ? ? ? ? byte[] newBytes = new byte[src.length + dest.length]; ? ? ? ? System.arraycopy(src, 0, newBytes, 0, src.length); ? ? ? ? System.arraycopy(dest, 0, newBytes, src.length, dest.length); ? ? ? ? return newBytes; ? ? } ? ? private void pjByteBuffer(byte[] tmpBuf) { ? ? ? ? if (sampleBytes == null) { ? ? ? ? ? ? sampleBytes = tmpBuf; ? ? ? ? } else { ? ? ? ? ? ? sampleBytes = pjArray(sampleBytes, tmpBuf); ? ? ? ? } ? ? } ? ? private void pauseReview() { ? ? ? ? audioTrackFlag = false; ? ? ? ? audioTrack.pause(); ? ? ? ? audioTrack.flush(); ? ? ? ? Log.e("Test", "pauseReview------ "); ? ? } ? ? private void startReview(boolean b) { ? ? ? ? if (audioTrack == null) { ? ? ? ? ? ? initAudioTack(); ? ? ? ? } ? ? ? ? audioTrack.play(); ? ? ? ? audioTrackFlag = true; ? ? ? ? audioTrackThread = new Thread() { ? ? ? ? ? ? @Override ? ? ? ? ? ? public void run() { ? ? ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? ? ? bytes = new byte[minBufferSize]; ? ? ? ? ? ? ? ? ? ? while (randomAccessFile.read(bytes) != -1 && audioTrackFlag) { ? ? ? ? ? ? ? ? ? ? ? ? Log.e("Test", "run------ "); ? ? ? ? ? ? ? ? ? ? ? ? Log.e("Test", "run------audiotrackflag is ?" + audioTrackFlag); ? ? ? ? ? ? ? ? ? ? ? ? Log.e("Test", "run------wrtie data in audiotrack "); ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? Log.e("Test", "run------ audiotrack end."); ? ? ? ? ? ? ? ? } catch (Exception e) { ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? }; ? ? ? ? audioTrackThread.start(); ? ? } ? ? public void pauseRecord() { ? ? ? ? if (audioRecord != null) { ? ? ? ? ? ? audioRecord.stop(); ? ? ? ? ? ? mThreadFlag = false; ? ? ? ? } ? ? } ? ? private void reset() { ? ? ? ? startPos = 0; ? ? ? ? endPos = 0; ? ? ? ? curFileLength = 44; ? ? ? ? isRewrite = false; ? ? } ? ? private void resumeRecord() { ? ? ? ? while (isRewrite) {//寫文件 ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? if (randomAccessFile.getFilePointer() != endPos || !isRewrite) {//不可寫 ,或者選中位置不是文件指針?biāo)谖恢? ? ? ? ? ? ? ? ? ? ? startPos = (int) randomAccessFile.getFilePointer(); // 從文件指針位置開始 ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? if (!isRewrite) {//不寫文件 ? ? ? ? ? ? ? ? ? ? if (44 + startPos >= endPos) {// ? ? ? ? ? ? ? ? ? ? ? ? continue; ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? isRewrite = true; ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } catch (IOException e) { ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? } ? ? ? ? ? ? audioRecord.startRecording(); ? ? ? ? ? ? if (thread == null || !mThreadFlag) { ? ? ? ? ? ? ? ? startThread(); ? ? ? ? ? ? } ? ? ? ? } ? ? } ? ? private void startRecording() { ? ? ? ? try { ? ? ? ? ? ? audioRecord.startRecording(); // ? ? ? ? ? ?if (thread==null||!mThreadFlag){ // ? ? ? ? ? ? ? ?startThread(); // ? ? ? ? ? ?} ? ? ? ? ? ? startThread(); ? ? ? ? ? ? Log.e("Test", "startRecording------ "); ? ? ? ? } catch (Exception e) { ? ? ? ? ? ? initRecorder(true); ? ? ? ? } ? ? } ? ? public int getMinBufferSize() { ? ? ? ? return minBufferSize; ? ? } ? ? public void getMinBufSize() { ? ? ? ? recBufSize = AudioRecord.getMinBufferSize(frequency, 12, 2); ? ? } ? ? public void setOnFileChangedListener(OnFileChangedListener onFileChangedListener) { ? ? ? ? this.onFileChangedListener = onFileChangedListener; ? ? } ? ? public void setDuration(int duration) { ? ? ? ? this.duration = duration; ? ? } ? ? interface OnFileChangedListener { ? ? ? ? void onBufferRecevied(long startPos, long endPos, byte[] b1, long currenFileLength, boolean isRew); ? ? } ? ? interface OnEventListener { ? ? ? ? void onError(String s); ? ? ? ? void onRecordComplete(); ? ? ? ? void onVolumnChanged(double vl); ? ? } ? ? public String creatFile() { // ? ? ? ?copyWaveFile(filePath,filePath,true); ? ? ? ? return outPath; ? ? } ? ? private void moveToPrevious(long pl) { ? ? ? ? try { ? ? ? ? ? ? long l = 44 + 4 * (pl * rate / 1000l); ? ? ? ? ? ? randomAccessFile.seek(l); ? ? ? ? ? ? Log.e("Test", "moveToPrevious------ offset:" + l + " length:" + randomAccessFile.length()); ? ? ? ? } catch (Exception e) { ? ? ? ? } ? ? } ? ? @Override ? ? protected void onPause() { ? ? ? ? super.onPause(); ? ? ? ? stopRecord(); ? ? } ? ? @Override ? ? protected void onStop() { ? ? ? ? super.onStop(); ? ? ? ? closeStream(); ? ? } ? ? private void stopRecord() { ? ? ? ? try { ? ? ? ? ? ? mThreadFlag = false; ? ? ? ? ? ? time = 0; ? ? ? ? ? ? thread = null; ? ? ? ? ? ? if (audioRecord != null) { ? ? ? ? ? ? ? ? if (audioRecord.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) { ? ? ? ? ? ? ? ? ? ? audioRecord.stop(); ? ? ? ? ? ? ? ? ? ? Log.e("Test", "stopRecord------ "); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? audioRecord.release(); ? ? ? ? ? ? ? ? audioRecord = null; ? ? ? ? ? ? } ? ? ? ? ? ? closeStream(); ? ? ? ? } catch (Exception e) { ? ? ? ? } ? ? } ? ? private void closeStream() { ? ? ? ? try { ? ? ? ? ? ? if (randomAccessFile != null) { ? ? ? ? ? ? ? ? randomAccessFile.close(); ? ? ? ? ? ? } ? ? ? ? } catch (Exception e) { ? ? ? ? } ? ? } ? ? float getDensity() { ? ? ? ? DisplayMetrics metrics = new DisplayMetrics(); ? ? ? ? getWindowManager().getDefaultDisplay().getMetrics(metrics); ? ? ? ? return metrics.density; ? ? } }
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android音頻錄制MediaRecorder之簡(jiǎn)易的錄音軟件實(shí)現(xiàn)代碼
- Android簡(jiǎn)單的利用MediaRecorder進(jìn)行錄音的實(shí)例代碼
- Android實(shí)現(xiàn)錄音功能實(shí)現(xiàn)實(shí)例(MediaRecorder)
- Android實(shí)現(xiàn)錄音方法(仿微信語(yǔ)音、麥克風(fēng)錄音、發(fā)送語(yǔ)音、解決5.0以上BUG)
- Android應(yīng)用開發(fā):電話監(jiān)聽和錄音代碼示例
- Android App調(diào)用MediaRecorder實(shí)現(xiàn)錄音功能的實(shí)例
- 詳解Android開發(fā)錄音和播放音頻的步驟(動(dòng)態(tài)獲取權(quán)限)
- Android實(shí)現(xiàn)語(yǔ)音播放與錄音功能
- Android編程實(shí)現(xiàn)錄音及保存播放功能的方法【附demo源碼下載】
- Android開發(fā)四大組件之實(shí)現(xiàn)電話攔截和電話錄音
相關(guān)文章
使用Kotlin開發(fā)Android應(yīng)用教程
這篇文章主要為大家詳細(xì)介紹了使用Kotlin開發(fā)Android應(yīng)用的教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05Android開發(fā)之瀏覽器用法實(shí)例詳解(調(diào)用uc,opera,qq瀏覽器訪問(wèn)網(wǎng)頁(yè))
這篇文章主要介紹了Android開發(fā)之瀏覽器用法,結(jié)合實(shí)例形式詳細(xì)分析了Android調(diào)用瀏覽器的具體步驟與相關(guān)使用技巧,需要的朋友可以參考下2016-01-01Android Button點(diǎn)擊事件的四種實(shí)現(xiàn)方法
這篇文章主要為大家詳細(xì)介紹了Android Button點(diǎn)擊事件的四種實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07Android控件之ImageView用法實(shí)例分析
這篇文章主要介紹了Android控件之ImageView用法,以實(shí)例形式較為詳細(xì)的分析了ImageView控件用于顯示圖片的使用方法,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-09-09android效果TapBarMenu繪制底部導(dǎo)航欄的使用方式示例
本篇文章主要介紹了android效果TapBarMenu繪制底部導(dǎo)航欄的使用方式,具有一定的參考價(jià)值,有興趣的可以了解一下。2017-01-01Android使用Spinner實(shí)現(xiàn)城市級(jí)聯(lián)下拉框
這篇文章主要為大家詳細(xì)介紹了Android使用Spinner實(shí)現(xiàn)城市級(jí)聯(lián)下拉框,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12Android中發(fā)送Http請(qǐng)求(包括文件上傳、servlet接收)的實(shí)例代碼
首先我是寫了個(gè)java工程測(cè)試發(fā)送post請(qǐng)求:可以包含文本參數(shù)和文件參數(shù)2013-05-05