从 Android 静音看正确的查找 bug 的姿势
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了从 Android 静音看正确的查找 bug 的姿势,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含10301字,纯文字阅读大概需要15分钟。
内容图文
![从 Android 静音看正确的查找 bug 的姿势](/upload/InfoBanner/zyjiaocheng/1329/9fe94454aa9b43e2a886ecbb5fffabb2.jpg)
0、写在前面
1、实现个静音的功能
PM:『我这里有个需求,很简单很简单那种』RD:『哦,需要做三天』PM:『真的很简单很简单那种』RD:『哦,现在需要做六天了』
private
void
setMuteEnabled(
boolean
enabled){
AudioManager mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
mAudioManager.setStreamMute(AudioManager.STREAM_MUSIC, enabled);
}
|
2、『您好,我是京东快递,您有一个bug签收一下』
QA:『如果我先开启静音,然后退出我们的app再进来,尽管页面显示静音状态,但我无法取消静音啊』RD:『一定是你的用法有问题!』
boolean
persistedMute = mute.getContext().getSharedPreferences(
"volume"
, Context.MODE_PRIVATE).getBoolean(
"Volume.Mute"
,
false
);
muteButton.setChecked(persistedMute);
|
接着看,这时候我们要取消静音了,调用的代码就是下面这段代码:
private
void
setMuteEnabled(
boolean
enabled){
AudioManager mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
mAudioManager.setStreamMute(AudioManager.STREAM_MUSIC, enabled);
}
|
3、『你可以告诉我该静音或者不静音,但听不听那是我的事儿』
我这么无辜,寥寥几行代码,能犯什么错误呢?所以问题一定出在官方的API上。
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
/**
* Mute or unmute an audio stream.
* <p>
* The mute command is protected against client process death: if a process
* with an active mute request on a stream dies, this stream will be unmuted
* automatically.
* <p>
* The mute requests for a given stream are cumulative: the AudioManager
* can receive several mute requests from one or more clients and the stream
* will be unmuted only when the same number of unmute requests are received.
* <p>
* For a better user experience, applications MUST unmute a muted stream
* in onPause() and mute is again in onResume() if appropriate.
* <p>
* This method should only be used by applications that replace the platform-wide
* management of audio settings or the main telephony application.
* <p>This method has no effect if the device implements a fixed volume policy
* as indicated by {@link #isVolumeFixed()}.
*
* @param streamType The stream to be muted/unmuted.
* @param state The required mute state: true for mute ON, false for mute OFF
*
* @see #isVolumeFixed()
*/
public
void
setStreamMute(
int
streamType,
boolean
state) {
IAudioService service = getService();
try
{
service.setStreamMute(streamType, state, mICallBack);
}
catch
(RemoteException e) {
Log.e(TAG,
"Dead object in setStreamMute"
, e);
}
}
|
The mute requests for a given stream are cumulative: the AudioManager can receive several mute requests from one or more clients and the stream will be unmuted only when the same number of unmute requests are received.
好像找到答案了。不对呀,我以你的人格担保,我只发了一次静音请求啊,怎么取消静音就这么费劲呢!
4、『这是我的名片』
1
2
3
4
5
6
7
8
|
public
void
setStreamMute(
int
streamType,
boolean
state) {
IAudioService service = getService();
try
{
service.setStreamMute(streamType, state, mICallBack);
}
catch
(RemoteException e) {
Log.e(TAG,
"Dead object in setStreamMute"
, e);
}
}
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
/** @see AudioManager#setStreamMute(int, boolean) */
public
void
setStreamMute(
int
streamType,
boolean
state, IBinder cb) {
if
(mUseFixedVolume) {
return
;
}
if
(isStreamAffectedByMute(streamType)) {
if
(mHdmiManager !=
null
) {
synchronized
(mHdmiManager) {
if
(streamType == AudioSystem.STREAM_MUSIC && mHdmiTvClient !=
null
) {
synchronized
(mHdmiTvClient) {
if
(mHdmiSystemAudioSupported) {
mHdmiTvClient.setSystemAudioMute(state);
}
}
}
}
}
mStreamStates[streamType].mute(cb, state);
}
}
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
public
void
mute(
boolean
state) {
boolean
updateVolume =
false
;
if
(state) {
if
(mMuteCount ==
0
) {
// Register for client death notification
try
{
// mICallback can be 0 if muted by AudioService
if
(mICallback !=
null
) {
mICallback.linkToDeath(
this
,
0
);
}
VolumeStreamState.
this
.mDeathHandlers.add(
this
);
// If the stream is not yet muted by any client, set level to 0
if
(!VolumeStreamState.
this
.isMuted()) {
updateVolume =
true
;
}
}
catch
(RemoteException e) {
// Client has died!
binderDied();
return
;
}
}
else
{
Log.w(TAG,
"stream: "
+mStreamType+
" was already muted by this client"
);
}
mMuteCount++;
}
else
{
if
(mMuteCount ==
0
) {
Log.e(TAG,
"unexpected unmute for stream: "
+mStreamType);
}
else
{
mMuteCount--;
if
(mMuteCount ==
0
) {
// Unregister from client death notification
VolumeStreamState.
this
.mDeathHandlers.remove(
this
);
// mICallback can be 0 if muted by AudioService
if
(mICallback !=
null
) {
mICallback.unlinkToDeath(
this
,
0
);
}
if
(!VolumeStreamState.
this
.isMuted()) {
updateVolume =
true
;
}
}
}
}
if
(updateVolume) {
sendMsg(mAudioHandler,
MSG_SET_ALL_VOLUMES,
SENDMSG_QUEUE,
0
,
0
,
VolumeStreamState.
this
,
0
);
}
}
|
01
02
03
04
05
06
07
08
09
10
|
private
class
VolumeDeathHandler
implements
IBinder.DeathRecipient {
private
IBinder mICallback;
// To be notified of client‘s death
private
int
mMuteCount;
// Number of active mutes for this client
VolumeDeathHandler(IBinder cb) {
mICallback = cb;
}
……
}
|
5、『其实,刚才不是我』
对呀,有名片啊,问题是我这是同一个app啊,同一个啊……问题出在哪里了呢。
1
|
private
final
IBinder mICallBack =
new
Binder();
|
操曰:『天下英雄,唯使君与操耳』玄德大惊曰:『操耳是哪个嘛?』
1
|
AudioManager mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
|
1
2
3
4
5
|
@Override
public
Object getSystemService(String name) {
ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
return
fetcher ==
null
?
null
: fetcher.getService(
this
);
}
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public
Object getService(ContextImpl ctx) {
ArrayList<Object> cache = ctx.mServiceCache;
Object service;
synchronized
(cache) {
if
(cache.size() ==
0
) {
// Initialize the cache vector on first access.
// At this point sNextPerContextServiceCacheIndex
// is the number of potential services that are
// cached per-Context.
for
(
int
i =
0
; i < sNextPerContextServiceCacheIndex; i++) {
cache.add(
null
);
}
}
else
{
service = cache.get(mContextCacheIndex);
if
(service !=
null
) {
return
service;
}
}
service = createService(ctx);
cache.set(mContextCacheIndex, service);
return
service;
}
}
|
1
2
3
4
|
registerService(AUDIO_SERVICE,
new
ServiceFetcher() {
public
Object createService(ContextImpl ctx) {
return
new
AudioManager(ctx);
}});
|
等会儿让我想会儿静静。它在这里new了一个AudioManager。它怎么能new了一个AudioManager呢。
1
|
AudioManager mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
|
6、『这事儿还是交给同一个人办比较靠谱』
1
|
AudioManager mAudioManager = (AudioManager) getContext().getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
|
7、结语
侯捷先生在《STL源码剖析》一书的扉页上面写道『源码之前,了无秘密』。写程序的时候,我经常会因为运行结果与预期不一致而感到不悦,甚至抱怨这就是『命』,想想也是挺逗的。计算机总是会忠实地执行我们提供的程序,如果你发现它『不听』指挥,显然是你的指令有问题;除此之外,我们的指令还需要经过层层传递,才会成为计算机可以执行的机器码,如果你对系统api的工作原理不熟悉,对系统的工作原理不熟悉,你在组织自己的代码的时候就难免一厢情愿。
至于官方API文档,每次看到它都有看到『课本』一样的感觉。中学的时候,老师最爱说的一句话就是,『课本要多读,常读常新』。官方API呢,显然也是这样。没有头绪的时候,它就是我们救星啊。
作为Android开发者,尽管我不需要做Framework开发,但这并不能说明我不需要对Framework有一定的认识和了解。我们应该在平时的开发和学习当中经常翻阅这些系统的源码,了解它们的工作机制有助于我们更好的思考系统api的应用场景。
关于Android系统源码,如果不是为了深入的研究,我比较建议直接在网上直接浏览:
* [Androidxref](http://androidxref.com/),该站点提供了一定程度上的代码跳转支持,以及非常强大的检索功能,是我们查询系统源码的首选。
* [Grepcode](http://grepcode.com/)也可以检索Android系统源码,与前者不同的是,它只包含Java代码,不过也是尺有所长,grepcode在Java代码跳转方面的支持已经非常厉害了。
原文:http://www.cnblogs.com/krislight1105/p/5203164.html
内容总结
以上是互联网集市为您收集整理的从 Android 静音看正确的查找 bug 的姿势全部内容,希望文章能够帮你解决从 Android 静音看正确的查找 bug 的姿势所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。