日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
Android簡(jiǎn)易“吹一吹實(shí)現(xiàn)”以及錄音和播放示例

最近在做一些跟傳感器相關(guān)的東西,有注意到以前騰訊微博以前出過(guò)一個(gè)吹一吹交互,雖然和傳感器無(wú)關(guān),但是感覺(jué)也比較有興趣,就寫了一個(gè)拙劣的demo,因?yàn)榻佑|媒體文件操作比較少,順帶寫了一個(gè)錄音和播放的例子,總結(jié)了一下一些小坑的地方,一并在此分享給大家。

在綏江等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場(chǎng)前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供網(wǎng)站建設(shè)、網(wǎng)站制作 網(wǎng)站設(shè)計(jì)制作按需求定制設(shè)計(jì),公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),品牌網(wǎng)站制作,網(wǎng)絡(luò)營(yíng)銷推廣,外貿(mào)網(wǎng)站建設(shè),綏江網(wǎng)站建設(shè)費(fèi)用合理。

主要思路和坑的地方

主要的思路是通過(guò)MediaRecorder提供的getMaxAmplitude()函數(shù),獲取一段時(shí)間內(nèi)輸入的音頻最大幅值來(lái)進(jìn)行檢測(cè),所以除了吹的動(dòng)作,其他聲音也會(huì)被錄進(jìn)來(lái)。

“吹”這個(gè)動(dòng)作如果想和其他動(dòng)作進(jìn)行區(qū)分,其實(shí)本質(zhì)在于吹的時(shí)候靠近聽(tīng)筒,即便吹這個(gè)動(dòng)作本身音量不大,但是麥克風(fēng)看來(lái)它的分貝是很大的,所以我們可以通過(guò)檢測(cè)分貝來(lái)判斷這個(gè)動(dòng)作是否是吹(如果其他聲音更大……那……算了不管了)。

這里附上前人的一些參考資料:

http://www.jb51.net/article/6...

一看到這個(gè)網(wǎng)站后面是htm,仿佛就明白了這個(gè)網(wǎng)站的框架…

這個(gè)東西坑的地方在于mediaplayer和MediaRecorder這兩個(gè)東西stop和start的順序經(jīng)常是嚴(yán)格被限制的,在退出時(shí)如果沒(méi)有成功釋放資源,有時(shí)候Activity再啟動(dòng)時(shí),由于上次退出沒(méi)有stop,再重新start也會(huì)拋出異常。

權(quán)限添加

 
 
 
 
  1.  
  2.  
  3.  
  4.  

主要界面

大概想了一個(gè)簡(jiǎn)單的界面,好吧其實(shí)是左下角的音響閃動(dòng),忘記修改文字描述了

布局文件:

 
 
 
 
  1.  
  2. xmlns:tools="http://schemas.android.com/tools" 
  3. android:id="@+id/activity_sound" 
  4. android:layout_width="match_parent" 
  5. android:layout_height="match_parent" 
  6. android:paddingBottom="@dimen/activity_vertical_margin" 
  7. android:paddingLeft="@dimen/activity_horizontal_margin" 
  8. android:paddingRight="@dimen/activity_horizontal_margin" 
  9. android:paddingTop="@dimen/activity_vertical_margin" 
  10. tools:context=".SoundActivity"> 
  11.     android:layout_width="wrap_content" 
  12.     android:layout_height="wrap_content" 
  13.     android:text="@string/introduction_of_sound"/> 
  14.     android:layout_width="match_parent" 
  15.     android:layout_height="wrap_content" 
  16.     android:orientation="vertical" 
  17.     android:gravity="center" 
  18.     android:layout_centerInParent="true"> 
  19.  
  20.     
  21.         android:layout_width="70dp" 
  22.         android:layout_height="70dp" 
  23.         android:id="@+id/btn_start_record" 
  24.         android:background="@drawable/ic_mic_none_black_24dp" 
  25.         /> 
  26.     
  27.         android:layout_width="wrap_content" 
  28.         android:layout_height="wrap_content" 
  29.         android:id="@+id/tv_record_tips"/> 
  30.  
  31.     
  32.         android:layout_width="70dp" 
  33.         android:layout_height="70dp" 
  34.         android:id="@+id/btn_start_play" 
  35.         android:background="@drawable/ic_play_circle_filled_black_24dp" 
  36.         /> 
  37.  
  38.     android:layout_width="50dp" 
  39.     android:layout_height="50dp" 
  40.     android:src="@drawable/ic_volume_mute_gray_24dp" 
  41.     android:layout_alignParentBottom="true" 
  42.     android:id="@+id/imv_sound"/> 
  43.   

