您的位置:首页 > 移动开发 > Android开发

Android电视机(机顶盒)初次开发的一些经验分享

2015-01-04 12:28 453 查看
  从之前的web后台开发转到Android应用开发,做的第一个正式项目就是公司一个App的电视机(机顶盒)版本Demo开发。经过四个人近两周加班加点的开发和测试,总算按时交付了任务。在后续开发还没有开始之前,决定把这次开发当中学习到的一些知识和遇到的一些问题和大家的一起分享一下,由于也是刚开始做Android开发,并且是初次做电视机(机顶盒)上的开发,有什么不正确的地方,欢迎大家批评指正。另外,这也是我本人的第一篇原创博客,希望以后能坚持写下去!好,废话不多说,我们进入正题。
    一、运行和调试

    在做手机版Android开发时,要运行我们的程序,可以选择使用模拟器或者USB连接手机来运行。但是在做电视机(机顶盒)版本开发时,由于现在电视机(机顶盒)普遍的输出分辨率都在720P以上,用模拟器模拟并不是很方便,而采用数据线连接的方式,同样也不方便,客观上受到数据线长度和电视机(机顶盒)上接口的限制,而且这次在我们的开发之前进行调研的时候,发现使用数据线连接无法识别设备(也许和驱动有关)。总的来说,之前在手机上开发所用的方法,在电视(机顶盒)上并不好用。那该如何调试运行呢,总不能每次运行都打包,再通过其它方式把安装包装上去吧?答案当然是:no。

     这里就要为大家介绍几个在电视机(机顶盒)我在本次开发中发现非常实用的几个adb 命令了:

     1.adb connect [ip]

    使用这个命令,可以连接指定ip的设备。有了这个命令,之前讲的问题就迎刃而解了,只要将我们的电脑和电视机(机顶盒)连入同一个局域网,就可以连接到相应的设备了,然后就可以在eclipse里直接运行或调试程序了。相应的有

      adb disconnect [ip]

功能相信大家都懂得,就不解释了。

    2.adb uninstall [package]

    看名字相信大家也知道,这个命令可以用来卸载应用。在电视机(机顶盒)上卸载应用并不如我们在手机上方便,全部都要用遥控器来操作,使用这个命令就方便多了。而且这次开发过程中,由于我们设备有限,几个人使用一台电视机,经常需要卸载别人安装的不同签名的程序,这个命令省去了我们不少时间。

    3.adb shell input text ****

    这个命令的功能看字面儿相信也能猜得出来,就是用来输入文字的。我们在调试程序的时候,很多情况下要键入文字,这在手机上可能并不是个问题,可到了电视上,用遥控器按键盘真的会让你崩溃的,这个命令简直就是福音!

    上面三个就是我在这次开发中使用最频繁的三个命令,其中第二和第三个的使用,都必须在使用第一个进行connect之后才有意义。当然,adb的命令还有很多,这里就不详细介绍了,有兴趣的话大家可以自行搜索。

    二、焦点控制

    关于焦点,在手机开发中,我们可能更多关心的是某个控件在焦点变化时的逻辑处理。而在电视机(机顶盒)上做开发时,每个控件只有获得了焦点,才能对其进行操作,因此,确保需要操作的控件能够获得焦点、控制焦点的前后顺序是一个非常重要的问题。例如,在一个布局中有多个控件,在点击遥控器的上下左右方向键时,焦点会移到哪一个控件,哪些控件仅仅做显示,但不需要获得焦点等等问题。

    为了确保上述问题的可控性,我们可以通过以下方式来实现:

    1.控制控件是否可获得焦点

[java]
view plaincopy





android:focusable="true/false"  

当这个属性置为true时,表示当前控件可以获得焦点,false则表示不可获得焦点。相应的,我们也可以在程序中通过以下代码来设置:

[java]
view plaincopy





v.setFocusable(true/false);  

    2.控制按遥控器上下左右时下一个获得焦点的控件

[java]
view plaincopy





android:nextFocusUp="@+id/..."  
android:nextFocusDown="@+id/..."  
android:nextFocusLeft="@+id/..."  
android:nextFocusRight="@+id/..."  

这个相信不用多做解释,从字面意思就能很清楚的明白这四个属性的含义。相应的,在代码中也可以实现:

[java]
view plaincopy





v.setNextFocusUp(id);  
v.setNextFocusDown(id);  
v.setNextFocusLeft(id);  
v.setNextFocusRight(id);  

    三、UI适配

    UI适配在Android开发中是一件既麻烦又无法避免的事情,在本次开发中同样也碰到了这方面的问题。我们这次开发,主要适配1080p和720p两种分辨率。最开始的想法是,既然适配这两种分辨率,就指定这两种分辨率的资源,即

    drawable-1920×1080

    drawable-1280×720

相应地,提供对应分辨率下的尺寸:

    values-1920×1080

    values-1280×720

我们开发的时候,有一台42寸的电视盒两个机顶盒,电视最高支持4k分辨率,盒子只能输出720p分辨率。按照我们的适配策略,在电视和机顶盒上测试,都证明是正确的。然而,开发结束,送到测试那边时,他们使用的是32寸的1080p电视,就出现问题了,程序直接崩溃,无法运行,通过查看日志,发现是OOM问题。经过同事的分析,觉得是因为测试的电视虽然是1080p,但尺寸小,dpi高,是的所有图片都会被压缩,导致OOM。最后,更改了适配策略,采用了

    drawable-sw1080dp

    drawable-sw720dp

相应地,提供对应分辨率下的尺寸:

    values-sw1080dp

    values-sw720dp

