热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

App竞品技术分析(3)减小安装包的体积(转)

http:blog.csdn.netJspAndAsparticledetails493394031从几件小事说起春节在家帮姐姐的iPhone手机安装市面上形形色色的App,忘记她

http://blog.csdn.net/JspAndAsp/article/details/49339403

1 从几件小事说起

  春节在家帮姐姐的iPhone手机安装市面上形形色色的App,忘记她是使用4G流量包月了,于是在下载了10个App后,不但耗尽了流量,还按照0.3元/兆的价格扣了七八十元流量费用。后来我检查了这几个App的体积,发现每个App体积都是40-50M的样子,这让我很吃惊,因为我记得两年前这些App也就在10-20M的样子。

  另一件记忆犹新的事情,是去公园景点游玩,当时公园门口有个活动“扫二维码下载App下单立减10元”,但是我发现下载这个40M的App要花费12元的流量,这样其实是要额外多花2元钱,所以“扫码立减”这件事情对于我这种小市民而言是很不划算的。

  由此而得到一个结论,App安装包的体积一定要小,至少要比竞争对手的App体积小。

  对于Android而言,国内的各大市场商店已经发现这个问题了,所以对于用户升级App,会为每个App提供增量下载的功能,所以App版本升级不再是几十M的流量,而只是下载1-2M的增量包就能升级到最新版本,这样就极大节省了流量。[1]

  对于iOS而言,AppStore从iOS6开始提供增量更新功能。对于iOS 6.x和iOS7.0,只要有文件改动过,这个文件就会进入到增量更新包中,比如说1个10M的文件,只改动了1KB的内容,这个10M文件就会进入到增量更新包中,包还是很大。到了iOS7.1及更高版本,这个机制进行了改良,它会把这1KB的改动内容放到增量更新包中,从而极大的减少了增量更新包的大小,但是安装的时候会变慢,因为要把这1KB的改动内容合并到10M文件中,这是个很繁琐很费时的工作。[2]

  尽管如此,以上种种措施只能解决升级用户的流量困扰,对新用户并无帮助。我们必须减小安装包的大小,才能吸引更多的新用户。

2 安装包为什么那么大

  是什么让App安装包的体积变得如此之大?

  我们在前面的章节看到了iOS和Android安装包的内部结构,对于可执行文件,我们无能为力;对于XML文件,这些文件在App打包压缩后会极大减小体积,所以也不用管它们;那么就只能在图片和音频文件上做文章了。

  各位读者看到这里,都请停下手中的工作,检查一下自家App包中图片和音频文件的大小。图片但凡是大于1M的,都是需要瘦身的。对于500KB-1M这个区间内的,也有瘦身的可能。我研究过很多知名的App,其中有很多图片都在2-3M的样子,其实真没有必要,之所以这么大,是因为UI设计人员提供的设计稿就是这么大,开发人员拿过来也不看文件体积大小直接就往项目里放,久而久之,App包的体积就大了。

  在众多App之中,我印象最深的是一款旅游类软件,它的所有图片都不超过100KB,甚至说50KB以上的都屈指可数。这是把极致做到家的表现。

  接下来说音频文件,对于应用类App而言,我见到的大都是App推送时发出的声音,这个声音很简单,不应该超过10KB。但我在很多App中看到的音频,都在100KB左右。这是我们优化的一个方向。网上有很多这样的软件,可以对音频进行大幅压缩。

3 png和jpg的区别和使用场景

  设计师曾经问过我,App为什么不使用jpg图片,因为同样的尺寸,png格式的图片要比jpg图片大很多。

  众所周知,png有透明通道,而jpg没有,此外png是无损压缩的而jpg是有损压缩的,所以png中存储的信息会很多,体积自然就大了。

  但是手机却偏偏对png情有独钟,会对其进行硬件加速,所以我们会发现,同样一张背景图,png虽然体积比jpg大但是加载速度却要快一些。

  终上所述,对于App包中的图片,我们都使用png格式的,而对于要从网上加载的图片,考虑到流量以及下载速度,则使用jpg格式的,因为它有较高的压缩率,体积很小。

  但是对于背景图、引导页,这种大尺寸的图片,我们还是倾向于使用jpg格式,虽然加载慢一些,但是体积小,减少了包的体积。我看过的App基本都是这么做的。

  对于Splash广告图,就是那个每次开启App一闪而过的广告,由于我们隔三岔五就要从线上下载新的广告图并展示在Spalsh页面上,所以这里使用jpg格式的图片。

  对于iOS,苹果规定启动页(Launch image)必须是png图片,否则审核时就会被拒。

  Google后来发布了一种新的图片格式,WebP,它的压缩率比jpg更好,已经慢慢普及。Android自然是支持的,iOS想要使用这种格式的图片,需要在程序中引入WebP解码器。