主要代碼

 
 
 
 
  1. import android.app.ProgressDialog; 
  2. import android.media.AudioManager; 
  3. import android.media.MediaPlayer; 
  4. import android.media.MediaRecorder; 
  5. import android.os.Environment; 
  6. import android.os.Handler; 
  7. import android.os.Message; 
  8. import android.support.v7.app.AppCompatActivity; 
  9. import android.os.Bundle; 
  10. import android.view.View; 
  11. import android.widget.Button; 
  12. import android.widget.ImageView; 
  13. import android.widget.TextView; 
  14. import android.widget.Toast; 
  15.  
  16. import java.io.IOException; 
  17. import java.util.Timer; 
  18. import java.util.TimerTask; 
  19.  
  20.  
  21. public class SoundActivity extends AppCompatActivity { 
  22.     static final int RECORDING = 1; 
  23.     static final int PLAYING = 2; 
  24.     static final int PAUSING = 3; 
  25.     static String TAG = "SoundActivity"; 
  26.     static int STATUS = RECORDING; 
  27.     //用于音頻錄制 
  28.     MediaRecorder mediaRecorder; 
  29.     //用于音頻播放 
  30.     MediaPlayer mediaPlayer; 
  31.  
  32.     //錄制按鈕 
  33.     Button btnRecord; 
  34.     //播放按鈕 
  35.     Button btnPlay; 
  36.     //提示信息 
  37.     TextView tvTips; 
  38.     //吹一吹小音箱 
  39.     ImageView imvSound; 
  40.     //播放進(jìn)度條 
  41.     static String PATH_NAME = Environment.getExternalStorageDirectory().getAbsolutePath() + "/SensorDemoRecorder.mp3"; 
  42.     @Override 
  43.     protected void onCreate(Bundle savedInstanceState) { 
  44.         super.onCreate(savedInstanceState); 
  45.         setContentView(R.layout.activity_sound); 
  46.         init(); 
  47.     } 
  48.  
  49.     public void init(){ 
  50.         //控件初始化 
  51.         btnPlay = (Button)findViewById(R.id.btn_start_play); 
  52.         btnRecord = (Button)findViewById(R.id.btn_start_record); 
  53.         tvTips = (TextView)findViewById(R.id.tv_record_tips); 
  54.         imvSound = (ImageView)findViewById(R.id.imv_sound); 
  55.         mediaplayerPreparingDialog = new ProgressDialog(this); 
  56.         btnPlay.setOnClickListener(new View.OnClickListener() { 
  57.             @Override 
  58.             public void onClick(View v) { 
  59.                 if (STATUS == RECORDING ){ 
  60.                     //如果是在錄制,點(diǎn)擊則停止錄制并且播放 
  61.                     stopRecording(); 
  62.                     startPlay(); 
  63.                 }else if (STATUS == PAUSING){ 
  64.                     startPlay(); 
  65.                 } else { 
  66.                     //如果是在播放,點(diǎn)擊則暫停 
  67.                     pausePlay(); 
  68.                 } 
  69.             } 
  70.         }); 
  71.         btnRecord.setOnClickListener(new View.OnClickListener() { 
  72.             @Override 
  73.             public void onClick(View v) { 
  74.                 if (STATUS == PLAYING || STATUS == PAUSING){ 
  75.                     //如果是在播放或者暫停,點(diǎn)擊開始錄制 
  76.                     startRecording(); 
  77.                 }else { 
  78.                     //如果在錄制,點(diǎn)擊開始播放 
  79.                     stopRecording(); 
  80.                     startPlay(); 
  81.                 } 
  82.             } 
  83.         }); 
  84.  
  85.         mediaRecorder = new MediaRecorder(); 
  86.         //設(shè)置到達(dá)最大錄制長(zhǎng)度時(shí)重頭開始錄制 
  87.         mediaRecorder.setOnInfoListener(new MediaRecorder.OnInfoListener() { 
  88.             @Override 
  89.             public void onInfo(MediaRecorder mr, int what, int extra) { 
  90.                 switch (what){ 
  91.                     case MediaRecorder.MEDIA_RECORDER_ERROR_UNKNOWN: 
  92.                         Toast.makeText(SoundActivity.this, "未知錯(cuò)誤", Toast.LENGTH_SHORT).show(); 
  93.                         finish(); 
  94.                         break; 
  95.                     case MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED: 
  96.                         Toast.makeText(SoundActivity.this, "已達(dá)到最大錄制長(zhǎng)度,開始重新錄制", Toast.LENGTH_SHORT).show( ); 
  97.                         startRecording(); 
  98.                         break; 
  99.                     case MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED: 
  100.                         Toast.makeText(SoundActivity.this, "空間不足,無(wú)法錄制", Toast.LENGTH_SHORT).show(); 
  101.                         mediaRecorder.stop(); 
  102.                         break; 
  103.  
  104.                 } 
  105.             } 
  106.         }); 
  107.         //默認(rèn)開始錄制 
  108.         startRecording(); 
  109.         btnRecord.setBackgroundResource(R.drawable.ic_mic_black_24dp); 
  110.         //默認(rèn)開始吹一吹檢測(cè)以及播放進(jìn)度檢測(cè) 
  111.         startCheckSound(); 
  112.     } 
  113.  
  114.  
  115.     @Override 
  116.     protected void onDestroy() { 
  117.         super.onDestroy(); 
  118.         if (PLAYING == STATUS){ 
  119.             mediaPlayer.stop(); 
  120.             mediaPlayer.release(); 
  121.         } 
  122.         if (RECORDING == STATUS){ 
  123.             mediaRecorder.stop(); 
  124.             mediaRecorder.release(); 
  125.         } 
  126.         //為了防止Activity結(jié)束后有時(shí)候這個(gè)timer還在定時(shí)執(zhí)行任務(wù)(很坑) 
  127.         timer.cancel(); 
  128.     } 
  129.  
  130.     public void startRecording(){ 
  131.         if (PLAYING == STATUS){ 
  132.             stopPlay(); 
  133.         } 
  134.         STATUS = RECORDING; 
  135.         //設(shè)置為錄制狀態(tài) 
  136.         tvTips.setText("正在錄制,點(diǎn)擊播放按鈕或者麥克風(fēng)停止錄制"); 
  137.         btnRecord.setBackgroundResource(R.drawable.ic_mic_black_24dp); 
  138.  
  139.         //開始錄制的設(shè)置 
  140.         mediaRecorder.reset();  // You can reuse the object by going back to setAudioSource() step 
  141.         mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); 
  142.         mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); 
  143.         mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); 
  144.         try{ 
  145.             mediaRecorder.setOutputFile(PATH_NAME); 
  146.             mediaRecorder.prepare(); 
  147.             mediaRecorder.start();   // Recording is now started 
  148.         }catch (IOException e){ 
  149.             Toast.makeText(this, "準(zhǔn)備錄制文件失敗", Toast.LENGTH_SHORT).show(); 
  150.             e.printStackTrace(); 
  151.             finish(); 
  152.         } 
  153.     } 
  154.  
  155.     public void stopRecording(){ 
  156.         if (RECORDING == STATUS){ 
  157.             //說(shuō)明正在錄制,設(shè)置停止信息 
  158.             tvTips.setText("已停止錄制,開始播放"); 
  159.             btnRecord.setBackgroundResource(R.drawable.ic_mic_none_black_24dp); 
  160.             mediaRecorder.stop(); 
  161.         } 
  162.     } 
  163.  
  164.  
  165.  
  166.     Handler handler= new Handler(new Handler.Callback() { 
  167.         @Override 
  168.         public boolean handleMessage(Message msg) { 
  169.             if ((Double)msg.obj > 70){ 
  170.                 imvSound.setImageResource(R.drawable.ic_volume_mute_valid_24dp); 
  171.             }else { 
  172.                 imvSound.setImageResource(R.drawable.ic_volume_mute_gray_24dp); 
  173.             } 
  174.             return false; 
  175.         } 
  176.     }); 
  177.  
  178.     Timer timer = new Timer(); 
  179.     public void startCheckSound(){ 
  180.         //定時(shí)檢測(cè)峰值,以及檢測(cè)播放進(jìn)度 
  181.         timer.schedule(new TimerTask() { 
  182.             @Override 
  183.             public void run() { 
  184.                 if (mediaRecorder != null) { 
  185.                     double amplitude = (double)mediaRecorder.getMaxAmplitude(); 
  186.                     double db = 0; 
  187.                     //計(jì)算分貝 
  188.                     if (amplitude > 1) 
  189.                         db = 20 * Math.log10(amplitude); 
  190.                     Message msg = new Message(); 
  191.                     msg.obj = db; 
  192.                     handler.sendMessage(msg); 
  193.                     //如果需要檢測(cè)播放進(jìn)度可以使用 
  194.                     //mediaPlayer.getCurrentPosition()/mediaPlayer.getDuration(); 
  195.                 } 
  196.             } 
  197.         },0,100); 
  198.     } 
  199.  
  200.  
  201.     ProgressDialog mediaplayerPreparingDialog; 
  202.     public void startPlay(){ 
  203.         if (RECORDING == STATUS){ 
  204.             //如果是從錄制狀態(tài)開始播放,則重新讀取新的錄制文件 
  205.             STATUS = PLAYING; 
  206.             //設(shè)置音頻播放器 
  207.             mediaPlayer = new MediaPlayer(); 
  208.             mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); 
  209.             mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { 
  210.                 @Override 
  211.                 public void onCompletion(MediaPlayer mp) { 
  212.                     //播放完設(shè)置 
  213.                     tvTips.setText("播放完畢,可點(diǎn)擊麥克風(fēng)重新錄制"); 
  214.                     btnPlay.setBackgroundResource(R.drawable.ic_play_circle_filled_black_24dp); 
  215.                 } 
  216.             }); 
  217.             try { 
  218.                 mediaPlayer.setDataSource(PATH_NAME); 
  219.                 mediaPlayer.prepareAsync(); 
  220.             } catch (IOException e) { 
  221.                 e.printStackTrace(); 
  222.                 Toast.makeText(this, "錄音文件已丟失", Toast.LENGTH_SHORT).show(); 
  223.                 finish(); 
  224.             } 
  225.             mediaplayerPreparingDialog.setTitle("正在準(zhǔn)備播放錄音"); 
  226.             mediaplayerPreparingDialog.show(); 
  227.  
  228.             mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { 
  229.                 @Override 
  230.                 public void onPrepared(MediaPlayer mp) { 
  231.                     mediaplayerPreparingDialog.dismiss(); 
  232.                     mediaPlayer.start(); 
  233.                 } 
  234.             }); 
  235.  
  236.         }else if(PAUSING == STATUS){ 
  237.             //從暫停狀態(tài)開始播放則直接播放 
  238.             mediaPlayer.start(); 
  239.         } 
  240.         //開始播放,設(shè)置按鈕為暫停 
  241.         btnPlay.setBackgroundResource(R.drawable.ic_pause_circle_filled_black_24dp); 
  242.  
  243.     } 
  244.  
  245.     public void pausePlay(){ 
  246.         if (PLAYING == STATUS) { 
  247.             //暫停播放,設(shè)置按鈕為開始播放 
  248.             mediaPlayer.pause(); 
  249.             btnPlay.setBackgroundResource(R.drawable.ic_play_circle_filled_black_24dp); 
  250.             STATUS = PAUSING; 
  251.         } 
  252.     } 
  253.  
  254.     public void stopPlay(){ 
  255.         if (mediaPlayer != null) mediaPlayer.stop(); 
  256.     } 
  257. }  

