当前位置:  ▪Android实现动态显示或隐藏密码输入框的内容 iis7站长之家
本页文章导读:
    ▪SpriteKit官方文档翻译跟学习(二)-Jumping into Sprite Kit        SpriteKit官方文档翻译和学习(二)---Jumping into Sprite Kit深入SpriteKit 学习Sprite Kit最好的途径是实战,下面通过一个例子来初探SpriteKit。通过这个例子,你将会学到以下内容: 在一个以SpriteKit.........
    ▪ (三)选择元素——(6)属性选择器(Attribute selectors)        (3)选择元素——(6)属性选择器(Attribute selectors)Attribute selectors are a particularly helpful subset of CSS selectors. They allow us to specify an element by one of its HTML attributes, such as a link's title attribute or an.........
    ▪ AudioManager详解(组合源代码)       AudioManager详解(结合源代码) AudioManager:用来对音量大小,声音模式(静音,震动,震动加声音等模式)的管理, 还有用它来注册“插入耳机”时的广播接收者(Action: android.intent.action.MEDIA_BUTTON).........

[1]SpriteKit官方文档翻译跟学习(二)-Jumping into Sprite Kit
    来源: 互联网  发布时间: 2014-02-18
SpriteKit官方文档翻译和学习(二)---Jumping into Sprite Kit
深入SpriteKit

学习Sprite Kit最好的途径是实战,下面通过一个例子来初探SpriteKit。通过这个例子,你将会学到以下内容:

  • 在一个以SpriteKit框架为基础的游戏中使用场景(scenes)。
  • 组织节点数并绘制内容。
  • 使用动作(actions)为场景内容做动画。
  • 为一个场景添加交互。
  • 场景之间的切换。
  • 场景中的模拟物理环境。
创建项目

整个项目需要使用Xocde5.0的集成开发环境。使用Single View Application模版创建项目。创建项目的时候使用以下参数:

  • Product Name:SpriteWalkthrough

  • Class Prefix:Sprite

  • Devices:iPad

创建你的第一个场景

Sprite Kit框架内容像其他可视内容一样被放置于一个Window视窗里。SptiteKit框架里的内容都是通过SKView类进行渲染,通常都是首先渲染场景,场景是一个SKScene对象。场景也参与响应链,同时还拥有一些专为游戏匹配的其他特性。

因为SpriteKit框架内容是通过一个视图对象渲染出来的,所以你可以将这个视图与其他视图按照视图层级关系排列。例如你可以创建一个按钮控制层放置在SpriteKit视图之上。或者,你还可以通过按钮为sprite添加交互。之后的例子中,你将看到如何为场景添加交互。