4 Splash、引导图和背景图

  通过对50多款App中的图片逐个分析,我发现有3种比较典型的场景,大多数公司的解决方案是雷同的:

  1. Splash默认广告是体积最大的,而且对应不同机型,要做多套,根据我的经验,每张图控制在300-500k左右就可以了。分辨率再高,对于手机而言,看不出效果。

  2. 引导图,设计师每次都会给几张高分辨率的图片,然后程序员不加思索直接放到App中,体积自然就变大了。其实,仔细观察,你会发现,为了保持风格统一,这些图片的背景都是一样的。所以我们完全可以这样做,比如说背景上有一只小兔子:

  • 把背景与小兔子拆分成2张图片。如果另一个引导图的背景上有一只小鸭子,那么就只需要这张小鸭子的图片了,背景图可以复用。
  • 根据分辨率,动态放置小兔子的位置,动态拉伸背景图,使之铺满整个屏幕。

  3. 对于背景图,为了达到一种视觉效果,这张图片经常被添加虚化等效果,既然如此,没有必要做得太清晰,应该控制在50k左右,看到很多App中类似的背景图都在1M左右,实在没有必要。背景图一般使用jpg文件。

5 iOS的1倍图、2倍图和3倍图

  iOS不使用像素作为单位,而是使用点这个单位,对于iPhone4及之后,1点等于2个像素;而对于iPhone3GS及之前,1点等于1个像素。这样就保证了之前在iPhone3GS上运行的App,不用修改也能在iPhone4上运行。[3]

  但是原先适用于iPhone3GS的图片,比如说a.png的尺寸是30 x 40像素,在iPhone4中看起来就模糊了。于是我们必须为a.png再准备一张60 x 80像素的图片,命名为a@2x.png,也放到App项目中,这样App在运行时会根据屏幕是否为iPhone3GS来选择相应的图片。iPhone3GS会选择a.png,iPhone4会选择a@2x.png。对于iPhone4而言,如果没有这张2倍图,则选择a.png,所以就模糊了。

  iPhone4S、iPhone5、iPhone5c、iPhone5s、iPhone6,它们都使用a@2x.png这张2倍图。

  直到iPhone6 Plus,才需要提供a@3x.png的图片。如果没有这张3倍图呢,它会选择1倍图或2倍图,我尝试过只有2倍图的情况,在iPhone6 Plus上确实是模糊的效果。

  那么问题就来了,我们需要为每张图都提供1倍图、2倍图和3倍图这3张图片吗?

  我看到一款国际版的App是这么处理图片的。它在提供了多国语言文字的同时,还为每张图片生成了1倍图、2倍图和3倍图。这就导致了这款App的体积非常大。看上去有点“宁可错杀一千,不可放走一个”的感觉,但只要反过来想,图片一张也不缺,永远不会模糊。

  我查看过很多App的图片,发现1倍图铺天盖地,但并不是每张1倍图都有相应的2倍图和3倍图,或者是只有相应的2倍图而没有3倍图,当然,也有只存在2倍图和3倍图而找不到1倍图的情况。图片管理五花八门,乱七八糟。

  但是在中国,可不是这样哦。我看过友盟给出的数据报告,中国iPhone3GS用户不足0.1%。于是,我有一个大胆的设想,就是把iOS App的包中所有的1倍图都干掉,为每张图生成2倍图和3倍图。

  很多公司都有根据1倍图批量生成2倍图和3倍图的工具,我也曾用C#写过一个。但是我发现有问题,并不是每张图片转换后都清晰,矢量图可以拉伸,但是拉伸位图就会失真。当我反过来根据3倍图批量生成1倍图和2倍图时,却发现位图可以压缩,而矢量图压缩后会失真。于是一种好的解决方案是,先把所有图片按照位图和矢量图进行分类,属于矢量图的,要提供1倍图,然后批量转换为2倍图和3倍图;而属于位图的,则是提供3倍图,然后批量转换为1倍图和2倍图。

  本文给出的解决方案,并不能有效减小iOS包的体积,说不定反而会增大包的大小,但是却能系统的对图片进行管理,从而确保每张图片都是清晰的。