Media和IllegalStateException

這個(gè)就是之前提到的由于沒(méi)有按順序釋放資源或者stop掉這兩個(gè)破玩意兒,可能會(huì)導(dǎo)致的各種錯(cuò)誤,所以我很無(wú)奈地設(shè)置了一個(gè)STATUS變量,并且在Activity的OnDestoy里對(duì)兩個(gè)東西進(jìn)行了stop,其實(shí)一般還會(huì)使用release釋放掉資源…大家隨意吧…

QCMediaPlayer mediaplayer NOT present

!!!我就知道,如果你看到這個(gè)地方,一定也對(duì)這個(gè)錯(cuò)誤感到莫名其妙。我記得好像上古時(shí)期,也就是上次我寫這個(gè)的時(shí)候也被坑了。

論壇上有人說(shuō)這個(gè)東西在4.4以下的系統(tǒng)就容易出現(xiàn),但是我也只能感覺(jué)不明覺(jué)厲,我一開始用的是MediaPlayer.create(this,Uri.parse(PATH_NAME))來(lái)創(chuàng)建MediaPlayer,于是換成了

 
 
 
 
  1. mediaPlayer = new MediaPlayer(); 
  2. mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); 
  3. mediaPlayer.setDataSource(PATH_NAME);  

好吧,然后問(wèn)題就解決了,我也是無(wú)語(yǔ)了。我覺(jué)得這個(gè)地方是一個(gè)很久遠(yuǎn)的坑了,查原因一時(shí)也沒(méi)查到。我只能推測(cè)大概因?yàn)閏reate函數(shù)創(chuàng)建時(shí)沒(méi)有指定AudioStreamType導(dǎo)致使用了默認(rèn)的

 
 
 
 
  1. private int mStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE; 

