国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專(zhuān)欄INFORMATION COLUMN

淺談Android O Touch聲音播放流程

XiNGRZ / 2597人閱讀

摘要:前言當(dāng)我們點(diǎn)擊屏幕按鍵時(shí),就會(huì)聽(tīng)到音,那么音是如何播放起來(lái)的呢,由于最近項(xiàng)目需求順便熟悉下了音的邏輯。完成的繪制過(guò)程,包括過(guò)程。向分發(fā)收到的用戶(hù)發(fā)起的事件,如按鍵,觸屏等事件。總結(jié)音的流程就簡(jiǎn)單分析到這里,歡迎大家交流指正。

前言

當(dāng)我們點(diǎn)擊屏幕按鍵時(shí),就會(huì)聽(tīng)到touch音,那么touch音是如何播放起來(lái)的呢,由于最近項(xiàng)目需求順便熟悉下了touch音的邏輯。

正文

談touch邏輯首先要說(shuō)下這個(gè)類(lèi)ViewRootImpl.java,位于frameworks/base/core/java/android/view下,ViewRootImpl的主要功能:
A:鏈接WindowManager和DecorView的紐帶,更廣一點(diǎn)可以說(shuō)是Window和View之間的紐帶。
B:完成View的繪制過(guò)程,包括measure、layout、draw過(guò)程。
C:向DecorView分發(fā)收到的用戶(hù)發(fā)起的event事件,如按鍵,觸屏等事件。
關(guān)于ViewRootImpl的源碼可參照博客ViewRootImpl類(lèi)源碼解析,我們從performFocusNavigation()入手

private boolean performFocusNavigation(KeyEvent event) {
    //略
    if (v.requestFocus(direction, mTempRect)) {
        playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));
        return true;
    }
    //略
    return false;
}

當(dāng)我們點(diǎn)擊某個(gè)控件時(shí),會(huì)先觸發(fā)performFocusNavigation()這個(gè)方法,然后當(dāng)控件獲取到focus后便會(huì)調(diào)用playSoundEffect()方法,我只截取了performFocusNavigation()中關(guān)鍵代碼playSoundEffect()部分,來(lái)看下playSoundEffect()這個(gè)方法

    public void playSoundEffect(int effectId) {
        checkThread();

        try {
            final AudioManager audioManager = getAudioManager();

            switch (effectId) {
                case SoundEffectConstants.CLICK:
                    audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
                    return;
                case SoundEffectConstants.NAVIGATION_DOWN:
                    audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
                    return;
                case SoundEffectConstants.NAVIGATION_LEFT:
                    audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);
                    return;
                case SoundEffectConstants.NAVIGATION_RIGHT:
                    audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);
                    return;
                case SoundEffectConstants.NAVIGATION_UP:
                    audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);
                    return;
                default:
                    throw new IllegalArgumentException("unknown effect id " + effectId +
                            " not defined in " + SoundEffectConstants.class.getCanonicalName());
            }
        } catch (IllegalStateException e) {
            // Exception thrown by getAudioManager() when mView is null
            Log.e(mTag, "FATAL EXCEPTION when attempting to play sound effect: " + e);
            e.printStackTrace();
        }
    }

發(fā)現(xiàn)調(diào)用了audioManager的playSoundEffect()方法,audiomanager就不說(shuō)了,接觸android audio最先接觸的可能就是AudioManager了,音量控制,聲音焦點(diǎn)申請(qǐng)等。接著看

    public void  playSoundEffect(int effectType) {
        if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) {
            return;
        }
        //查詢(xún)是否開(kāi)啟touch音,如果settings中關(guān)閉了,則直接返回
        if (!querySoundEffectsEnabled(Process.myUserHandle().getIdentifier())) {
            return;
        }

        final IAudioService service = getService();
        try {
            //調(diào)用到AudioService的playSoundEffect()
            service.playSoundEffect(effectType);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

查詢(xún)touch音是否可播放,因?yàn)楫吘乖赼ndroid的setting中有個(gè)touch音的開(kāi)關(guān),如果可播放則調(diào)用到AudioService的playSoundEffect()

    public void playSoundEffect(int effectType) {
        playSoundEffectVolume(effectType, -1.0f);
    }
    
    public void playSoundEffectVolume(int effectType, float volume) {
        if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
            Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
            return;
        }

        sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
                effectType, (int) (volume * 1000), null, 0);
    }

其實(shí)AudioService初始化的時(shí)候會(huì)創(chuàng)建一個(gè)子線(xiàn)HandlerThread,HandlerThread主要處理一些相對(duì)耗時(shí)的操作,這里將播放touch音的功能放在了這個(gè)子線(xiàn)程中去執(zhí)行,這樣避免了主線(xiàn)程的阻塞,其實(shí)大家在做mediaplayer播放時(shí)也建議放在子線(xiàn)程去播放,接下來(lái)看看handler里對(duì)消息的處理,關(guān)鍵代碼如下

case MSG_PLAY_SOUND_EFFECT:
     if (msg.obj == null) {
         onPlaySoundEffect(msg.arg1, msg.arg2, 0);
    } else {
        onPlaySoundEffect(msg.arg1, msg.arg2, (int) msg.obj);
     }
     break;

直接調(diào)用onPlaySoundEffect()的方法

       private void onPlaySoundEffect(int effectType, int volume) {
            synchronized (mSoundEffectsLock) {
                //初始化mSoundPool和要播放的資源文件
                onLoadSoundEffects();

                if (mSoundPool == null) {
                    return;
                }
                float volFloat;
                // use default if volume is not specified by caller
                if (volume < 0) {
                    volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
                } else {
                    volFloat = volume / 1000.0f;
                }

                if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
                    //播放touch音
                    mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
                                        volFloat, volFloat, 0, 0, 1.0f);
                } else {
                    MediaPlayer mediaPlayer = new MediaPlayer();
                    try {
                        String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
                                    SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
                        mediaPlayer.setDataSource(filePath);
                        mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
                        mediaPlayer.prepare();
                        mediaPlayer.setVolume(volFloat);
                        mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
                            public void onCompletion(MediaPlayer mp) {
                                cleanupPlayer(mp);
                            }
                        });
                        mediaPlayer.setOnErrorListener(new OnErrorListener() {
                            public boolean onError(MediaPlayer mp, int what, int extra) {
                                cleanupPlayer(mp);
                                return true;
                            }
                        });
                        mediaPlayer.start();
                    } catch (IOException ex) {
                        Log.w(TAG, "MediaPlayer IOException: "+ex);
                    } catch (IllegalArgumentException ex) {
                        Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
                    } catch (IllegalStateException ex) {
                        Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
                    }
                }
            }
        }

最終通過(guò)soundPool來(lái)播放指定的資源文件實(shí)現(xiàn)了touch音的播放,因此大家在工作中如果有什么需要對(duì)應(yīng)touch音的邏輯,可參照AudioService的onPlaySoundEffect()中的邏輯。
比如指定touch音的AudioAttributes使touch音輸出到指定的device上等。

總結(jié)

touch音的流程就簡(jiǎn)單分析到這里,歡迎大家交流指正。
努力學(xué)習(xí)ing~

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/72669.html

相關(guān)文章

  • 淺談Android O Notification聲音播放流程

    摘要:在線(xiàn)程中,在中創(chuàng)建線(xiàn)程在線(xiàn)程中通過(guò)播放饒了一大圈竟然也用來(lái)播放就是從傳下來(lái)的需要注意,通知音是會(huì)申請(qǐng)焦點(diǎn)的。總結(jié)從創(chuàng)建到播放的流程基本就這樣,至于聲音的區(qū)分是否電話(huà)中,如果則使用播放,反之播放。 前言 我們?cè)谧鯝ndroid開(kāi)發(fā)的時(shí)候,免不了會(huì)使用到Notification,而且在android設(shè)備的設(shè)置中還可以設(shè)置通知音的優(yōu)先級(jí),以及播放的聲音種類(lèi)。那么通知音是如何播放的呢,今天我們...

    huhud 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<