6 在iOS中进行图片拉伸和旋转

  在Android技术领域,流行.9图这个概念,从而极大的节省了图片的体积。iOS其实也可以这么干,使用iOS的图片拉伸的语法,可以把一张.9图铺满一个区域,比如说按钮,如下所示:

(UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets

  其中capInsets这个参数是一个UIEdgeInsets类型的结构体,被capInsets覆盖到的区域将会保持不变,而未覆盖到的部分将会被用来平铺。

  以上这个方法只适用于iOS0及以上版本,0以下版本有另外的解决方案,但是目前国内的App都只支持0以上版本了,所以这里我就不提及了。

  对于箭头,更没必要准备上下左右4张图片,准备一张图片就够了,使用的时候在方向上进行旋转即可。

7 使用XML配置动画

  动画主要体现在引导图中以及加载进度条上。

  对于做应用类App的开发人员,他们做动画不是很在行,所以他们会要求设计师提供gif格式的动画,或者二十多张图片进行轮播,以达到gif动画的效果,殊不知,在编程上简单了,但是App的体积却相应变大了。

  比较简单的解决方案是,减少动画中的关键帧,来降低动画的大小。

  稍微正规一点,还是要使用原生的Android或iOS原生代码来实现。任何复杂的动画,都是由四种简单的动画组成的,分别是:移动、旋转、缩放、渐变。在Android中,是使用XML来配置的,上述这四种简单动画都有对应的XML语法,可以很快拼凑出一个复杂的动画;而对于iOS,只好使用编码方式了。

  我们为什么不仿照Android的XML动画实现技术,为iOS也量身定制一套XML的动画标签呢?从而不用写任何objective-C代码,配置几行XML就展现一个动画。

  我见过一家App就是使用这个思想在plist中配置属性来做iOS动画的,如图9-4所示,就是一个平移的动画:

  技术分享

  图9-4 配置文件中的平移动画

  基于这个配置,还需要有一个动画引擎,来解析这个配置文件,将其翻译成objective-C原生语言。在设计模式中,我们称之为解释器模式。

  不单如此,我还需要有个测试页面,通过在这个页面中修改动画的属性,然后点击按钮能立刻看到改动后的效果,而不需要重新运行App程序。点个按钮就能执行输入框中的XML脚本。

  使用上述的若干方法,我们可以把1个500KB左右的gif文件,减小到50KB的几张图片,并且极大地节省了而开发成本。

8 iOS使用storyboard还是xib?

  抱歉,我始终不喜欢storyboard,但是存在即合理。我曾经认为storyboard比xib大,是导致iOS安装包体积变大的一个原因,于是我做了一件探索性的工作,就是把storyboard中的页面拆分为若干个xib文件,然后重新打包,但是结果却是前后大小一致。

  结论是,是否使用storyboard,对ipa包大小没有影响。

9 字体文件的学问

  我在某个ipa包中发现了ttf格式的字体文件。起初还以为是他们的App使用了某种特定字体,但打开这个ttf文件后才发现,这里面存放的居然是图片,如图9-5所示:

  技术分享

  图9-5 字体文件中的icon图片

  每个icon对应一个十六进制的数字,比如说第一个是\Ue600,这个值是唯一的。

  观察这个字体文件,我们看到所有的icon具有以下共性:

  • 这些icon都是单色的,可以在App中的页面里设置这些icon为其他颜色,但也必须是单色。
  • 这些icon可大可小,因为它们是一种“字体”,字体是矢量图,所以拉伸不会失真。
  • 这个ttf文件体积很小,比做成单独的png图片要小。

  有人立刻就会联想到iOS的1倍图、2倍图和3倍图,每次都要准备3张图片,分别适用于不同的手机型号。如果做成一个字体,就可以减少体积,再也不用设计@2x和@3x两套图了——这种方案仅限于单色图片。

  我们一般到下述网站来把单色icon转换成字体文件:https://icomoon.io。或者使用FontLab这样的工具自己来制作。

  接下来我们来看如何在App中推广这门技术。

  1)Android

  首先把这个字体文件放到assets目录下,如图9-6所示:

  技术分享

  图9-6 assets目录下的字体文件

  接下来,我们将icon和十六进制编码的映射关系保存在drawable资源文件中:




  这样就可以使用R.id.font_icon_1_normal这样的语法来取出这个图片了。