使用Sptite Kit来配置视图控制器

  • 打开项目里的storyboard。它只有一个单独的视图控制器(SpriteViewontroller)。选择视图控制器的view视图对象,将它的class改为SKView。
  • 在视图控制器的实现文件头部添加下面代码。

    #import <SpriteKit/SpriteKit.h>

  • 实现视图控制器的ViewDidLoad方法配置视图。
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        SKView *spriteView = (SKView *) self.view;
        spriteView.showsDrawCount = YES;
        spriteView.showsNodeCount = YES;
        spriteView.showsFPS = YES;
    }
    这段代码打开了性能调试信息模块,用来描述场景的渲染情况。帧频(spriteView.showFPS)是最重要的信息。另外两个是描述了为视图中一共有多少个节点显示出来,渲染内容一共绘制了多少次(越少越好)。

  • 接下来,添加第一个场景。

    创建Hello场景:

  • 创建一个继承自SKScene类名为HelloScene子类。
    头文件:
    #import <SpriteKit/SpriteKit.h>
     
    @interface HelloScene : SKScene
     
    @end
    你不需要做任何修改
  • 在视图控制器实现文件中导入场景类的头文件。
    #import "HelloScene.h"
  • 修改视图控制器,创建一个场景,并在视图中显示
    - (void)viewWillAppear:(BOOL)animated
    {
        HelloScene* hello = [[HelloScene alloc] initWithSize:CGSizeMake(768,1024)];
        SKView *spriteView = (SKView *) self.view;
        [spriteView presentScene: hello];
    }
  • 运行。
    程序运行后会显示一个场景,但是是空的,只有性能调试信息模块。
  • 为你的场景添加内容

    当你制作一款基于SpriteKit框架的游戏时,你可能会根据模块为你的游戏创建不同的场景。例如,为你的主菜单创建一个单独的场景、为你的游戏模块分配一个场景。我们的这个例子也遵循相同的设计,第一个场景显示一个“Hello World”文本。

     通常情况下,我们是在场景已经被视图显示出来的时候为场景创建内容。这个例子中,代码应该写在didMoveToView:方法中,说明场景已经被加载到视图中。

    在场景中显示Hello World文本

  • 在场景实现文件中添加一个属性,来判断场景是否为自身已经创建了内容。
    你的实现文件应该如下:
    #import "HelloScene.h"
     
    @interface HelloScene ()
    @property BOOL contentCreated;
    @end
     
    @implementation HelloScene
     
    @end

    这个属性并不需要暴露在外部,所以它实现了一个私有访问权限,定义在实现文件中。
  • 实现场景的didMoveToView:方法。
    - (void)didMoveToView: (SKView *) view
    {
        if (!self.contentCreated)
        {
            [self createSceneContents];
            self.contentCreated = YES;
        }
    }

    当场景已经被加载进视图的时候调用didMoveToView:方法,但是在这种情况下,内容部分只应该在场景第一次被加载时创建,所以需要使用之前定义的属性(contentCreated)来判断场景内容是否已经被创建过。
  • 实现场景的createSceneContents:方法。
    - (void)createSceneContents
    {
        self.backgroundColor = [SKColor blueColor];
        self.scaleMode = SKSceneScaleModeAspectFit;
        [self addChild: [self newHelloNode]];
    }

    为场景定义背景颜色,这里的颜色定义使用的是SKColor,它并不是一个类,它是指向UIColor的一个宏。只是为了让代码更统一。

    场景的scaleMode属性确定场景如何缩放来适应视图(这个例子中我四个属性都试了,没看出变化来,知道的讲解一下,请赐教)。
  • 实现场景的newHelloNode方法。
    - (SKLabelNode *)newHelloNode
    {
        SKLabelNode *helloNode = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];
        helloNode.text = @"Hello, World!";
        helloNode.fontSize = 42;
        helloNode.position = CGPointMake(CGRectGetMidX(self.frame),CGRectGetMidY(self.frame));
        return helloNode;
    }

    在SpriteKit框架中,你不能想使用OpenGL ES或Quartz 2D那样直接执行绘制请求。而是通过创建节点对象并添加他们到场景来添加内容。所有绘制必须由SpriteKit内置类来完成,你可以自定义这些类的行为从而产生不同的图形效果。
  • 运行。你将看到一个带有“Hello, World!”文本的蓝色场景。
  • 为你的场景动画添加动作

    你可以通过定义一个action对象描述一些动作,让节点运行。当场景渲染的时候,它就会执行这些动作。

    当用户触摸屏幕的时候,文本会做一些动画,然后消失。


    为文本添加动画:

  • 接着为newHelloNode方法添加下面的代码:
    helloNode.name = @"helloNode";
    所有节点都有一个描述自身的name属性。以便之后可以通过name属性寻找对应节点。
    通常在游戏中,你可以给场景内容所有同一类型的节点一个相同的name属性。例如你将游戏中所有怪兽节点定义一个相同的name属性:“monster”。
  • 重写场景类中的touchesBegan:withEvent:方法。当场景接收到触摸时间的时候,它会寻找name属性为helloNode的节点并让它运行一个短暂的动画。
    在ios中,所有的节点对象都是UIResponder子类。这意味着你可以创建节点类的子类,并为场景中的节点添加交互。
    - (void)touchesBegan:(NSSet *) touches withEvent:(UIEvent *)event
    {
        SKNode *helloNode = [self childNodeWithName:@"helloNode"];
        if (helloNode != nil)
        {
            helloNode.name = nil;
            SKAction *moveUp = [SKAction moveByX: 0 y: 100.0 duration: 0.5];
            SKAction *zoom = [SKAction scaleTo: 2.0 duration: 0.25];
            SKAction *pause = [SKAction waitForDuration: 0.5];
            SKAction *fadeAway = [SKAction fadeOutWithDuration: 0.25];
            SKAction *remove = [SKAction removeFromParent];
            SKAction *moveSequence = [SKAction sequence:@[moveUp, zoom, pause, fadeAway, remove]];
            [helloNode runAction: moveSequence];
        }
    }
    为了避免节点重复响应这个进程,代码中清除了节点的name属性。然后定义一些action对象执行不同的动作。最后将这些动作合并在一个队列中,按顺序执行。
  • 运行。(效果什么样,自己敲出来看看)
  • 场景切换
    Sprite Kit框架可以很容易的做场景切换。你可以让场景保持持续的切换,或者控制它们的切换。在这个例子中,你可以通过创建第二个场景来学习其他一些游戏行为。当“Hello, world!”文本从屏幕上消失时,我们创建一个新的场景替换它。切换之后Hello场景会被丢弃。

    创建一个宇宙飞船场景

  • 创建一个SKScene的子类,并命名为SpaceshipScene。
  • 初始化太空飞船场景,代码与HelloScene类似。
    @import "SpaceshipScene.h"
     
    @interface SpaceshipScene ()
    @property BOOL contentCreated;
    @end
     
    @implementation SpaceshipScene
    - (void)didMoveToView:(SKView *)view
    {
        if (!self.contentCreated)
        {
            [self createSceneContents];
            self.contentCreated = YES;
        }
    }
     
    - (void)createSceneContents
    {
        self.backgroundColor = [SKColor blackColor];
        self.scaleMode = SKSceneScaleModeAspectFit;
    }
    @end

  • 在HelloScene.m文件中import进SpaceShipScene.h头文件。
    #import "SpaceshipScene.h"

  • 在HelloScene类的touchesBegin:withEvent:方法中将runAction:方法替换为runAction:completion:方法。在完成处理器中创建并呈现一个新的场景。
    [helloNode runAction: moveSequence completion:^{
        SKScene *spaceshipScene  = [[SpaceshipScene alloc] initWithSize:self.size];
        SKTransition *doors = [SKTransition doorsOpenVerticalWithDuration:0.5];
        [self.view presentScene:spaceshipScene transition:doors];
    }];

  • 运行。当你触摸场景的时候,文字会消失,然后切换到新的黑色场景。
  • 使用节点为场景创建一个合成的内容

    接下来要为场景添加一个宇宙飞船。你要使用多个SKSpriteNode对象创建一个宇宙飞船,并且在它表面有发光。每一个节点都要执行一些动作。

    SKSpriteNode是SpriteKit框架中创建内容最常见的类。它们可以绘制有纹理和无纹理的矩形。这个例子中你将使用无纹理的物体。之后你也可以很容易的使用有纹理的物体将无纹理的物体替换而不需要改变它的行为。有时候,你可能需要使用几十甚至上百个节点为你的游戏创建可视化内容。但是,本质上,这些sprite都使用的是相同的方法去创建,正如我们这个例子。 

    虽然你可以直接将这三个sprite添加到创景当中国,但SpriteKit框架不提倡这么做。闪烁的光是宇宙飞船的一部分!如果飞船移动,光也要跟着移动。解决的办法是将光变成飞船的子视图。光的坐标就相对于它的父节点位置定位在sptite图像的中心。


    添加宇宙飞船

  • 在SpaceshipScene.m文件,接着在createSceneContents方法中输入一下代码来创建宇宙飞船。
    SKSpriteNode *spaceship = [self newSpaceship];
    spaceship.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame)-150);
    [self addChild:spaceship];

  • 实现newSpaceship方法。
    - (SKSpriteNode *)newSpaceship
    {
        SKSpriteNode *hull = [[SKSpriteNode alloc] initWithColor:[SKColor grayColor] size:CGSizeMake(64,32)];
     
        SKAction *hover = [SKAction sequence:@[
                              [SKAction waitForDuration:1.0],
                              [SKAction moveByX:100 y:50.0 duration:1.0],
                              [SKAction waitForDuration:1.0],
                              [SKAction moveByX:-100.0 y:-50 duration:1.0]]];
        [hull runAction: [SKAction repeatActionForever:hover]];
     
        return hull; }

    这个方法中创建了一个船体,并且引入了一个新的动作类型。重复的执行传入的动作。这个例子中,将无限的执行队列动作。
  • 运行程序,你将看到一个单独的矩形船体。
  • 在newSpaceship方法中添加下面的代码来创建光。
    SKSpriteNode *light1 = [self newLight];
    light1.position = CGPointMake(-28.0, 6.0);
    [hull addChild:light1];
     
    SKSpriteNode *light2 = [self newLight];
    light2.position = CGPointMake(28.0, 6.0);
    [hull addChild:light2];

  • 实现newLight方法
    - (SKSpriteNode *)newLight
    {
        SKSpriteNode *light = [[SKSpriteNode alloc] initWithColor:[SKColor yellowColor] size:CGSizeMake(8,8)];
     
        SKAction *blink = [SKAction sequence:@[
                              [SKAction fadeOutWithDuration:0.25],
                              [SKAction fadeInWithDuration:0.25]]];
        SKAction *blinkForever = [SKAction repeatActionForever:blink];
        [light runAction: blinkForever];
     
        return light;
    }

  • 运行程序。你将看到一个带有两个发光体的宇宙飞船。它们一起不间断的移动。
  • 创建带有相互交互的节点

    在真实游戏中,你通常需要节点直接带有交互性。为sprite(精灵)添加行为又多种方式,这个例子只展示其中一种。你将为场景添加一些新的节点并使用物理系统模拟它们运动,实现碰撞效果。

    SpriteKit框架提供了一个完整的物理模拟环境,你可以为你的接的添加自动化的行为。不需要为节点实现行为(action),模拟物理环境将自动为节点添加这些行为,使它们的移动。当一个节点与其他处于物理系统中的节点接触的时候,会自动检测碰撞。

    为宇宙飞船场景添加物理环境

  • 修改newSpaceship方法,为飞船添加一个物理刚体。
    hull.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:hull.size];
  • 运行程序。
    由于重力的原因,飞船会沿着屏幕底部垂直落下。并且飞船移动的动作与重力作用同时存在。
  • 修改newSpaceship方法,防止飞船受到物理影响。
    hull.physicsBody.dynamic = NO;
    现在再次运行程序,飞船不再受到重力的影响,像之前一样运动。之后,由于它属于静态物体,所以碰撞也不会影响它的速率。
  • 在creatSceneContents方法中添加以下代码,效果是创建大量岩石
    SKAction *makeRocks = [SKAction sequence: @[
        [SKAction performSelector:@selector(addRock) onTarget:self],
        [SKAction waitForDuration:0.10 withRange:0.15]
        ]];
    [self runAction: [SKAction repeatActionForever:makeRocks]];
    场景也是一个节点,因此它也可以执行动作。在这里,由自定义的动作在场景中执行一个方法来创建一个岩石。场景会在一个随机的时间间隔中持续的创建新岩石。
  • 实现addRock方法
    static inline CGFloat skRandf() {
        return rand() / (CGFloat) RAND_MAX;
    }
     
    static inline CGFloat skRand(CGFloat low, CGFloat high) {
        return skRandf() * (high - low) + low;
    }
     
    - (void)addRock
    {
        SKSpriteNode *rock = [[SKSpriteNode alloc] initWithColor:[SKColor brownColor] size:CGSizeMake(8,8)];
        rock.position = CGPointMake(skRand(0, self.size.width), self.size.height-50);
        rock.name = @"rock";
        rock.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:rock.size];
        rock.physicsBody.usesPreciseCollisionDetection = YES;
        [self addChild:rock];
    }

  • 运行程序。
    大量岩石会从屏幕顶端落下。当岩石碰到飞船,会被反弹开。不需要为岩石添加动作,它们会受到物理系统的作用力发生下降和碰撞。
    岩石小而移动迅速,代码中指定了精准碰撞检测也确保碰撞的准确性。
    如果你运行一段时间,你会发现即使节点的数量保持很低的值,但是帧频开始下降。这是因为代码中只让场景中的可见节点纳入节点数量计算当中。然而,当岩石掉落至屏幕底部之后,它们仍然存在于场景中。这意味着它们仍然存在于物理环境中。最终,大量的节点导致SpriteKit框架运行缓慢。
  • 在场景中实现didSimulatePhysics方法,移除掉移动到屏幕之外的岩石。
    -(void)didSimulatePhysics
    {
        [self enumerateChildNodesWithName:@"rock" usingBlock:^(SKNode *node, BOOL *stop) {
            if (node.position.y < 0)
                [node removeFromParent];
        }];
    }
    
    当场景处理每一帧的时候,都会执行动作和模拟物理环境。这时你的游戏也会在这个时候执行一些其他的自定义代码。现在,当应用运行到一个新的帧动画的时,它在物理环境下,将移出屏幕外的岩石移除,所以,当程序运行时,帧频就比较稳定了。





  •     
    [2] (三)选择元素——(6)属性选择器(Attribute selectors)
        来源: 互联网  发布时间: 2014-02-18
    (3)选择元素——(6)属性选择器(Attribute selectors)
    Attribute selectors are a particularly helpful subset of CSS selectors. They allow us to specify an element by one of its HTML attributes, such as a link's title attribute or an image's alt attribute. 
    属性选择器是一个相当有用css选择器的子集。它允许我们通过一个元素的html属性去明确一个元素,比如一个链接的title属性或者一个图片的alt属性。
    For example, to select all images that have an alt attribute, we write the following:$('img[alt]')Attribute selectors accept a wildcard syntax inspired by regular expressions for identifying the value at the beginning (^) or ending ($) of a string. They can also take an asterisk (*) to indicate the value at an arbitrary position within a string or an exclamation mark (!) to indicate a negated value.
    比如,为了选择所有有着alt属性的的图片,我们写下下面的$("img[alt]")属性选择器,接受一个使用有规则的表达式的通配符语法用来明确一个字符串开始(^)和结束($)的值。他们也可以使用星号(*)去表明在某一个位置有某个值,或者使用叹号(!)去表明一个相反的值。

        
    [3] AudioManager详解(组合源代码)
        来源: 互联网  发布时间: 2014-02-18
    AudioManager详解(结合源代码)


    AudioManager:用来对音量大小,声音模式(静音,震动,震动加声音等模式)的管理, 还有用它来注册“插入耳机”时的广播接收者(Action: android.intent.action.MEDIA_BUTTON)

    源码(没有Android源码的可以看下我之前的博文,有提供下载地址哈~)所在位置:
    Android-4.0/frameworks/base/media/java/android/media/AudioManager.java


    一. 首先在应用层面上分析下怎么使用这个类:

    1.获取AudioManager实例对象
    AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);

    2.AudioManager能实现的一些基本的功能的函数介绍


    adjustStreamVolume(int streamType, int direction, int flags)
    /**
    方法分析:(通过该方法可以控制特定的声音的音量)

    用"步长"调整手机声音大小的函数(Adjusts the volume of a particular stream by one step in a direction.)
    这个函数只能用于应用程序对Audio属性的设置或者通话(telephony)应用程序

    streamType(表示要处理的声音是哪种):
        能使用的streamType的值包括:
        STREAM_VOICE_CALL(通话)
        STREAM_SYSTEM(系统声音)
        STREAM_RING(铃声)
        STREAM_MUSIC(音乐)
        STREAM_ALARM(闹铃)
        
    direction(“方向”:顾名思义是要往上增加音量,往下减少音量,还是维持不变):
        能使用的值有:
        ADJUST_LOWER(降低)
        ADJUST_RAISE(升高)
        ADJUST_SAME(维持原来的)[呵~~呵]

    flags(可选标志位):
        flags One(单个参数) or more flags.(参数1|参数2|参数3..)
        如下flag:
            AudioManager.FLAG_SHOW_UI(显示出音量调节UI)
            AudioManager.FLAG_ALLOW_RINGER_MODES
            AudioManager.FLAG_PLAY_SOUND
            AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE
            AudioManager.FLAG_VIBRATE

    对应get方法:
        getStreamVolume(int streamType)
        最大值为7,最小值为0,当为0时,手机自动将模式调整为“震动模式”
    */


    adjustVolume(int direction, int flags)
    /**
    方法分析:
    系统智能地判断现在是要处理的是哪个类型的声音("通话音","媒体音"等)
    如果你在打电话,这个时候这个函数相应处理的就是"通话音",而如果你在听歌,处理的就是“媒体音”~~平时其实用一些软件也是有这种感觉的哈~~

    direction(“方向”:顾名思义是要往上增加音量,往下减少音量,还是维持不变):
        能使用的值有:
        ADJUST_LOWER(降低)
        ADJUST_RAISE(升高)
        ADJUST_SAME(维持原来的)[呵~~呵]

    flags(可选标志位):
        flags One(单个参数) or more flags.(参数1|参数2|参数3..)
        如下flag:
            AudioManager.FLAG_SHOW_UI(显示出音量调节UI)
            AudioManager.FLAG_ALLOW_RINGER_MODES
            AudioManager.FLAG_PLAY_SOUND
            AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE
            AudioManager.FLAG_VIBRATE

    */

    int getMode()
    /**
    方法分析:
    得到声音的模式

    返回值(int)对应的宏:
        MODE_INVALID: 发生异常的时候返回
        MODE_NORMAL: 普通模式
        MODE_RINGTONE:铃声模式
        MODE_IN_CALL: 通话模式
        MODE_IN_COMMUNICATION:通话模式

    对应set方法:
        setMode(int mode)
    */


    int getRingerMode()
    /**
    方法分析:
    得到铃声设置的模式

    返回值(int)对应的宏:
        RINGER_MODE_NORMAL(铃声模式)
             RINGER_MODE_SILENT(静音模式)
        RINGER_MODE_VIBRATE(静音但是震动)

    对应set方法(改变铃声模式):
        setRingerMode(int ringerMode)
    */

    getStreamMaxVolume(int streamType)
    /**

    方法分析:
        得到手机最大的音量

    */

    setStreamMute(int streamType, boolean state)
    /**

    方法分析:
        让streamType指定的对应的声音流做处理
        state为true表示让它静音,false表示不让它静音
        如:让音乐静音
        setStreamMute(AudioManager.STREAM_MUSIC , true);
    */


    3.实例Demo代码

    //获取实例
    AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
    
    //获取/设置系统音量
    audioManager.getStreamVolume(AudioManager.STREAM_SYSTEM);
    audioManager.setStreamVolume(AudioManager.STREAM_SYSTEM,
                AudioManager.ADJUST_RAISE
                , AudioManager.FLAG_SHOW_UI);
    //获取/设置音乐音量
    audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
    audioManager.setStreamVolume(AudioManager.STREAM_MUSIC,
                AudioManager.ADJUST_RAISE
                , AudioManager.FLAG_SHOW_UI);
    //其他的类似
    
    
    
    //获取/设置铃声的模式
    int ringMode = audioManager.getRingerMode();
    //普通模式
    audioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
    //静音模式
    audioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
    //其他的类似
    
    //设置声音流静音/不静音
    //音乐静音
    audioManager.setStreamMute(AudioManager.STREAM_MUSIC, true);
    //铃声不静音
    audioManager.setStreamMute(AudioManager.STREAM_RING, false);
    //其他的类似





    二. 分析下这个类里面的部分源代码


    由于知识水平有限,我觉得下面的代码自己分析不好,建议看这篇博文:http://blog.csdn.net/qinjuning/article/details/6938436



     /*
        为Action == “MEDIA_BUTTON”注册广播接收者
    
        用来广播“耳机插入”的事件
    
        eventReceiver一般接受的参数为这样一个ComponentName对象
    
        如:
        AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
        ComponentName component = new ComponentName(context.getApplicationContext(),MediaControlReceiver.class);
        audioManager.registerMediaButtonEventReceiver(component);    
        
    */
     public void registerMediaButtonEventReceiver(ComponentName eventReceiver) {
            if (eventReceiver == null) {
                return;
            }
            if (!eventReceiver.getPackageName().equals(mContext.getPackageName())) {
                Log.e(TAG, "registerMediaButtonEventReceiver() error: " +
                        "receiver and context package names don't match");
                return;
            }
            // construct a PendingIntent for the media button and register it
            Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
            //     the associated intent will be handled by the component being registered
            mediaButtonIntent.setComponent(eventReceiver);
            PendingIntent pi = PendingIntent.getBroadcast(mContext,
                    0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/);
            registerMediaButtonIntent(pi, eventReceiver);
        }
    
    /**
    为MediaButton注册一个Intent
    可以发现,这边也是通过aidl的方式进行的调用
    IAudioService的aidl:https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/media/java/android/media/IAudioService.aidl  
    */
        public void registerMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver) {
            if ((pi == null) || (eventReceiver == null)) {
                Log.e(TAG, "Cannot call registerMediaButtonIntent() with a null parameter");
                return;
            }
            IAudioService service = getService();
            try {
                // pi != null
                service.registerMediaButtonIntent(pi, eventReceiver);
            } catch (RemoteException e) {
                Log.e(TAG, "Dead object in registerMediaButtonIntent"+e);
            }
        }
    
        /**
         * Unregister the receiver of MEDIA_BUTTON intents.
         * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
         *      that was registered with {@link #registerMediaButtonEventReceiver(ComponentName)}.
         */
        public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) {
            if (eventReceiver == null) {
                return;
            }
            // construct a PendingIntent for the media button and unregister it
            Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
            //     the associated intent will be handled by the component being registered
            mediaButtonIntent.setComponent(eventReceiver);
            PendingIntent pi = PendingIntent.getBroadcast(mContext,
                    0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/);
            unregisterMediaButtonIntent(pi, eventReceiver);
        }
    
        /**
         * @hide
         */
        public void unregisterMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver) {
            IAudioService service = getService();
            try {
                service.unregisterMediaButtonIntent(pi, eventReceiver);
            } catch (RemoteException e) {
                Log.e(TAG, "Dead object in unregisterMediaButtonIntent"+e);
            }
        }
    
        /**
         * Registers the remote control client for providing information to display on the remote
         * controls.
         * @param rcClient The remote control client from which remote controls will receive
         *      information to display.
         * @see RemoteControlClient
         */
        public void registerRemoteControlClient(RemoteControlClient rcClient) {
            if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
                return;
            }
            IAudioService service = getService();
            try {
                service.registerRemoteControlClient(rcClient.getRcMediaIntent(),   /* mediaIntent   */
                        rcClient.getIRemoteControlClient(),                        /* rcClient      */
                        // used to match media button event receiver and audio focus
                        mContext.getPackageName());                                /* packageName   */
            } catch (RemoteException e) {
                Log.e(TAG, "Dead object in registerRemoteControlClient"+e);
            }
        }
    
        /**
         * Unregisters the remote control client that was providing information to display on the
         * remote controls.
         * @param rcClient The remote control client to unregister.
         * @see #registerRemoteControlClient(RemoteControlClient)
         */
        public void unregisterRemoteControlClient(RemoteControlClient rcClient) {
            if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
                return;
            }
            IAudioService service = getService();
            try {
                service.unregisterRemoteControlClient(rcClient.getRcMediaIntent(), /* mediaIntent   */
                        rcClient.getIRemoteControlClient());                       /* rcClient      */
            } catch (RemoteException e) {
                Log.e(TAG, "Dead object in unregisterRemoteControlClient"+e);
            }
        }
    
        /**
         * @hide
         * Registers a remote control display that will be sent information by remote control clients.
         * @param rcd
         */
        public void registerRemoteControlDisplay(IRemoteControlDisplay rcd) {
            if (rcd == null) {
                return;
            }
            IAudioService service = getService();
            try {
                service.registerRemoteControlDisplay(rcd);
            } catch (RemoteException e) {
                Log.e(TAG, "Dead object in registerRemoteControlDisplay " + e);
            }
        }
    
        /**
         * @hide
         * Unregisters a remote control display that was sent information by remote control clients.
         * @param rcd
         */
        public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
            if (rcd == null) {
                return;
            }
            IAudioService service = getService();
            try {
                service.unregisterRemoteControlDisplay(rcd);
            } catch (RemoteException e) {
                Log.e(TAG, "Dead object in unregisterRemoteControlDisplay " + e);
            }
        }
    




        
    最新技术文章:
    ▪Android开发之登录验证实例教程
    ▪Android开发之注册登录方法示例
    ▪Android获取手机SIM卡运营商信息的方法
    ▪Android实现将已发送的短信写入短信数据库的...
    ▪Android发送短信功能代码
    ▪Android根据电话号码获得联系人头像实例代码
    ▪Android中GPS定位的用法实例
    ▪Android实现退出时关闭所有Activity的方法
    ▪Android实现文件的分割和组装
    ▪Android录音应用实例教程
    ▪Android双击返回键退出程序的实现方法
    ▪Android实现侦听电池状态显示、电量及充电动...
    ▪Android获取当前已连接的wifi信号强度的方法
    ▪Android实现动态显示或隐藏密码输入框的内容
    ▪根据USER-AGENT判断手机类型并跳转到相应的app...
    ▪Android Touch事件分发过程详解
    ▪Android中实现为TextView添加多个可点击的文本
    ▪Android程序设计之AIDL实例详解
    ▪Android显式启动与隐式启动Activity的区别介绍
    ▪Android按钮单击事件的四种常用写法总结
    ▪Android消息处理机制Looper和Handler详解
    ▪Android实现Back功能代码片段总结
    ▪Android实用的代码片段 常用代码总结
    ▪Android实现弹出键盘的方法
    ▪Android中通过view方式获取当前Activity的屏幕截...
    ▪Android提高之自定义Menu(TabMenu)实现方法
    ▪Android提高之多方向抽屉实现方法
    ▪Android提高之MediaPlayer播放网络音频的实现方法...
    ▪Android提高之MediaPlayer播放网络视频的实现方法...
    ▪Android提高之手游转电视游戏的模拟操控
     


    站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3