|
- w% E7 m, k. ]9 `处理音频焦点;尽管某个时刻只有一个activity可以运行,A;Android2.2之前,没有内建的机制来处理这;当你的应用需要输出像乐音和通知之类的音频时,你应;将来的音频焦点是合作的.所以,应用被希望(并被强;要请求音频焦点,你必须从AudioManager;[java];AudioManageraudioManager;getSystemService
2 d8 y0 p9 T' L- F4 `2 [) B, ?" _3 w) E7 Z$ l; E# b0 Z
9 Y6 v& N8 K' J1 ]
; x1 Y" M$ ?; Y2 t1 b处理音频焦点6 t0 ~& l# `+ |; N$ v0 H
2 ^: m0 O5 O: U0 |- s: Z3 R& c尽管某个时刻只有一个activity可以运行,Android却是一个多任务环境.这对使用音频的应用带来了特殊的挑战,因为只有一个音频输出而可能多个媒体都想用它.在
9 _& B1 ~! T# Z& g' o }6 U8 G9 S7 i2 ~+ u4 K$ n) h
Android2.2之前,没有内建的机制来处理这个问题,所以可能在某些情况下导致坏的用户体验.例如,当一个用户正在听音乐而另一个应用需要通知用户一些重要的事情时,用户可能由于音乐声音大而不能听的通知.从Android2.2开始,平台为应用提供了一个协商它们如何使用设备音频输出的途径,这个机制叫做音频焦点.
* L9 |" |: n) [% G7 f
- `0 o# X: G5 B当你的应用需要输出像乐音和通知之类的音频时,你应该总是请求音频焦点.一旦应用具有了焦点,它就可以自由的使用音频输出.但它总是应该监听焦点的变化.如果被通知丢失焦点,它应该立即杀死声音或降低到静音水平(有一个标志表明应选择哪一个)并且仅当重新获得焦点后才恢复大声播放.- Y% ?" G9 H& N
0 v+ o) ` X* c! c1 R* @3 O1 y( |
将来的音频焦点是合作的.所以,应用被希望(并被强列鼓励)遵守音频焦点的方针,但是却不是被系统强制的.如果一个应用在丢失音频焦点后依然想大声播放音乐,系统不会去阻止它.然而用户却体验很坏并且很想把这鸟应用卸载.
7 @) L: H) ^( }2 i# t* {
0 d0 r' h9 P7 j/ T& b7 |要请求音频焦点,你必须从AudioManager调用requestAudioFocus(),如下所示:
1 c$ ~) l Z+ I5 \* p) K; Q5 R: m6 b/ B
[java]
8 w! P1 q$ Q! e; ^5 l0 O# G" D' ^. \2 ~% S1 z# R2 }, l' a: Q
AudioManager audioManager = (AudioManager)
9 m9 |+ k# G5 r3 j2 i! b3 y" N. M! V( I8 I+ h/ Z
getSystemService(Context.AUDIO_SERVICE);6 ]' @7 ^1 Y3 R- i5 I, v
- G& y K( z J @6 L0 Vint result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);! D" u) \1 t# B7 t+ E
h& u3 c6 E4 S& s2 F0 eif (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
" W4 ~9 P$ {( U( x
9 q$ Q3 S3 \& g8 d: s( O+ @; m5 w// 不能获得音频焦点4 S i4 V6 S( ]$ B/ ^4 ]
$ N1 N$ X% F9 ~" s! ]" y+ W}" w) `/ ?! m6 A5 p, y
2 b& f8 H" j2 M# h+ Y0 E
AudioManager audioManager = (AudioManager)! Y$ ^/ {6 L" o2 t+ L
0 Y7 A( P+ i6 B( J: U
getSystemService(Context.AUDIO_SERVICE);
3 n# `2 I3 ~7 |
7 `; O8 f& J3 s8 dint result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);: L9 }( `6 [# f1 B) m5 w% X
2 I: j) a9 o1 w/ C$ ~- I8 qif (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {& L. E1 R: }3 ~1 n/ X
3 ]) G% i. c' [3 d+ R: n& Y: g2 Q/ d. `: H// 不能获得音频焦点
. K& p, X% q2 R+ _- p1 {
9 D3 V1 T! |% ?" e}; r2 Z( L5 n; t* w1 L
2 k( w( j7 a6 J. BrequestAudioFocus()的第一个参数是一个
4 S( `2 E1 p5 o- g3 B! Z% O/ X% r' J- ^5 H( G6 {; t5 V" E
AudioManager.OnAudioFocusChangeListener,它的onAudioFocusChange()方法在音频焦点发改变时被调用.因此,你也应该在你的service和activity上实现此接口.例如:1 f, b- B8 F/ ?" Q
# G; K7 Z/ r& `- b" B0 z5 x[java]2 h0 i9 q% } T! @7 f
* f, c1 C; B2 I6 v2 L* Xclass MyService extends Service; x) _5 z: ~+ f: |3 T4 P
/ n2 g$ d' j. Z* p; c
implements AudioManager.OnAudioFocusChangeListener {# f2 \: s+ {; e, m' ^
# ]; s7 c" Y2 a
// ...." |6 v5 i" e1 K
' a% G! @0 U* K9 _, s* M# D6 T. b! Xpublic void onAudioFocusChange(int focusChange) {
! \4 M( i" k$ \& R$ ]" u% p) D) j( C: K" {* g3 \' G3 c
// Do something based on focus change...% K& k) e7 g' e
/ b8 O' D$ o1 k) ^
}. q# \$ K# D, X5 w4 G* Y2 ^9 t. I9 W
6 B% u% ?+ S* L}! E' _- J" u g& L R: r4 R) G
7 j" A& o; q5 G6 iclass MyService extends Service" ~% {# i- {# ]1 L8 N
& E2 j+ L+ L! [implements AudioManager.OnAudioFocusChangeListener {
+ e/ A( b7 p/ `+ r3 `" P+ \' F H* Z. t' y9 O
// ....
" h6 g- M" X* R5 s }
6 S `$ I& Z) `9 q/ Y+ r- k8 W' i2 g. rpublic void onAudioFocusChange(int focusChange) {
, {# b* V* O/ O. a. q& i% B/ U3 a$ r! C$ f5 \& q8 s
// Do something based on focus change...
4 H7 t/ U3 Y/ K. \9 m# x, q1 C
0 @( n: I$ q/ T1 n; E7 A}3 K0 }5 Z, C" I, ?) u8 E
9 s" Y/ @ @4 `# m/ Z}
5 }* |" V/ a) n3 l; e
+ `8 t% x$ c! o8 L参数focusChange告诉你音频焦点如何发生了变化,它可以是以上几种值(它们都是定义在AudioManager中的常量):
, n9 n7 f3 v, d; k' ~" z
1 `. c, n* Y& Y# f0 v: o3 rAUDIOFOCUS_GAIN:你已获得了音频焦点.
( g- j' d9 Y7 r* x6 V7 |) a
0 N+ e1 S: L: V/ Y$ j! \AUDIOFOCUS_LOSS:你已经丢失了音频焦点比较长的时间了.你必须停止所有的音频播放.因为预料到你可能很长时间也不能再获音频焦点,所以这里是清理你的资源的好地方.比如,你必须释放MediaPlayer.
' E- x2 {( H" e, w$ Z+ J1 `
+ s: s6 n- W9 m2 K, \9 b. c: C- ~AUDIOFOCUS_LOSS_TRANSIENT:你临时性的丢掉了音频焦点,很快就会重新获得.你必须停止所有的音频播放,但是可以保留你的资源,因为你可能很快就能重新获得焦点.
( l( K. L6 N" V4 ?
# R; o& \& }7 B2 n0 |/ N. p9 o. D) qAUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:你临时性的丢掉了音频焦点,但是你被允许继续以低音量播放,而不是完全停止.
5 i2 b% H0 |' \/ C' N
. S, _5 s" N8 o8 K" G4 Y1 z下面是一个例子:% O8 j( d& I, [# z
2 P& H/ U$ E4 R6 M- k! e5 |1 G2 t[java]
: b& [0 R ?& H3 O( f) `+ F+ u; K0 f- E; C7 e2 b
public void onAudioFocusChange(int focusChange) {2 U) z. q4 F' H- b" ?& ?, x
# q) B4 ^2 G( N; w8 Oswitch (focusChange) {
- a7 W2 T3 z1 u. T {
- N# R2 U+ v0 c$ W+ ?case AudioManager.AUDIOFOCUS_GAIN:
: z0 c- `& {1 d
: W7 F' t6 h6 E) l( ?// resume playback) i: B; K& t% o. A7 r) n
* F0 X, D* U1 Y# A& F
if (mMediaPlayer == null) initMediaPlayer();) C$ @1 i" `7 \9 q8 |, _
; d0 J+ o; L: I2 U- Kelse if (!mMediaPlayer.isPlaying()) mMediaPlayer.start(); mMediaPlayer.setVolume(1.0f, 1.0f);
5 |$ `9 X- |+ m8 U+ h O0 L Y$ ^+ ?) Z m, I7 `% L
break;' n5 f( Y8 s# f$ {9 d5 E" g
- f7 ]1 c" | g8 M- x! ]% {+ o: |
case AudioManager.AUDIOFOCUS_LOSS:! K" p# r' I/ A6 t) {* Z
* A: `; K$ D9 x( W4 X1 Y// Lost focus for an unbounded amount of time: stop playback and release media player' q. s+ F+ s) K+ b8 Q0 H: ^: y
7 _5 Z) t( F/ r& G4 _5 aif (mMediaPlayer.isPlaying()) mMediaPlayer.stop();
$ h# y4 Z3 [4 T* B% ^$ V( y* }& U% K: N* U I6 X
mMediaPlayer.release();
0 j! h/ A, A: K4 K x1 D A
; P' F' A( Z1 E i0 K6 dmMediaPlayer = null;5 R5 C$ p( [4 p% T
5 X& p8 F& `" I$ w, k9 ~* S
break;* l% P+ c/ l- a2 ], Z" }
6 ]* i& Z/ H% C4 ]' u/ l! `
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:& a+ W3 ^; V1 f5 U! h- L
8 p2 v( O. K! E
// Lost focus for a short time, but we have to stop; R! F! q/ X8 T8 ]) i: `1 y
' ]6 Y t9 P: |3 \% L. X+ q6 `1 h
// playback. We don't release the media player because playback // is likely to resume+ x# w9 a. E5 S/ Y
7 }9 s w$ a8 ^4 h) Z6 zif (mMediaPlayer.isPlaying()) mMediaPlayer.pause();
* ]6 o5 ^4 u G- z
3 f5 b* O$ k: c1 M; Fbreak;$ M3 G! Q, `6 Y a
' N! f0 F# N3 ~4 U5 U7 gcase AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
- S% M8 D7 X# O2 V; q0 {5 m7 h& [1 B& _& _9 U! h4 j. w N
// Lost focus for a short time, but it's ok to keep playing // at an attenuated level
, \1 G% s, ?6 P2 b* Z) l
$ W: C# i% I% m: Q5 [' {6 m% p' |if (mMediaPlayer.isPlaying()) mMediaPlayer.setVolume(0.1f, 0.1f); break;
f: k2 N) C" N& X6 s6 L+ t
! Y; i( M. L, c$ s- u# F' T8 D: L& C}
& ~5 m$ j8 G3 _' h" V. B! v, m5 b/ Y: a2 s- u2 y2 e. o
}
3 @" o+ p2 V2 D" `" W. H3 @6 _# u. k
public void onAudioFocusChange(int focusChange) {% `- D2 D! R! r" [
4 F3 V' Z) i. K
switch (focusChange) {6 A- c- G. c) W' t" o
' h/ c3 K/ U0 X) [
case AudioManager.AUDIOFOCUS_GAIN:
- N8 ]0 x) C! ?% i ?! E }* ^7 |
, [ i$ B; ^, K# `// resume playback* d% S0 k6 C% V& C" U5 a4 `
' Q! X5 L; v4 k- j# T# Xif (mMediaPlayer == null) initMediaPlayer();( a: y. o/ |( f. W, D! j" O0 F2 H
) c2 J, z& W* t) G6 i/ \
else if (!mMediaPlayer.isPlaying()) mMediaPlayer.start();( M6 E% `. O: F6 F
! H2 R7 p0 [& umMediaPlayer.setVolume(1.0f, 1.0f);5 x) o& I4 }( g) L4 u
$ Y0 B/ R# N3 [9 V9 D. ~# Kbreak;( w3 m# U9 }$ @+ t: p" l
2 {( X9 ]7 O" G. n/ p3 Y
case AudioManager.AUDIOFOCUS_LOSS:4 H. b2 O3 s- k: l9 k6 p$ X$ B
) B# h! E3 o7 ?8 f
// Lost focus for an unbounded amount of time: stop playback and release media player
- @' D, H2 ^( ^# x( H/ D d( O9 Z) ]
if (mMediaPlayer.isPlaying()) mMediaPlayer.stop();, m9 o5 ]# O5 R- [/ c! w6 i" e
/ t! b( a8 k( X" w4 D3 W! |3 O) F8 F
mMediaPlayer.release();
+ |# d6 q6 B$ J4 ~! m
~$ D) e) ^+ l) z( rmMediaPlayer = null;
: o! l& t8 @ y& m. G* j1 z, U# {1 n8 `( z; k7 t7 U. f+ C
break;
+ C' }2 {/ e, u/ K- V8 }" ^% V$ S/ {. Z8 }
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
. O! L1 _% T* K3 C5 w4 f: k. y7 V# h. Z% c
// Lost focus for a short time, but we have to stop4 I+ j- E4 ~$ w6 f9 X& k% z
3 r7 e6 n& L. ?: p) J6 w, J% o// playback. We don't release the media player because playback // is likely to resume
/ U* Q/ M- k4 P8 Z; T T; J( w3 t6 N" M
if (mMediaPlayer.isPlaying()) mMediaPlayer.pause();
+ A& D) J( Q5 B+ K4 q; {5 d/ ~
' R3 a) j* o) A- y) ]1 A% mbreak;
$ e. c" d& [% i$ Y# k0 T
5 a3 O# X6 T3 G8 i7 N5 ecase AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:& h2 z/ g; F3 [; A7 M" f5 d! z* x
8 T! _8 Z5 C9 `7 P5 x// Lost focus for a short time, but it's ok to keep playing // at an attenuated level
" h# |( J5 e- ?" u. Q m
3 O: y& S$ K m8 z: |if (mMediaPlayer.isPlaying()) mMediaPlayer.setVolume(0.1f, 0.1f); break;/ g0 A: G1 P* P8 X p& N0 e4 ?0 j& G
+ A: @: F! l B) Z
}
! z6 ?* b4 e! x/ y* k0 ?% v/ P% o- O4 ~9 g
}
! ^# p1 L* f! f: i8 C3 a. J1 J1 b, y' S
记住音频焦点API仅在APIlevel 8 (Android2.2)及更高版本上可以,所以如果你想支持更早的Android版本,你必须在可能时采取兼容性的策略使用特性,如果不可能,you should adopt a backward compatibility strategy that allows you touse this feature if available, and fall back seamlessly if not.1 H3 Z0 O4 u. Z: U( q
! g( b6 d& {) g) x+ O
你可以用反射的方式调用音频焦点方法或自己在一个单独的类(叫做
9 ] v9 j: @3 r! Z e% v1 Y# o# Y
7 v! V! k7 _) f$ e0 e4 w7 E4 f# ZAudioFocusHelper)中实现所有的音频焦点功能来达到向前兼容.下面是一个这样的类:% a! O6 ^' | |7 u8 i/ Z) d3 l
9 B2 @. [; \7 B3 c- K# c6 k[java]
5 r; G7 ^/ B" i8 a2 c& \3 D8 x
' V3 X8 m% M: {public class AudioFocusHelper implements AudioManager.OnAudioFocusChangeListener {( ?, I0 _* S9 x+ I
6 e, `0 A+ [$ \9 v' ~" N, V- pAudioManager mAudioManager;. `. n' j6 F- H: R
( _- o; \+ N) W6 r" n5 q* @$ f// 这里是其它的字段,你可能要保存一个接口的引用,这个接口2 b. `6 u; U) Y. g: I
2 x/ }8 C) R" L( j; O1 i! l) T
// 被用于与你的service通讯以报告焦点的变化.
& V, p; H; \7 T: D
G, p$ j% W7 [8 lpublic AudioFocusHelper(Context ctx, /* 其它的参数 */) {
+ Q2 D4 c2 @7 f$ A, M0 t1 c
( T( b) B9 o# i8 B9 V, z4 }mAudioManager = (AudioManager)- u8 u' ~! M; g9 r
* S1 A3 z2 H2 |5 G3 \mContext.getSystemService(Context.AUDIO_SERVICE);2 \6 f# s1 \' i/ B4 z, U5 e
2 P: Y, a$ W4 c7 K$ b// ...
; F. K3 X0 C o* V& J5 ?4 U! @0 [
3 _- F4 q' H7 l; h8 K9 a}1 `% T) c% t! E8 G( g: A6 G6 H
! {& U% m, Z* d7 {( \ Q
public boolean requestFocus() {
2 i5 K* ]/ a9 r
. }" h8 z& c3 D4 |( n% @: Rreturn AudioManager.AUDIOFOCUS_REQUEST_GRANTED == |
|