TextView textView1 = (TextView) findViewById(R.id.textView1);
Typeface fOnt= Typeface.createFromAsset(getAssets(), "icomoon.ttf");
textView1.setTypeface(font);
textView1.setTextSize(12);
textView1.setText(getResources().getString(R.string.font_icon_1_normal));

  也可以将其设计为一个Drawable对象,然后设置给ImageView这样的控件。

  2)对于iOS,实现思路差不多。

  首先我们要把icmoon.ttf文件添加到项目中,如图9-7所示:

  技术分享

  图9-7 UseIconInTTF中的icomoon.ttf文件

  在Supporting Files目录下的UserIconInTTF-Info.plist文件中,增加一个配置,类型指定为Fonts provided by application,在其中添加对icomoon.ttf字体文件的声明,如图9-8所示:

  技术分享

  图9-8 在UseIconInTTF-Info.plist配置icomoon.ttf

  与Android类似,为了不直接使用\ue605这样的十六机制编码数字,我们将icon和十六进制编码的映射关系定义为一个宏TTFConstants:  

#define font_icon_1_normal "\ue605"
#define font_icon_1_pressed "\ue606"

  接下来只要两行代码就能显示这个字体文件中的图片:

[self.label1 setFont:[UIFont fontWithName:@"icomoon" size:12]];
[self.label1 setText:
[NSString stringWithUTF8String: font_icon_1_normal]];
10 表情图片打包下载

  对于表情图片。很多App中集成了聊天功能,有了聊天,自然就要提供各种表情图片,有静态图png,也有动画gif,虽然每个都不大,但是数量多啊,都打到包里面一起发布,会直接导致包变大。

  考虑到实际的场景,用户不会一打开App就使用聊天功能,所以我们可以把这些表情图片打包成一个Zip包,在启动App的时候,在一个新的线程中异步下载这个Zip包然后解压到本地。这样以后聊天的时候就可以使用本地的图片了。对此,我们要做好版本增量升级功能,以确保有新表情图片的时候也能下载到本地后使用。

11 清除未使用图片

  对于Android而言,Eclipse可以自动检查出哪些图片没有用到。

  对于iOS而言,则需要写个小程序,逐一检查哪些图片没有使用到,注意,对于a@2x.png和a@3x.png的处理,要先将@2x和@3x过滤掉。

  无论是Android还是iOS,即使发现到冗余图片,也不能直接删除,因为我们的程序经常会在代码中动态决定要显示哪些图片,我们只能检查这些图片在版本库的修改历史,来决定这些图片是否真的不需要了。

12 Proguard不只是用来混淆的

  一提起Android中的Proguard,我们首先想到的是代码混淆,那是因为我们要经常去修改proguard.cfg文件,去keep那些不需要被混淆的类和方法。

  其实,Proguard还能瘦身apk,在打包时它会帮忙检查那些不使用的类和方法,将其移除。最有效果的就是那些第三方SDK了,比如说aSmack这个用于xmpp的SDK有几万个方法,但其实我们只使用其中很小的一部分。Proguard会帮助我们把不使用的部分移除,从而极大的减小了apk的体积。

13 在iOS中使用pdf格式的图片

  在研究各家App的过程中,我发现某款App的ipa文件中有几张pdf格式的图片。

  在研究中还发现,有几款App的ipa包中的每张图片都做成imageset的形式,每个imageset目录中都同时存在这张图片的1倍图、2倍图和3倍图,如图9-9所示:

  技术分享

  图9-9 cancelSelectedListBtn.imageset目录下的3张图片

  上述这两件看似无关的事情,咋一看毫无关联,其实是使用了iOS的一个新技术。让我们从这些蛛丝马迹中探赜索隐。

  就是这几张pdf图片,我研究了半天,请设计师同学做成同样的png图片,体积相差不大,所以和png相比毫无优势。由于这个App的ipa包中有几百张图片,其中只有这3张图片是pdf格式的,所以我怀疑,这只是他们的新技术尝试。

  再观察imageset目录下的那3张图片,我发现每张图片都是这样的。这不由使我意识到,一定是用了什么工具,一次性生成的这些图片。

  搜索关键字ios+pdf,直到找到《Using Vector Images in Xcode 6》这篇文章[4],才发现这是iOS8才出现的一种新技术,只能在XCode6上使用。

  在这里简单介绍一下这门技术,先绘制一张pdf矢量图,然后XCode6在编译的时候,会生成3张pdf格式的图片,分别是1倍图、2倍图、3倍图。这样就避免了图片不全导致的模糊,也避免了每次都要设计师准备3套图的麻烦。

  但是,我们为什么要在用户的iPhone上装一些永远用不到的图片呢?苹果煞费苦心的搞出来这样一门技术,仍然没有解决App体积日益膨胀的现实,而且这门技术只会让App的体积变得更庞大——而这才是用户的痛点所在。如果是我来设计下一版iOS,我会让App中只包括pdf矢量图,只有在用户下载完App开始安装的时候,才会根据用户的机型,把pdf转换为相应的图片,比如说iPhone 6+上App生成的图片就是3倍图。

  苹果公司在iOS9中推出了App瘦身功能,据说能大幅减少要下载的App包的体积。具体效果如何,我们拭目以待。

14 iOS的包永远比Android包体积大吗?

  我比较了100多款App后发现,同一款App的iOS和Android版本,iOS的ipa包的一定比Android的apk包在体积上大很多。

  但总是有特立独行的App,比如说某款著名视频播放软件,Android版本23.2M,而iOS版本才20.5M。我起初以为这个App的Android版本做的有问题,于是仔细研究了这个Android包里的内容,我就发现这家公司Android技术做的很精致,之所以比iOS版本体积大,是因为Android版本为几十种分辨率都适配了不同的图片和布局,以确保用户体验在任何分辨率下都是一致的。

  如图9-10所示,居然有12种layout布局:

  技术分享

  图9-10 Android项目中的Layout文件夹

  drawable文件夹就更多了,高达28个,限于篇幅,这里就不贴图了。

  以上只是特例,而大多数App并没有做的那么细致,比如说:

  1)首先是不支持那么多分辨率。这是由当前App的开发现状导致的。一方面是产品经理和设计师在人力的不足,另一方面则因为设计师偏爱iPhone,一般只会给出iPhone版本的设计稿,然后让Android开发人员根据iPhone的设计稿去适配。于是Android开发人员只好去做UI自适应,使用.9图拉伸技术,实在搞不定了,才去找设计师重新给画一张。所以我们会看到iPhone的App大都很精致,相应的Android版本都很粗糙,这是因为Android App的UI很多都是开发人员凭着自己的审美观去二次加工的。

  2)其次,你会发现,不同drawable目录下放置着不同内容的图片。用开发人员的画讲,好找。比如说drawable目录下放各种Selector文件,drawable–hdpi目录下放美食类图片,drawable-large目录下放门票图片。所以说,目录虽多,但其实只有一套图。殊不知,这样反而降低了App运行的速度,因为它在相应分辨率的drawable目录下找不到某张图片时,就会逐个遍历每个drawable目录下的图片,直至找到该图片的位置。

15 从代码层面减少iOS包的体积

  对于iOS而言,在ipa包中会有一个.a格式的二进制文件,这是代码编译后生成的文件,往往占据了整个ipa包的50%到80%的体积。苹果曾要求所有的App都支持64位,于是在此基础上,ipa包的体积又扩大了将近一倍,主要是那个.a文件编译后变大了。

  我们要想办法减少这个.a文件的大小,其实就是要减少项目中的冗余代码。经过不断地摸索和尝试,我发现这些冗余代码分为3部分:

  1)已经不使用的类。为此,我们需要写一个Python脚本,逐个检查哪些类不再使用了。检查的过程中我发现,某个类即使不使用了,但是在其他类中仍然保持对它的引用,所以我们要排除掉这种特殊情况,不让它对我们的检查工作造成影响。

  还存在这么一种情况,在A类中使用了B。A类不再使用了,第一遍执行Python脚本找出来A类,将其删除了。这时B类就孤零零的放在那里,也不再使用了,所以我们有必要再次执行Python脚本,将B找出来。以此类推,不停地执行这个Python脚本,直到再也找不到不再使用的类为止。

  2)已经不再使用的方法。这个找起来有些费劲,因为Objective-C独特的方法签名形式(方法签名由三部分组成,包括方法名称、参数和返回类型)。

仍然是写一个Python脚本,逐个遍历每个类中的方法,然后到项目中查找是否使用到了。

  在执行过程中,遇到这么一种情况,A类和B类都有这个loveBaobao这个方法,方法签名也完全相同。这时Python是区分不出来到底是使用了哪个类的loveBaobao方法的。我们也只能将其汇总起来,然后用手动检查。

  此外,有很多方法是系统自带的,比如说UITableView的那6个方法,只要是使用了UITableView的页面,都有这6个方法。我们在执行Python脚本的时候,不应该统计这样的方法。所以需要做一个白名单,事先把这些方法填进去。

  3)代码相似度问题。初级程序员在写代码时,喜欢把一段代码从A类粘贴到B类中,然后修改其中的几个变量名称,这个功能就算做完了。于是两段相似度极高的代码就产生了。

  稍微懂得些面向对象思想的人,都知道这时候需要把这样的代码抽象出来,比如说在Utils类中新建一个方法,然后要用到这段逻辑的人调用Utils类的这个方法即可。

  但并不是所有的程序员都有这样的境界,即使是有几年经验的人,也会因为急着下班二人世界或者给孩子换尿布而采用复制粘贴大法敷衍了事。久而久之,冗余代码就多了,包的体积自然就大了。为此,我们需要有一个检查代码相似度的工具。在iOS领域,我推荐Simian这个工具。有兴趣的读者可以尝试一下,对你们的项目使用一下这个工具,看能找出来多少相似的代码来。


[1] 关于Android增量更新技术,请参见http://blog.csdn.net/hmg25/article/details/8100896

[2] 关于iOS增量更新机制,请参见https://developer.apple.com/library/ios/qa/qa1779/_index.html?utm_source=iOS+Dev+Weekly&utm_campaign=iOS_Dev_Weekly_Issue_114&utm_medium=email

[3] 详细内容请参见知乎上的这篇文章:http://www.zhihu.com/question/25421514/answer/31623909

[4] 文章参见http://martiancraft.com/blog/2014/09/vector-images-xcode6/

App竞品技术分析 (3)减小安装包的体积(转)


推荐阅读
  • C++入门必备:首个博客知识点汇总
    本文总结了C++初学者需要掌握的关键知识点,特别强调了成员类型的区分。其中,protected成员与private成员在本类中的作用相同,但protected成员允许派生类的成员函数访问,而private成员则不允许。此外,文章还介绍了其他重要的C++基础概念,如类的构造函数、析构函数以及继承机制,为初学者提供了一个全面的学习指南。 ... [详细]
  • 在使用Block时,正确的声明方法和确保线程安全是至关重要的。为了保证Block在堆中分配,应使用`copy`修饰符进行声明,因为栈中的Block与栈的生命周期绑定,容易导致内存问题。此外,还需注意Block捕获外部变量的行为,以避免潜在的循环引用和数据不一致问题。建议深入研究相关文档,以掌握更多高级技巧和最佳实践。 ... [详细]
  • 利用树莓派畅享落网电台音乐体验
    最近重新拾起了闲置已久的树莓派,这台小巧的开发板已经沉寂了半年多。上个月闲暇时间较多,我决定将其重新启用。恰逢落网电台进行了改版,回忆起之前在树莓派论坛上看到有人用它来播放豆瓣音乐,便萌生了同样的想法。通过一番调试,终于实现了在树莓派上流畅播放落网电台音乐的功能,带来了全新的音乐享受体验。 ... [详细]
  • 本文全面解析了 gRPC 的基础知识与高级应用,从 helloworld.proto 文件入手,详细阐述了如何定义服务接口。例如,`Greeter` 服务中的 `SayHello` 方法,该方法在客户端和服务器端的消息交互中起到了关键作用。通过实例代码,读者可以深入了解 gRPC 的工作原理及其在实际项目中的应用。 ... [详细]
  • vtkGlyph3D 是一种强大的符号化可视化工具,能够将三维数据集中的每个点用预定义的几何图形(如球体或箭头)进行表示。该工具不仅支持自定义符号的方向和缩放比例,还能够在复杂的数据场中突出显示关键特征,从而提高数据的可解释性和可视化效果。通过这种方式,用户可以更直观地理解和分析三维数据集中的重要信息。 ... [详细]
  • HDU1176:免费馅饼问题的动态规划解法分析
    题目“免费馅饼”通过动态规划方法进行了解析。该问题的时间限制为 Java 2000ms 和其他语言 1000ms,内存限制为 Java 65536K 和其他语言 32768K。本文详细探讨了如何利用动态规划算法高效求解此问题,并对算法的时间复杂度和空间复杂度进行了深入分析。此外,还提供了具体的实现步骤和代码示例,帮助读者更好地理解和应用这一方法。 ... [详细]
  • 在处理遗留数据库的映射时,反向工程是一个重要的初始步骤。由于实体模式已经在数据库系统中存在,Hibernate 提供了自动化工具来简化这一过程,帮助开发人员快速生成持久化类和映射文件。通过反向工程,可以显著提高开发效率并减少手动配置的错误。此外,该工具还支持对现有数据库结构进行分析,自动生成符合 Hibernate 规范的配置文件,从而加速项目的启动和开发周期。 ... [详细]
  • 在遍历集合的过程中,若需根据特定条件对集合进行修改操作,如添加或删除元素,应特别注意避免引发 `ConcurrentModificationException` 异常。例如,在当前场景中,当集合中的对象ID与另一个集合中的对象ID不匹配时,需要向集合中添加新元素。为了避免这一异常,建议使用迭代器的 `remove` 方法或采用线程安全的集合类型,如 `CopyOnWriteArrayList`,以确保操作的安全性和一致性。 ... [详细]
  • 如何在Mac上构建高效的本地服务器环境
    在Mac上构建高效的本地服务器环境,首先需要了解基本步骤:1. 配置目录基础;2. 启动Apache服务;3. 添加自定义文档至本地服务器;4. 查看自定义效果。此外,还可以通过手机或其他电脑访问本机服务器,以确保跨设备的兼容性和调试效果。Mac系统自带的Apache服务为本地开发提供了便捷的工具,本文将详细介绍每个步骤的具体操作方法。 ... [详细]
  • CAS 机制下的无锁队列设计与实现 ... [详细]
  • 【Linux进阶指南】第一阶段第三课:体验与部署Ubuntu系统
    在正式踏上Linux学习之旅之前,本课程将引导你深入体验和部署Ubuntu系统。通过详细的操作步骤和实践演练,你将掌握Ubuntu的基本安装、配置及常用命令,为后续的进阶学习打下坚实的基础。此外,课程还将介绍如何解决常见问题和优化系统性能,帮助你更加高效地使用Ubuntu。 ... [详细]
  • 概率与期望动态规划的深入探讨与应用分析
    本文深入探讨了概率与期望动态规划的基本原理及其在实际问题中的应用。概率是指某一事件发生的可能性大小,用P(A)表示。若某一事件的所有可能结果共有n种,且每种结果出现的概率相等,而事件A包含其中的m种结果,则该事件的概率P(A)为m/n。例如,在投掷骰子的情况下,如果事件A定义为掷出偶数点,由于共有3种偶数点(2、4、6),而总共有6种可能的结果,因此P(A)为1/2。文章进一步分析了概率与期望动态规划在复杂场景下的建模方法和求解策略,并通过具体实例展示了其在决策优化和风险管理中的应用价值。 ... [详细]
  • 本文详细介绍了 Windows API 中的按钮控件及其应用实例。主要功能包括:1. `CheckDlgButton` 用于更改对话框中按钮的选中状态;2. `CheckRadioButton` 用于设置单选按钮的选中状态。此外,还探讨了按钮控件在实际开发中的多种应用场景,帮助开发者更好地理解和使用这些功能。 ... [详细]
  • 采购订单条件类型配置的开发流程详解
    为了满足采购业务的需求,需开发新的价格类型。首先,在SPRO配置中定位到相应的配置节点,创建新的条件类型“ZMM00”。接着,创建定价过程“ZMM003”。具体步骤包括:1. 配置条件类型;2. 设置定价过程。此外,还需确保新条件类型与现有系统中的其他模块兼容,以保证整体业务流程的顺畅运行。 ... [详细]
  • 二叉树的直径是指树中任意两个叶节点之间最长路径上的节点数量。本文深入解析了计算二叉树直径的算法,并提出了一种优化方法,以提高计算效率和准确性。通过详细的案例分析和性能对比,展示了该优化算法在实际应用中的优势。 ... [详细]
author-avatar
手机用户2502854361
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有