Android中實現短音訊和震動的一些總結

筆墨Android發表於2018-11-04

好長時間沒有寫部落格了,因為最近事情比較多。所以好長時間沒有寫部落格了。堅持是一件很辛苦的事情。但還需要努力。。。好了,閒話不扯了。因為最近專案中用到了相應的短音訊和震動的功能,所以這裡總結一下相應的內容!

本文知識點:

    1. 音訊中的一些知識和常用的API介紹;
    1. 震動中的一些知識和常用的API介紹;
    1. 簡單的使用和封裝;

1. 音訊中的一些知識介紹和常用的API

1.1 關於短音訊一些知識的介紹

在專案中突然有個需求,就是實現短音訊,好比簡訊音那種!最開始想到的方案就是MediaPlayer解決。但是我隨手百度了一下,發現其實Android提供了一個單獨播放短音訊的 類(SoundPool),為什麼是它呢?因為soundPool用於播放密集,急促的短暫音效,例如微信的搖一搖等。。。SoundPool使用了音效池的來播放音訊,如果超過流的最大數目,SoundPool會基於優先順序自動停止先前播放的流。所以播放短促且密集的音訊應該使用SoundPool進行相應的播放,好了就簡單介紹到這裡吧!

1.2 音訊的一些相應的API介紹

這裡說明一點,在android5.0的時候廢棄了相應SoundPool使用構造方法的建立,所以為了相容,在建立的時候要進行相應的適配!相應的適配程式碼如下:

1.2.1 構造物件的方法

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            mSoundPool = new SoundPool.Builder()
                    .setMaxStreams(MAX_STREAMS)
                    .build();
        } else {
            mSoundPool = new SoundPool(MAX_STREAMS, AudioManager.STREAM_MUSIC, DEFAULT_QUALITY);
        }
複製程式碼

1.2.2 常見的API簡介

其實就是幾個過載的方法,基本上就是傳入引數進行相應的載入資源。

  1. load(Context context, int resId, int priority)
  2. load(String path, int priority)
  3. load(FileDescriptor fd, long offset, long length, int priority)
  4. load(AssetFileDescriptor afd, int priority)

上述方法都會返回一個聲音的ID(這個ID對應後面的soundID),後面我們可以通過這個ID來播放指定的聲音。

因為使用的引數都差不多,所以這裡統一進行講解一下:

  • context 上下文,沒有什麼好說的
  • resId 資源Id(這裡說明一下:一般音訊檔案都會放在res->raw資料夾下)
  • priority 沒有什麼實際用處,這裡傳入1就好了
  • path 檔案路徑
  • AssetFileDescriptor:從asset目錄讀取某個資原始檔,用法: AssetFileDescriptor descriptor = assetManager.openFd("biaobiao.mp3");
  1. play(int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate)

上面是開始播放的程式碼,引數含義如下:

  • soundID load()返回的相應索引
  • leftVolume:左聲道音量設定
  • rightVolume:右聲道音量設定
  • priority:指定播放聲音的優先順序,數值越高,優先順序越大。
  • loop:指定是否迴圈:-1表示無限迴圈,0表示不迴圈,其他值表示要重複播放的次數
  • rate:指定播放速率:1.0的播放率可以使聲音按照其原始頻率,而2.0的播放速率,可以使聲音按照其 原始頻率的兩倍播放。如果為0.5的播放率,則播放速率是原始頻率的一半。播放速率的取值範圍是0.5至2.0
  1. release() 釋放相應的資源
  2. setOnLoadCompleteListener(OnLoadCompleteListener listener) 檔案載入完畢的監聽

以上就是SoundPool的一些常見API,基本上上面的程式碼就可以輕鬆的使用SoundPool了!

2. 震動中的一些知識和常用的API介紹

2.1 震動的一些知識點介紹

關於震動沒有什麼好說的,只能使用Vibrator進行開發,但是切記一點就是許可權的宣告,基本上只要相關的許可權處理好了,震動還是很容易的。哦,忘記了,這個也要進行相應的版本適配,下面會說到的。

2.2 一些相應的API介紹

2.2.1 建構函式的建立

Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
複製程式碼

這個沒有什麼好說的,就是系統的相應服務。

2.2.2 常見的API簡介

幾個相應的過載方法

  1. vibrate(long milliseconds);
  2. vibrate(long milliseconds, AudioAttributes attributes);
  3. vibrate(long[] pattern, int repeat);
  4. vibrate(long[] pattern, int repeat, AudioAttributes attributes);

其實呼叫這個就可以直接進行相應的震動了,所以說挺簡單的。解釋一下相應的引數含義

  • milliseconds 震動的持續時間
  • attributes 震動的屬性,AudioAttributes類中定義了很多的屬性,感興趣的可以嘗試一下
  • pattern 這是一個陣列,可以實現一個間斷的震動效果(第一個值表示在開啟振動器之前要等待的毫秒數下一個值表示在關閉振動器之前保持振動器的毫秒數)實驗一下就可以了。
  • repeat 振動重複的模式 。"-1"代表不重複

記得我上面說過關於版本適配的問題吧,其實在26版本也就是Android O的時候,需要進行相應的適配,使用了VibrationEffect封裝了一層。

  1. vibrator.vibrate(long milliseconds); 設定手機震動
  2. vibrator.hasVibrator(); 判斷手機硬體是否有振動器
  3. vibrator.cancel(); 關閉振動
  4. VibrationEffect vibrationEffect = VibrationEffect.createOneShot(long milliseconds, int amplitude);
  5. VibrationEffect vibrationEffect = VibrationEffect.createWaveform(long[] timings, int repeat);
  6. VibrationEffect vibrationEffect = VibrationEffect.createWaveform(long[] timings, int[] amplitudes, int repeat);

也就是說之前直接呼叫的程式碼通過VibrationEffect進行了相應的封裝。解釋一個引數

  • amplitude 振幅值. 振幅在0~255之間,隨便選擇一個吧
  1. vibrate(VibrationEffect vibe); 開啟震動
  2. vibrate(VibrationEffect vibe, AudioAttributes attributes); 開啟震動

3. 簡單的使用和封裝

基本上關於短音訊和振幅的內容就是上面這些,基本上按照上面這些進行相應的組合就可以了.但是為了大家的方便,我簡單的封裝了一個工具類給大家使用.封裝的不好還請見諒!!!

public class SoundPoolUtils {

    private static final int MAX_STREAMS = 2;
    private static final int DEFAULT_QUALITY = 0;
    private static final int DEFAULT_PRIORITY = 1;
    private static final int LEFT_VOLUME = 1;
    private static final int RIGHT_VOLUME = 1;
    private static final int LOOP = 0;
    private static final float RATE = 1.0f;

    private static SoundPoolUtils sSoundPoolUtils;

    /**
     * 音訊的相關類
     */
    private SoundPool mSoundPool;
    private Context mContext;
    private Vibrator mVibrator;


    private SoundPoolUtils(Context context) {
        mContext = context;
        //初始化行營的音訊類
        intSoundPool();
        initVibrator();
    }

    /**
     * @author Angle
     * 建立時間: 2018/11/4 13:02
     * 方法描述: 初始化短音訊的內容
     */
    private void intSoundPool() {
        //根據不同的版本進行相應的建立
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            mSoundPool = new SoundPool.Builder()
                    .setMaxStreams(MAX_STREAMS)
                    .build();
        } else {
            mSoundPool = new SoundPool(MAX_STREAMS, AudioManager.STREAM_MUSIC, DEFAULT_QUALITY);
        }
    }

    /**
     * @author Angle
     * 建立時間: 2018/11/4 13:03
     * 方法描述: 初始化震動的物件
     */
    private void initVibrator() {
        mVibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
    }

    public static SoundPoolUtils getInstance(Context context) {
        if (sSoundPoolUtils == null) {
            synchronized (SoundPoolUtils.class) {
                if (sSoundPoolUtils == null) {
                    sSoundPoolUtils = new SoundPoolUtils(context);
                }
            }
        }
        return sSoundPoolUtils;
    }

    /**
     * @param resId 音訊的資源ID
     * @author Angle
     * 建立時間: 2018/11/4 13:03
     * 方法描述: 開始播放音訊
     */
    public void playVideo(int resId) {
        if (mSoundPool == null) {
            intSoundPool();
        }
        int load = mSoundPool.load(mContext, resId, DEFAULT_PRIORITY);
        mSoundPool.play(load, LEFT_VOLUME, RIGHT_VOLUME, DEFAULT_PRIORITY, LOOP, RATE);
    }

    /**
     * @param milliseconds 震動時間
     * @author Angle
     * 建立時間: 2018/11/4 13:04
     * 方法描述: 開啟相應的震動
     */
    public void startVibrator(long milliseconds) {
        if (mVibrator == null) {
            initVibrator();
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            VibrationEffect vibrationEffect = VibrationEffect.createOneShot(milliseconds, 100);
            mVibrator.vibrate(vibrationEffect);
        } else {
            mVibrator.vibrate(1000);
        }
    }

    /**
     * @param resId        資源id
     * @param milliseconds 震動時間
     * @author Angle
     * 建立時間: 2018/11/4 13:06
     * 方法描述: 同時開始音樂和震動
     */
    public void startVideoAndVibrator(int resId, long milliseconds) {
        playVideo(resId);
        startVibrator(milliseconds);
    }

    /**
     * @author Angle
     * 建立時間: 2018/11/4 13:05
     * 方法描述:  釋放相應的資源
     */
    public void release() {
        //釋放所有的資源
        if (mSoundPool != null) {
            mSoundPool.release();
            mSoundPool = null;
        }

        if (mVibrator != null) {
            mVibrator.cancel();
            mVibrator = null;
        }
    }
}
複製程式碼

因為我們專案中,只用到了相應的播放一個短音訊所以這裡就只簡單的封裝了一下.見諒!!!

使用起來就很簡單了,在你使用的地方直接呼叫

  • startVibrator 單獨的震動
  • playVideo 單獨的聲音
  • startVideoAndVibrator 震動加聲音
  • release 在onPause的時候釋放相應的資源

好了今天的內容就這麼多了,有什麼不明白的地方歡迎騷擾...

相關文章