在某些設(shè)備上可能不支持,于是就出了問(wèn)題= =好吧,我也不知道還能說(shuō)啥,就醬…

Vector Asset添加的圖標(biāo)顏色不變化

如上,我的播放按鈕啊,音響啊,之類的圖標(biāo)都是通過(guò)Vector Asset添加的,這也是一個(gè)比較久遠(yuǎn)的坑了,但是以前也沒(méi)有記下來(lái),即在Android L以下的版本中,Vector Asset添加的圖標(biāo),修改顏色時(shí)不能使用顏色的引用,而要直接寫顏色,例如:

 
 
 
 
  1.     android:width="24dp" 
  2.     android:height="24dp" 
  3.     android:viewportWidth="24.0" 
  4.     android:viewportHeight="24.0"> 
  5.     android:fillColor="#3F51B5" 
  6.     android:pathData="***"/> 
  7.   

使用

 
 
 
 
  1.     android:width="24dp" 
  2.     android:height="24dp" 
  3.     android:viewportWidth="24.0" 
  4.     android:viewportHeight="24.0"> 
  5.     android:fillColor="@color/colorPrimary" 
  6.     android:pathData="***"/> 
  7.   

則導(dǎo)致顏色并不會(huì)修改,依然是黑色


分享標(biāo)題:Android簡(jiǎn)易“吹一吹實(shí)現(xiàn)”以及錄音和播放示例
分享URL:http://www.5511xx.com/article/dhisgcj.html