解决了程序崩溃的问题。

    虽然问题解决了,但我觉得原因其实是我们之前虽然采用了分辨率来适配,但是在values文件里,使用的却是dp单位,只是当时开发用的电视,恰好dpi是160,才使得UI显示正常。所以,采用最初的适配方案,将values中尺寸的单位改为px,应该也是可以的,当然这个还没有验证过,后面我会验证一下。

    四、阴影的程序实现

    为了界面的美观与动感,在电视APP设计中,往往会用到倒影和阴影的效果,我们这次的demo设计也不例外。开发中,我负责模块需要实现倒影和阴影,本来是想让美工来切图,但是美工不愿意,让我们用程序来实现,交涉许久无果之下,只得自己来了。倒影的生成,由另外一个同事写了一个公用方法实现了,这里就不和大家分享了,其原理基本上就是将原图倒置,画在画布上,然后加上一个半透明的蒙版,就搞定了。

    阴影效果是我自己实现的,其实网上有很多讲阴影实现的教程,但是对我这个都不太适用,我需要的是在一个圆角矩形的图片四周加上阴影效果。经过很长时间的考虑,最后的办法是在原图四边加上矩形的阴影,然后在四个圆角的地方画扇形阴影来实现。不多说,直接上代码:

[java]
view plaincopy





/**  
     * @author: sunnybaby 
     * @Title: createShadowBitmap  
     * @Description: 生成带阴影图片 
     * @param orignalBitmap:原图 
     * @param shadowMargin:阴影边宽 
     * @param iconCornerRadius:原图圆角半径 
     * @return :生成的带阴影图片 
     */  
    public static Bitmap createShadowBitmap(Bitmap orignalBitmap,  
            int shadowMargin, int iconCornerRadius) {  
        int w = orignalBitmap.getWidth();  
        int h = orignalBitmap.getHeight();  
        Bitmap shadowBitmap = Bitmap.createBitmap(w + shadowMargin * 2, h  
                + shadowMargin * 2, Config.ARGB_8888);  
        int width = shadowBitmap.getWidth();  
        int height = shadowBitmap.getHeight();  
        Canvas canvas = new Canvas(shadowBitmap);  
        canvas.drawBitmap(orignalBitmap, shadowMargin, shadowMargin, null);  
        Paint paint = new Paint();  
        paint.setXfermode(new PorterDuffXfermode(Mode.DST_OVER));  
        int radius = shadowMargin + iconCornerRadius;  
        // 四个边的阴影效果,采用线性阴影,宽度等于阴影边距+圆角半径  
        LinearGradient leftGradient = new LinearGradient(radius, 0, 0, 0,  
                0x7F000000, 0x00000000, TileMode.CLAMP);  
        LinearGradient rightGradient = new LinearGradient(width - radius, 0,  
                width, 0, 0x7F000000, 0x00000000, TileMode.CLAMP);  
        LinearGradient topGradient = new LinearGradient(0, radius, 0, 0,  
                0x7F000000, 0x00000000, TileMode.CLAMP);  
        LinearGradient bottomGradient = new LinearGradient(0, height - radius,  
                0, height, 0x7F000000, 0x00000000, TileMode.CLAMP);  
        paint.setShader(leftGradient);  
        canvas.drawRect(0, radius, radius, height - radius, paint);  
        paint.setShader(rightGradient);  
        canvas.drawRect(width - radius, radius, width, height - radius, paint);  
        paint.setShader(topGradient);  
        canvas.drawRect(radius, 0, width - radius, radius, paint);  
        paint.setShader(bottomGradient);  
        canvas.drawRect(radius, height - radius, width - radius, height, paint);  
        // 四个角的阴影效果,采用圆形阴影,半径等于阴影边距+圆角半径  
        RadialGradient topLeftCornerGradient = new RadialGradient(radius,  
                radius, radius, 0x7F000000, 0x00000000, TileMode.CLAMP);  
        RadialGradient topRightCornerGradient = new RadialGradient(width  
                - radius, radius, radius, 0x7F000000, 0x00000000,  
                TileMode.CLAMP);  
        RadialGradient bottomLeftCornerGradient = new RadialGradient(radius,  
                height - radius, radius, 0x7F000000, 0x00000000, TileMode.CLAMP);  
        RadialGradient bottomRightCornerGradient = new RadialGradient(width  
                - radius, height - radius, radius, 0x7F000000, 0x00000000,  
                TileMode.CLAMP);  
        // 画四个角,就是画四个圆心角为90度的扇形,drawArc函数第一个参数为圆弧所在圆的的外接矩形,第二个参数为起始角度,第三个参数为扇形顺时针滑过的角度,第四个参数如果为true时,在绘制圆弧时将圆心包括在内(用来画扇形),第五个参数为画笔  
        paint.setShader(topLeftCornerGradient);  
        canvas.drawArc(new RectF(0, 0, radius * 2, radius * 2), 180, 90, true,  
                paint);  
        paint.setShader(topRightCornerGradient);  
        canvas.drawArc(new RectF(width - radius * 2, 0, width, radius * 2),  
                270, 90, true, paint);  
        paint.setShader(bottomLeftCornerGradient);  
        canvas.drawArc(new RectF(0, height - radius * 2, radius * 2, height),  
                90, 90, true, paint);  
        paint.setShader(bottomRightCornerGradient);  
        canvas.drawArc(new RectF(width - radius * 2, height - radius * 2,  
                width, height), 0, 90, true, paint);  
        return shadowBitmap;  
    }  

    好了,以上就是这次开发中想跟大家分享的一些东西,欢迎大家的批评指正

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: